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