1 /* 2 * Copyright 2008 Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Alexandre Deckner 7 * 8 */ 9 10 /* 11 * Original Be Sample source modified to use a quaternion for the object's orientation 12 */ 13 14 /* 15 Copyright 1999, Be Incorporated. All Rights Reserved. 16 This file may be used under the terms of the Be Sample Code License. 17 */ 18 19 #include "ObjectView.h" 20 21 #include <Application.h> 22 #include <Catalog.h> 23 #include <Cursor.h> 24 #include <InterfaceKit.h> 25 #include <FindDirectory.h> 26 27 #include "FPS.h" 28 #include "GLObject.h" 29 #include "ResScroll.h" 30 31 #undef B_TRANSLATION_CONTEXT 32 #define B_TRANSLATION_CONTEXT "ObjectView" 33 34 float displayScale = 1.0; 35 float depthOfView = 30.0; 36 float zRatio = 10.0; 37 38 float white[3] = {1.0, 1.0, 1.0}; 39 float dimWhite[3] = {0.25, 0.25, 0.25}; 40 float black[3] = {0.0, 0.0, 0.0}; 41 float foggy[3] = {0.4, 0.4, 0.4}; 42 float blue[3] = {0.0, 0.0, 1.0}; 43 float dimBlue[3] = {0.0, 0.0, 0.5}; 44 float yellow[3] = {1.0, 1.0, 0.0}; 45 float dimYellow[3] = {0.5, 0.5, 0.0}; 46 float green[3] = {0.0, 1.0, 0.0}; 47 float dimGreen[3] = {0.0, 0.5, 0.0}; 48 float red[3] = {1.0, 0.0, 0.0}; 49 50 float* bgColor = black; 51 52 const char *kNoResourceError = B_TRANSLATE("The Teapot 3D model was " 53 "not found in application resources. " 54 "Please repair the program installation."); 55 56 struct light { 57 float *ambient; 58 float *diffuse; 59 float *specular; 60 }; 61 62 63 light lights[] = { 64 {NULL, NULL, NULL}, 65 {dimWhite, white, white}, 66 {dimWhite, yellow, yellow}, 67 {dimWhite, red, red}, 68 {dimWhite, blue, blue}, 69 {dimWhite, green, green} 70 }; 71 72 73 74 long 75 signalEvent(sem_id event) 76 { 77 int32 c; 78 get_sem_count(event,&c); 79 if (c < 0) 80 release_sem_etc(event,-c,0); 81 82 return 0; 83 } 84 85 86 long 87 setEvent(sem_id event) 88 { 89 int32 c; 90 get_sem_count(event,&c); 91 if (c < 0) 92 release_sem_etc(event,-c,0); 93 94 return 0; 95 } 96 97 98 long 99 waitEvent(sem_id event) 100 { 101 acquire_sem(event); 102 103 int32 c; 104 get_sem_count(event,&c); 105 if (c > 0) 106 acquire_sem_etc(event,c,0,0); 107 108 return 0; 109 } 110 111 112 static int32 113 simonThread(void* cookie) 114 { 115 ObjectView* objectView = reinterpret_cast<ObjectView*>(cookie); 116 BScreen screen(objectView->Window()); 117 118 int noPause = 0; 119 while (acquire_sem_etc(objectView->quittingSem, 1, B_TIMEOUT, 0) == B_NO_ERROR) { 120 if (objectView->SpinIt()) { 121 objectView->DrawFrame(noPause); 122 release_sem(objectView->quittingSem); 123 noPause = 1; 124 } else { 125 release_sem(objectView->quittingSem); 126 noPause = 0; 127 waitEvent(objectView->drawEvent); 128 } 129 if (objectView->LimitFps()) 130 screen.WaitForRetrace(); 131 } 132 return 0; 133 } 134 135 136 ObjectView::ObjectView(BRect rect, const char *name, ulong resizingMode, 137 ulong options) 138 : BGLView(rect, name, resizingMode, 0, options), 139 fHistEntries(0), 140 fOldestEntry(0), 141 fFps(true), 142 fLimitFps(true), 143 fLastGouraud(true), 144 fGouraud(true), 145 fLastZbuf(true), 146 fZbuf(true), 147 fLastCulling(true), 148 fCulling(true), 149 fLastLighting(true), 150 fLighting(true), 151 fLastFilled(true), 152 fFilled(true), 153 fLastPersp(false), 154 fPersp(false), 155 fLastTextured(false), 156 fTextured(false), 157 fLastFog(false), 158 fFog(false), 159 fForceRedraw(false), 160 fLastYXRatio(1), 161 fYxRatio(1) 162 { 163 fTrackingInfo.isTracking = false; 164 fTrackingInfo.pickedObject = NULL; 165 fTrackingInfo.buttons = 0; 166 fTrackingInfo.lastX = 0.0f; 167 fTrackingInfo.lastY = 0.0f; 168 fTrackingInfo.lastDx = 0.0f; 169 fTrackingInfo.lastDy = 0.0f; 170 171 fLastObjectDistance = fObjectDistance = depthOfView / 8; 172 quittingSem = create_sem(1, "quitting sem"); 173 drawEvent = create_sem(0, "draw event"); 174 175 TriangleObject *Tri = new TriangleObject(this); 176 if (Tri->InitCheck() == B_OK) { 177 fObjListLock.Lock(); 178 fObjects.AddItem(Tri); 179 fObjListLock.Unlock(); 180 } else { 181 BAlert *NoResourceAlert = new BAlert(B_TRANSLATE("Error"), 182 kNoResourceError, B_TRANSLATE("OK"), NULL, NULL, 183 B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_STOP_ALERT); 184 NoResourceAlert->SetFlags(NoResourceAlert->Flags() | B_CLOSE_ON_ESCAPE); 185 NoResourceAlert->Go(); 186 delete Tri; 187 } 188 } 189 190 191 ObjectView::~ObjectView() 192 { 193 delete_sem(quittingSem); 194 delete_sem(drawEvent); 195 } 196 197 198 void 199 ObjectView::AttachedToWindow() 200 { 201 float position[] = {0.0, 3.0, 3.0, 0.0}; 202 float position1[] = {-3.0, -3.0, 3.0, 0.0}; 203 float position2[] = {3.0, 0.0, 0.0, 0.0}; 204 float local_view[] = {0.0, 0.0}; 205 // float ambient[] = {0.1745, 0.03175, 0.03175}; 206 // float diffuse[] = {0.61424, 0.10136, 0.10136}; 207 // float specular[] = {0.727811, 0.626959, 0.626959}; 208 // rgb_color black = {0, 0, 0, 255}; 209 BRect bounds = Bounds(); 210 211 BGLView::AttachedToWindow(); 212 Window()->SetPulseRate(100000); 213 214 LockGL(); 215 216 glEnable(GL_DITHER); 217 glEnable(GL_CULL_FACE); 218 glCullFace(GL_BACK); 219 glDepthFunc(GL_LESS); 220 221 glShadeModel(GL_SMOOTH); 222 223 glLightfv(GL_LIGHT0, GL_POSITION, position); 224 glLightfv(GL_LIGHT0 + 1, GL_POSITION, position1); 225 glLightfv(GL_LIGHT0 + 2, GL_POSITION, position2); 226 glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, local_view); 227 228 glEnable(GL_LIGHT0); 229 glLightfv(GL_LIGHT0, GL_SPECULAR, lights[lightWhite].specular); 230 glLightfv(GL_LIGHT0, GL_DIFFUSE,lights[lightWhite].diffuse); 231 glLightfv(GL_LIGHT0, GL_AMBIENT,lights[lightWhite].ambient); 232 glEnable(GL_LIGHT1); 233 glLightfv(GL_LIGHT1, GL_SPECULAR, lights[lightBlue].specular); 234 glLightfv(GL_LIGHT1, GL_DIFFUSE,lights[lightBlue].diffuse); 235 glLightfv(GL_LIGHT1, GL_AMBIENT,lights[lightBlue].ambient); 236 237 glFrontFace(GL_CW); 238 glEnable(GL_LIGHTING); 239 glEnable(GL_AUTO_NORMAL); 240 glEnable(GL_NORMALIZE); 241 242 glMaterialf(GL_FRONT, GL_SHININESS, 0.6 * 128.0); 243 244 glClearColor(bgColor[0], bgColor[1], bgColor[2], 1.0); 245 glColor3f(1.0, 1.0, 1.0); 246 247 glViewport(0, 0, (GLint)bounds.IntegerWidth() + 1, 248 (GLint)bounds.IntegerHeight() + 1); 249 glMatrixMode(GL_PROJECTION); 250 glLoadIdentity(); 251 252 float scale = displayScale; 253 glOrtho(-scale, scale, -scale, scale, -scale * depthOfView, 254 scale * depthOfView); 255 glMatrixMode(GL_MODELVIEW); 256 glLoadIdentity(); 257 258 UnlockGL(); 259 260 fDrawThread = spawn_thread(simonThread, "Simon", B_NORMAL_PRIORITY, this); 261 resume_thread(fDrawThread); 262 fForceRedraw = true; 263 setEvent(drawEvent); 264 } 265 266 267 void 268 ObjectView::DetachedFromWindow() 269 { 270 BGLView::DetachedFromWindow(); 271 272 status_t dummy; 273 long locks = 0; 274 275 while (Window()->IsLocked()) { 276 locks++; 277 Window()->Unlock(); 278 } 279 280 acquire_sem(quittingSem); 281 release_sem(drawEvent); 282 wait_for_thread(fDrawThread, &dummy); 283 release_sem(quittingSem); 284 285 while (locks--) 286 Window()->Lock(); 287 } 288 289 290 void 291 ObjectView::Pulse() 292 { 293 Window()->Lock(); 294 BRect parentBounds = Parent()->Bounds(); 295 BRect bounds = Bounds(); 296 parentBounds.OffsetTo(0, 0); 297 bounds.OffsetTo(0, 0); 298 if (bounds != parentBounds) { 299 ResizeTo(parentBounds.right - parentBounds.left, 300 parentBounds.bottom - parentBounds.top); 301 } 302 Window()->Unlock(); 303 } 304 305 306 void 307 ObjectView::MessageReceived(BMessage* msg) 308 { 309 BMenuItem* item = NULL; 310 bool toggleItem = false; 311 312 switch (msg->what) { 313 case kMsgFPS: 314 fFps = (fFps) ? false : true; 315 msg->FindPointer("source", reinterpret_cast<void**>(&item)); 316 item->SetMarked(fFps); 317 fForceRedraw = true; 318 setEvent(drawEvent); 319 break; 320 case kMsgAddModel: 321 { 322 TriangleObject *Tri = new TriangleObject(this); 323 if (Tri->InitCheck() == B_OK) { 324 fObjListLock.Lock(); 325 fObjects.AddItem(Tri); 326 fObjListLock.Unlock(); 327 } else { 328 BAlert *NoResourceAlert = new BAlert(B_TRANSLATE("Error"), 329 kNoResourceError, B_TRANSLATE("OK"), NULL, NULL, 330 B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_STOP_ALERT); 331 NoResourceAlert->SetFlags(NoResourceAlert->Flags() | B_CLOSE_ON_ESCAPE); 332 NoResourceAlert->Go(); 333 delete Tri; 334 } 335 setEvent(drawEvent); 336 break; 337 } 338 case kMsgLights: 339 { 340 msg->FindPointer("source", reinterpret_cast<void**>(&item)); 341 long lightNum = msg->FindInt32("num"); 342 long color = msg->FindInt32("color"); 343 BMenu *menu = item->Menu(); 344 long index = menu->IndexOf(item); 345 menu->ItemAt(index)->SetMarked(true); 346 for (int i = 0; i < menu->CountItems(); i++) { 347 if (i != index) 348 menu->ItemAt(i)->SetMarked(false); 349 } 350 351 LockGL(); 352 if (color != lightNone) { 353 glEnable(GL_LIGHT0 + lightNum - 1); 354 glLightfv(GL_LIGHT0 + lightNum - 1, GL_SPECULAR, 355 lights[color].specular); 356 glLightfv(GL_LIGHT0 + lightNum - 1, GL_DIFFUSE, 357 lights[color].diffuse); 358 glLightfv(GL_LIGHT0 + lightNum - 1, GL_AMBIENT, 359 lights[color].ambient); 360 } else { 361 glDisable(GL_LIGHT0 + lightNum - 1); 362 } 363 UnlockGL(); 364 fForceRedraw = true; 365 setEvent(drawEvent); 366 break; 367 } 368 case kMsgGouraud: 369 fGouraud = !fGouraud; 370 toggleItem = true; 371 break; 372 case kMsgZBuffer: 373 fZbuf = !fZbuf; 374 toggleItem = true; 375 break; 376 case kMsgCulling: 377 fCulling = !fCulling; 378 toggleItem = true; 379 break; 380 case kMsgLighting: 381 fLighting = !fLighting; 382 toggleItem = true; 383 break; 384 case kMsgFilled: 385 fFilled = !fFilled; 386 toggleItem = true; 387 break; 388 case kMsgPerspective: 389 fPersp = !fPersp; 390 toggleItem = true; 391 break; 392 case kMsgFog: 393 fFog = !fFog; 394 toggleItem = true; 395 break; 396 case kMsgLimitFps: 397 fLimitFps = !fLimitFps; 398 toggleItem = true; 399 break; 400 } 401 402 if (toggleItem && msg->FindPointer("source", reinterpret_cast<void**>(&item)) == B_OK){ 403 item->SetMarked(!item->IsMarked()); 404 setEvent(drawEvent); 405 } 406 407 BGLView::MessageReceived(msg); 408 } 409 410 411 int 412 ObjectView::ObjectAtPoint(const BPoint &point) 413 { 414 LockGL(); 415 glShadeModel(GL_FLAT); 416 glDisable(GL_LIGHTING); 417 glDisable(GL_FOG); 418 glClearColor(black[0], black[1], black[2], 1.0); 419 glClear(GL_COLOR_BUFFER_BIT | (fZbuf ? GL_DEPTH_BUFFER_BIT : 0)); 420 421 float idColor[3]; 422 idColor[1] = idColor[2] = 0; 423 for (int i = 0; i < fObjects.CountItems(); i++) { 424 // to take into account 16 bits colorspaces, 425 // only use the 5 highest bits of the red channel 426 idColor[0] = (255 - (i << 3)) / 255.0; 427 reinterpret_cast<GLObject*>(fObjects.ItemAt(i))->Draw(true, idColor); 428 } 429 glReadBuffer(GL_BACK); 430 uchar pixel[256]; 431 glReadPixels((GLint)point.x, (GLint)(Bounds().bottom - point.y), 1, 1, 432 GL_RGB, GL_UNSIGNED_BYTE, pixel); 433 int objNum = pixel[0]; 434 objNum = (255 - objNum) >> 3; 435 436 EnforceState(); 437 UnlockGL(); 438 439 return objNum; 440 } 441 442 443 void 444 ObjectView::MouseDown(BPoint point) 445 { 446 GLObject* object = NULL; 447 448 BMessage *msg = Window()->CurrentMessage(); 449 uint32 buttons = msg->FindInt32("buttons"); 450 object = reinterpret_cast<GLObject*>(fObjects.ItemAt(ObjectAtPoint(point))); 451 452 if (object != NULL){ 453 if (buttons == B_PRIMARY_MOUSE_BUTTON || buttons == B_SECONDARY_MOUSE_BUTTON) { 454 fTrackingInfo.pickedObject = object; 455 fTrackingInfo.buttons = buttons; 456 fTrackingInfo.isTracking = true; 457 fTrackingInfo.lastX = point.x; 458 fTrackingInfo.lastY = point.y; 459 fTrackingInfo.lastDx = 0.0f; 460 fTrackingInfo.lastDy = 0.0f; 461 fTrackingInfo.pickedObject->Spin(0.0f, 0.0f); 462 463 464 SetMouseEventMask(B_POINTER_EVENTS, 465 B_LOCK_WINDOW_FOCUS | B_NO_POINTER_HISTORY); 466 467 BCursor grabbingCursor(B_CURSOR_ID_GRABBING); 468 SetViewCursor(&grabbingCursor); 469 } else { 470 ConvertToScreen(&point); 471 object->MenuInvoked(point); 472 } 473 } 474 } 475 476 477 void 478 ObjectView::MouseUp(BPoint point) 479 { 480 if (fTrackingInfo.isTracking) { 481 482 //spin the teapot on release, TODO: use a marching sum and divide by time 483 if (fTrackingInfo.buttons == B_PRIMARY_MOUSE_BUTTON 484 && fTrackingInfo.pickedObject != NULL 485 && (fabs(fTrackingInfo.lastDx) > 1.0f 486 || fabs(fTrackingInfo.lastDy) > 1.0f) ) { 487 488 fTrackingInfo.pickedObject->Spin(0.5f * fTrackingInfo.lastDy, 0.5f * fTrackingInfo.lastDx); 489 490 setEvent(drawEvent); 491 } 492 493 //stop tracking 494 fTrackingInfo.isTracking = false; 495 fTrackingInfo.buttons = 0; 496 fTrackingInfo.pickedObject = NULL; 497 fTrackingInfo.lastX = 0.0f; 498 fTrackingInfo.lastY = 0.0f; 499 fTrackingInfo.lastDx = 0.0f; 500 fTrackingInfo.lastDy = 0.0f; 501 502 BCursor grabCursor(B_CURSOR_ID_GRAB); 503 SetViewCursor(&grabCursor); 504 } 505 } 506 507 508 void 509 ObjectView::MouseMoved(BPoint point, uint32 transit, const BMessage *msg) 510 { 511 if (fTrackingInfo.isTracking && fTrackingInfo.pickedObject != NULL) { 512 513 float dx = point.x - fTrackingInfo.lastX; 514 float dy = point.y - fTrackingInfo.lastY; 515 fTrackingInfo.lastX = point.x; 516 fTrackingInfo.lastY = point.y; 517 518 if (fTrackingInfo.buttons == B_PRIMARY_MOUSE_BUTTON) { 519 520 fTrackingInfo.pickedObject->Spin(0.0f, 0.0f); 521 fTrackingInfo.pickedObject->RotateWorldSpace(dx,dy); 522 fTrackingInfo.lastDx = dx; 523 fTrackingInfo.lastDy = dy; 524 525 setEvent(drawEvent); 526 527 } else if (fTrackingInfo.buttons == B_SECONDARY_MOUSE_BUTTON) { 528 529 float xinc = (dx * 2 * displayScale / Bounds().Width()); 530 float yinc = (-dy * 2 * displayScale / Bounds().Height()); 531 float zinc = 0; 532 533 if (fPersp) { 534 zinc = yinc * (fTrackingInfo.pickedObject->z / displayScale); 535 xinc *= -(fTrackingInfo.pickedObject->z * 4 / zRatio); 536 yinc *= -(fTrackingInfo.pickedObject->z * 4 / zRatio); 537 } 538 539 fTrackingInfo.pickedObject->x += xinc; 540 if (modifiers() & B_SHIFT_KEY) 541 fTrackingInfo.pickedObject->z += zinc; 542 else 543 fTrackingInfo.pickedObject->y += yinc; 544 545 fForceRedraw = true; 546 setEvent(drawEvent); 547 } 548 } else { 549 void* object = fObjects.ItemAt(ObjectAtPoint(point)); 550 BCursor cursor(object != NULL 551 ? B_CURSOR_ID_GRAB : B_CURSOR_ID_SYSTEM_DEFAULT); 552 SetViewCursor(&cursor); 553 } 554 } 555 556 557 void 558 ObjectView::FrameResized(float width, float height) 559 { 560 BGLView::FrameResized(width, height); 561 562 LockGL(); 563 564 width = Bounds().Width(); 565 height = Bounds().Height(); 566 fYxRatio = height / width; 567 glViewport(0, 0, (GLint)width + 1, (GLint)height + 1); 568 569 // To prevent weird buffer contents 570 glClear(GL_COLOR_BUFFER_BIT); 571 572 glMatrixMode(GL_PROJECTION); 573 glLoadIdentity(); 574 float scale = displayScale; 575 576 if (fPersp) { 577 gluPerspective(60, 1.0 / fYxRatio, 0.15, 120); 578 } else { 579 if (fYxRatio < 1) { 580 glOrtho(-scale / fYxRatio, scale / fYxRatio, -scale, scale, -1.0, 581 depthOfView * 4); 582 } else { 583 glOrtho(-scale, scale, -scale * fYxRatio, scale * fYxRatio, -1.0, 584 depthOfView * 4); 585 } 586 } 587 588 fLastYXRatio = fYxRatio; 589 590 glMatrixMode(GL_MODELVIEW); 591 592 UnlockGL(); 593 594 fForceRedraw = true; 595 setEvent(drawEvent); 596 } 597 598 599 bool 600 ObjectView::RepositionView() 601 { 602 if (!(fPersp != fLastPersp) && 603 !(fLastObjectDistance != fObjectDistance) && 604 !(fLastYXRatio != fYxRatio)) { 605 return false; 606 } 607 608 LockGL(); 609 610 glMatrixMode(GL_PROJECTION); 611 glLoadIdentity(); 612 float scale = displayScale; 613 614 if (fPersp) { 615 gluPerspective(60, 1.0 / fYxRatio, 0.15, 120); 616 } else { 617 if (fYxRatio < 1) { 618 glOrtho(-scale / fYxRatio, scale / fYxRatio, -scale, scale, -1.0, 619 depthOfView * 4); 620 } else { 621 glOrtho(-scale, scale, -scale * fYxRatio, scale * fYxRatio, -1.0, 622 depthOfView * 4); 623 } 624 } 625 626 glMatrixMode(GL_MODELVIEW); 627 628 UnlockGL(); 629 630 fLastObjectDistance = fObjectDistance; 631 fLastPersp = fPersp; 632 fLastYXRatio = fYxRatio; 633 return true; 634 } 635 636 637 void 638 ObjectView::EnforceState() 639 { 640 glShadeModel(fGouraud ? GL_SMOOTH : GL_FLAT); 641 642 if (fZbuf) 643 glEnable(GL_DEPTH_TEST); 644 else 645 glDisable(GL_DEPTH_TEST); 646 647 if (fCulling) 648 glEnable(GL_CULL_FACE); 649 else 650 glDisable(GL_CULL_FACE); 651 652 if (fLighting) 653 glEnable(GL_LIGHTING); 654 else 655 glDisable(GL_LIGHTING); 656 657 if (fFilled) 658 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 659 else 660 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 661 662 if (fFog) { 663 glFogf(GL_FOG_START, 10.0); 664 glFogf(GL_FOG_DENSITY, 0.2); 665 glFogf(GL_FOG_END, depthOfView); 666 glFogfv(GL_FOG_COLOR, foggy); 667 glEnable(GL_FOG); 668 bgColor = foggy; 669 glClearColor(bgColor[0], bgColor[1], bgColor[2], 1.0); 670 } else { 671 glDisable(GL_FOG); 672 bgColor = black; 673 glClearColor(bgColor[0], bgColor[1], bgColor[2], 1.0); 674 } 675 } 676 677 678 bool 679 ObjectView::SpinIt() 680 { 681 bool changed = false; 682 683 if (fGouraud != fLastGouraud) { 684 LockGL(); 685 glShadeModel(fGouraud ? GL_SMOOTH : GL_FLAT); 686 UnlockGL(); 687 fLastGouraud = fGouraud; 688 changed = true; 689 } 690 691 if (fZbuf != fLastZbuf) { 692 LockGL(); 693 if (fZbuf) 694 glEnable(GL_DEPTH_TEST); 695 else 696 glDisable(GL_DEPTH_TEST); 697 UnlockGL(); 698 fLastZbuf = fZbuf; 699 changed = true; 700 } 701 702 if (fCulling != fLastCulling) { 703 LockGL(); 704 if (fCulling) 705 glEnable(GL_CULL_FACE); 706 else 707 glDisable(GL_CULL_FACE); 708 UnlockGL(); 709 fLastCulling = fCulling; 710 changed = true; 711 } 712 713 if (fLighting != fLastLighting) { 714 LockGL(); 715 if (fLighting) 716 glEnable(GL_LIGHTING); 717 else 718 glDisable(GL_LIGHTING); 719 UnlockGL(); 720 fLastLighting = fLighting; 721 changed = true; 722 } 723 724 if (fFilled != fLastFilled) { 725 LockGL(); 726 if (fFilled) { 727 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); 728 } else { 729 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 730 } 731 UnlockGL(); 732 fLastFilled = fFilled; 733 changed = true; 734 } 735 736 if (fFog != fLastFog) { 737 if (fFog) { 738 glFogf(GL_FOG_START, 1.0); 739 glFogf(GL_FOG_DENSITY, 0.2); 740 glFogf(GL_FOG_END, depthOfView); 741 glFogfv(GL_FOG_COLOR, foggy); 742 glEnable(GL_FOG); 743 bgColor = foggy; 744 glClearColor(bgColor[0], bgColor[1], bgColor[2], 1.0); 745 } else { 746 glDisable(GL_FOG); 747 bgColor = black; 748 glClearColor(bgColor[0], bgColor[1], bgColor[2], 1.0); 749 } 750 fLastFog = fFog; 751 changed = true; 752 } 753 754 changed = changed || RepositionView(); 755 changed = changed || fForceRedraw; 756 fForceRedraw = false; 757 758 for (int i = 0; i < fObjects.CountItems(); i++) { 759 bool hack = reinterpret_cast<GLObject*>(fObjects.ItemAt(i))->SpinIt(); 760 changed = changed || hack; 761 } 762 763 return changed; 764 } 765 766 767 void 768 ObjectView::DrawFrame(bool noPause) 769 { 770 LockGL(); 771 glClear(GL_COLOR_BUFFER_BIT | (fZbuf ? GL_DEPTH_BUFFER_BIT : 0)); 772 773 fObjListLock.Lock(); 774 for (int i = 0; i < fObjects.CountItems(); i++) { 775 GLObject *object = reinterpret_cast<GLObject*>(fObjects.ItemAt(i)); 776 if (object->Solidity() == 0) 777 object->Draw(false, NULL); 778 } 779 EnforceState(); 780 for (int i = 0; i < fObjects.CountItems(); i++) { 781 GLObject *object = reinterpret_cast<GLObject*>(fObjects.ItemAt(i)); 782 if (object->Solidity() != 0) 783 object->Draw(false, NULL); 784 } 785 fObjListLock.Unlock(); 786 787 glDisable(GL_BLEND); 788 glDepthMask(GL_TRUE); 789 790 if (noPause) { 791 uint64 now = system_time(); 792 float fps = 1.0 / ((now - fLastFrame) / 1000000.0); 793 fLastFrame = now; 794 int entry; 795 if (fHistEntries < HISTSIZE) { 796 entry = (fOldestEntry + fHistEntries) % HISTSIZE; 797 fHistEntries++; 798 } else { 799 entry = fOldestEntry; 800 fOldestEntry = (fOldestEntry + 1) % HISTSIZE; 801 } 802 803 fFpsHistory[entry] = fps; 804 805 if (fHistEntries > 5) { 806 fps = 0; 807 for (int i = 0; i < fHistEntries; i++) 808 fps += fFpsHistory[(fOldestEntry + i) % HISTSIZE]; 809 810 fps /= fHistEntries; 811 812 if (fFps) { 813 glPushAttrib(GL_ENABLE_BIT | GL_LIGHTING_BIT); 814 glPushMatrix(); 815 glLoadIdentity(); 816 glTranslatef(-0.9, -0.9, 0); 817 glScalef(0.10, 0.10, 0.10); 818 glDisable(GL_LIGHTING); 819 glDisable(GL_DEPTH_TEST); 820 glDisable(GL_BLEND); 821 glColor3f(1.0, 1.0, 0); 822 glMatrixMode(GL_PROJECTION); 823 glPushMatrix(); 824 glLoadIdentity(); 825 glMatrixMode(GL_MODELVIEW); 826 827 FPS::drawCounter(fps); 828 829 glMatrixMode(GL_PROJECTION); 830 glPopMatrix(); 831 glMatrixMode(GL_MODELVIEW); 832 glPopMatrix(); 833 glPopAttrib(); 834 } 835 } 836 } else { 837 fHistEntries = 0; 838 fOldestEntry = 0; 839 } 840 SwapBuffers(); 841 UnlockGL(); 842 } 843