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