xref: /haiku/src/apps/glteapot/ObjectView.cpp (revision 493d3c69f3346eaa10a48d154d7451e8d26b6990)
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