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