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