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