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