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