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