1 /***************************************************************************
2                           gamerenderer.cpp  -  Renderer using world object
3                              -------------------
4     begin                : di apr 8 2003
5     copyright            : (C) 2003 by CJP
6     email                : cornware-cjp@users.sourceforge.net
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 #include <GL/gl.h>
18 #include <cstdio>
19 #include <cmath>
20 #include "pi.h"
21 
22 #include "gamerenderer.h"
23 #include "console.h"
24 
25 #include "world.h"
26 
27 #include "timer.h"
28 
29 #define FOV_MULTIPLIER (0.25)
30 
31 //TODO: remove this when not debugging
32 CTimer _DebugTimer;
33 
CGameRenderer()34 CGameRenderer::CGameRenderer()
35 {
36 	m_GraphicWorld = new CGraphicWorld();
37 	m_NumCameras = 1;
38 
39 	m_UpdateBodyReflection = -1;
40 }
41 
reloadConfiguration()42 bool CGameRenderer::reloadConfiguration()
43 {
44 	if(!CRenderer::reloadConfiguration()) return false;
45 
46 	if(!m_GraphicWorld->reloadConfiguration()) return false;
47 
48 	return true;
49 }
50 
~CGameRenderer()51 CGameRenderer::~CGameRenderer()
52 {
53 	unloadTrackData();
54 	delete m_GraphicWorld;
55 }
56 
loadTrackData()57 bool CGameRenderer::loadTrackData()
58 {
59 	if(!m_GraphicWorld->loadWorld())
60 		return false;
61 
62 	{
63 		CVector cc = m_GraphicWorld->m_Background->getClearColor();
64 		glClearColor(cc.x, cc.y, cc.z,1.0);
65 
66 		CVector fc = m_GraphicWorld->m_Background->getFogColor();
67 		m_FogColor[0] = fc.x;
68 		m_FogColor[1] = fc.y;
69 		m_FogColor[2] = fc.z;
70 		m_FogColor[3] = 1.0;
71 		if(m_Settings.m_FogMode >= 0)
72 			glFogfv(GL_FOG_COLOR, m_FogColor);
73 	}
74 
75 	//Lighting:
76 	CTrack *theTrack = theWorld->getTrack();
77 	CVector lightCol = theTrack->m_Environment.m_LightColor;
78 	CVector ambCol = theTrack->m_Environment.m_AmbientColor;
79 
80 	GLfloat light_color[] = {lightCol.x, lightCol.y, lightCol.z, 1.0};
81 	GLfloat specular_color[] = {3.0*lightCol.x, 3.0*lightCol.y, 3.0*lightCol.z, 1.0};
82 	GLfloat ambient_color[] = {ambCol.x, ambCol.y, ambCol.z, 1.0};
83 
84 	glLightfv(GL_LIGHT0, GL_DIFFUSE, light_color);
85 	glLightfv(GL_LIGHT0, GL_SPECULAR, specular_color);
86 	glLightfv(GL_LIGHT1, GL_AMBIENT, ambient_color);
87 
88 	return true;
89 }
90 
unloadTrackData()91 void CGameRenderer::unloadTrackData()
92 {
93 	m_GraphicWorld->unloadWorld();
94 }
95 
loadObjData()96 bool CGameRenderer::loadObjData()
97 {
98 	return m_GraphicWorld->loadObjects();
99 }
100 
unloadObjData()101 void CGameRenderer::unloadObjData()
102 {
103 	//TODO
104 }
105 
setCameras(CGameCamera ** cams,unsigned int num)106 void CGameRenderer::setCameras(CGameCamera **cams, unsigned int num)
107 {
108 	m_Cameras = cams;
109 	m_NumCameras = num;
110 }
111 
update()112 void CGameRenderer::update()
113 {
114 	if(m_UpdateBodyReflection >= 0)
115 	{
116 		clearScreen();
117 		renderScene();
118 	}
119 	else
120 	{
121 		//float tstart = _DebugTimer.getTime();
122 
123 		updateShadows();
124 		updateParticleSystems();
125 		updateReflections();
126 		//fprintf(stderr, "Update reflections: %.5f\n\n\n", _DebugTimer.getTime() - tstart);
127 
128 		clearScreen();
129 		for(unsigned int i=0; i < m_NumCameras; i++)
130 		{
131 			//float tcam = _DebugTimer.getTime();
132 			m_CurrentCamera = i;
133 
134 			//3D part
135 			selectCamera(i);
136 			renderScene();
137 
138 			//2D part
139 			selectCamera(i, false);
140 			viewDashboard(m_Cameras[i]->getTrackedObject());
141 			//fprintf(stderr, "Viewport output: %.5f\n\n\n", _DebugTimer.getTime() - tcam);
142 		}
143 
144 		//fprintf(stderr, "Rendering: %.5f\n\n\n", _DebugTimer.getTime() - tstart);
145 	}
146 }
147 
clearScreen()148 void CGameRenderer::clearScreen()
149 {
150 	if(m_Settings.m_ZBuffer)
151 		glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
152 	else
153 		glClear( GL_COLOR_BUFFER_BIT );
154 }
155 
updateShadows()156 void CGameRenderer::updateShadows()
157 {
158 	if(m_Settings.m_ShadowSize <= 4) return;
159 
160 	CVector lightDir     = theWorld->getTrack()->m_Environment.m_LightDirection;
161 	CVector lightColor   = theWorld->getTrack()->m_Environment.m_LightColor;
162 	CVector ambientColor = theWorld->getTrack()->m_Environment.m_AmbientColor;
163 
164 	CVector totalColor = 1.4*lightColor + ambientColor;
165 
166 	CVector shadowColor(
167 		lightColor.x / totalColor.x,
168 		lightColor.y / totalColor.y,
169 		lightColor.z / totalColor.z);
170 
171 	for(unsigned int i=0; i < m_GraphicWorld->getNumObjects(CDataObject::eMovingObject); i++)
172 	{
173 		CDynamicShadow *shadow = m_GraphicWorld->getMovObjShadow(i);
174 		shadow->setLightSource(lightDir, shadowColor);
175 		shadow->update(&m_Settings, theWorld->m_LastTime);
176 	}
177 }
178 
updateReflections()179 void CGameRenderer::updateReflections()
180 {
181 	static int currentSide = 0;
182 	static int currentObject = 0;
183 	currentSide++;
184 	if(currentSide >= 6) currentSide = 0;
185 
186 	if(currentSide == 0 || m_Settings.m_UpdRefAllSides)
187 		currentObject++;
188 
189 	/*
190 	The following lines are OUTSIDE the previous if, because the number of
191 	objects can decrease, e.g. between different game sessions.
192 	*/
193 	if(currentObject >= (int)(m_NumCameras * theWorld->getNumObjects(CDataObject::eMovingObject)))
194 		currentObject = 0;
195 
196 
197 	/*
198 	//initialising reflections if they don't exist
199 	unsigned int numRequired = m_NumCameras * m_World->getNumObjects(CDataObject::eMovingObject);
200 	unsigned int numPresent = m_MovingObjectReflections.size();
201 	if(numPresent < numRequired)
202 		for(unsigned int i=0; i< (numRequired - numPresent); i++)
203 		{
204 			CDynamicReflection r(m_Settings.m_ReflectionSize);
205 			m_MovingObjectReflections.push_back(r);
206 		}
207 	*/
208 
209 	//Updating the reflection images
210 	if(m_Settings.m_UpdRefAllObjs)
211 	{
212 		for(unsigned int cam=0; cam < m_NumCameras; cam++)
213 		{
214 			m_CurrentCamera = cam;
215 
216 			for(unsigned int obj=0; obj < theWorld->getNumObjects(CDataObject::eMovingObject); obj++)
217 			{
218 				CMovingObject *mo = theWorld->getMovingObject(obj);
219 				CVector pos = mo->m_Position;
220 
221 				//we don't have to update a reflection that is not visible
222 				if((pos - m_Cameras[cam]->getPosition()).abs() > m_Settings.m_ReflectionDist) continue;
223 
224 				//camera
225 				CCamera front;
226 				pos += mo->m_OrientationMatrix * mo->getCameraPos();
227 				front.setPosition(pos);
228 				front.setOrientation(m_Cameras[cam]->getOrientation());
229 
230 				//update reflection
231 				m_UpdateBodyReflection = obj;
232 
233 				CDynamicReflection *theRefl = m_GraphicWorld->getMovObjReflection(obj, cam);
234 				//unsigned int index = cam + m_NumCameras * obj;
235 				//CDynamicReflection *theRefl = m_MovingObjectReflections[index];
236 
237 				if(m_Settings.m_UpdRefAllSides)
238 					{theRefl->update(this, &front);}
239 				else
240 					{theRefl->update(this, &front, currentSide);}
241 			}
242 
243 		}
244 	}
245 	else
246 	{
247 		unsigned int obj = currentObject / m_NumCameras;
248 		unsigned int cam = currentObject - m_NumCameras * obj;
249 		m_CurrentCamera = cam;
250 
251 		CMovingObject *mo = theWorld->getMovingObject(obj);
252 		CVector pos = mo->m_Position;
253 
254 		//we don't have to update a reflection that is not visible
255 		if((pos - m_Cameras[cam]->getPosition()).abs() <= m_Settings.m_ReflectionDist)
256 		{
257 			//camera
258 			CCamera front;
259 			pos += mo->m_OrientationMatrix * mo->getCameraPos();
260 			front.setPosition(pos);
261 			front.setOrientation(m_Cameras[cam]->getOrientation());
262 
263 			//update reflection
264 			m_UpdateBodyReflection = obj;
265 
266 			CDynamicReflection *theRefl = m_GraphicWorld->getMovObjReflection(obj, cam);
267 			//unsigned int index = cam + m_NumCameras * obj;
268 			//CDynamicReflection *theRefl = m_MovingObjectReflections[index];
269 
270 			if(m_Settings.m_UpdRefAllSides)
271 				{theRefl->update(this, &front);}
272 			else
273 				{theRefl->update(this, &front, currentSide);}
274 		}
275 	}
276 
277 	m_UpdateBodyReflection = -1;
278 }
279 
updateParticleSystems()280 void CGameRenderer::updateParticleSystems()
281 {
282 	for(unsigned int i=0; i < m_GraphicWorld->getNumObjects(CDataObject::eMovingObject); i++)
283 	{
284 		CMovingObject *mo = theWorld->getMovingObject(i);
285 		CGraphicMovObj *gmo = m_GraphicWorld->getMovObj(i);
286 
287 		//Crash smoke
288 		if(m_Settings.m_CrashSmoke)
289 		{
290 			CSmoke &smoke = gmo->m_CrashSmoke;
291 
292 			if(mo->getType() != CMessageBuffer::car) continue;
293 
294 			CCar *theCar = (CCar *)mo;
295 			bool crashed = theCar->m_RuleStatus.state == CCarRuleStatus::eCrashed;
296 
297 			//First set members
298 			smoke.m_Enabled = crashed;
299 			smoke.m_SourcePosition = mo->m_Bodies[0].m_Position;
300 
301 			//Then update the particles
302 			smoke.update(theWorld->m_Lastdt, true);
303 		}
304 	}
305 }
306 
selectCamera(unsigned int n,bool threed)307 void CGameRenderer::selectCamera(unsigned int n, bool threed)
308 {
309 	unsigned int sw = theWinSystem->getWidth();
310 	unsigned int sh = theWinSystem->getHeight();
311 
312 	//default for 1 camera:
313 	unsigned int x = 0, y = 0, w = sw, h = sh;
314 
315 	if(m_NumCameras == 2)
316 	{
317 		if(n == 0) y = sh / 2;
318 		h = sh / 2;
319 	}
320 	if(m_NumCameras > 2)
321 	{
322 		if(n == 0 || n == 1) y = sh / 2;
323 		if(n == 1 || n == 3) x = sw / 2;
324 
325 		w = sw / 2;
326 		h = sh / 2;
327 	}
328 
329 	//Set up openGL viewport + frustum stuff to window size
330 
331 	float ratio = (float) w / (float) h;
332 	GLfloat near = 1.0;
333 	GLfloat far = TILESIZE * m_Settings.m_VisibleTiles;
334 	float hor_mul = near * FOV_MULTIPLIER;
335 	GLfloat xs = ratio*hor_mul;
336 	GLfloat ys = 1.0*hor_mul;
337 
338 	glViewport( x, y, w, h );
339 	m_ViewportW = w;
340 	m_ViewportH = h;
341 
342 	glMatrixMode( GL_PROJECTION );
343 	glLoadIdentity();
344 
345 	if(threed)
346 	{
347 		glFrustum( -xs, xs, -ys, ys, near, far );
348 	}
349 	else
350 	{
351 		glOrtho(0, w, 0, h, -1, 1);
352 	}
353 
354 	glMatrixMode( GL_MODELVIEW );
355 	glLoadIdentity();
356 
357 	setCamera(m_Cameras[n]);
358 }
359 
renderScene()360 void CGameRenderer::renderScene()
361 {
362 	//fprintf(stderr, "renderBackground start: %.3f\n", _DebugTimer.getTime());
363 
364 	const CMatrix &cammat = m_Camera->getOrientation();
365 	//glLoadIdentity();
366 	glLoadMatrixf(cammat.transpose().gl_mtr());
367 
368 	if(m_Settings.m_UseBackground)
369 	{
370 		viewBackground();
371 		if(m_Settings.m_ZBuffer)
372 			glClear(GL_DEPTH_BUFFER_BIT);
373 	}
374 
375 	//fprintf(stderr, "renderTrack start: %.3f\n", _DebugTimer.getTime());
376 
377 	//Lighting:
378 	CVector lightDir = theWorld->getTrack()->m_Environment.m_LightDirection;
379 	GLfloat light_direction[] = {-lightDir.x, -lightDir.y, -lightDir.z, 0.0};
380 	glLightfv(GL_LIGHT0, GL_POSITION, light_direction);
381 
382 	const CVector &camera = m_Camera->getPosition();
383 
384 	glTranslatef (-camera.x, -camera.y, -camera.z);
385 
386 	//Camera position in tile units
387 	camx = (int)(0.5 + (camera.x)/TILESIZE);
388 	camy = (int)(0.5 + (camera.y)/VERTSIZE);
389 	camz = (int)(0.5 + (camera.z)/TILESIZE);
390 
391 	//Camera clipping plane
392 	m_CamPlaneNor  = cammat * CVector(0.0,0.0,-1.0);
393 	m_CamPlaneDist = camera.dotProduct(m_CamPlaneNor);
394 
395 	glEnableClientState(GL_VERTEX_ARRAY);
396 	glEnableClientState(GL_NORMAL_ARRAY);
397 	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
398 
399 	//Draw the track
400 	if(m_Settings.m_TrackDisplayList)
401 		{viewTrack_displaylist();}
402 	else
403 		{viewTrack_normal();}
404 
405 	if(!m_Settings.m_ReflectionDrawMovingObjects && m_UpdateBodyReflection >= 0)
406 		return; //don't draw moving objects
407 
408 	//Draw the moving objects
409 	//float tobj = _DebugTimer.getTime();
410 	CGameCamera *gcam = (CGameCamera *)m_Camera;
411 	int num_objs = theWorld->getNumObjects(CDataObject::eMovingObject);
412 	for(int i=0; i<num_objs; i++)
413 	{
414 		if(i == m_UpdateBodyReflection)
415 			continue; //don't draw the object in its own reflection
416 		if(i == gcam->getTrackedObject() && gcam->getCameraMode() == CGameCamera::In)
417 			continue; //don't draw the object in "In object" camera view
418 		viewMovObj(i);
419 	}
420 	//fprintf(stderr, "Drawing moving objects: %.5f\n", _DebugTimer.getTime() - tobj);
421 
422 	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
423 	glDisableClientState(GL_NORMAL_ARRAY);
424 	glDisableClientState(GL_VERTEX_ARRAY);
425 }
426 
viewBackground()427 void CGameRenderer::viewBackground()
428 {
429 	//if(m_FogMode != -1)
430 	//	glDisable(GL_FOG);
431 	if(m_Settings.m_ZBuffer)
432 		glDisable(GL_DEPTH_TEST);
433 
434 	m_GraphicWorld->m_Background->draw();
435 
436 	//if(m_FogMode != -1)
437 	//	glEnable(GL_FOG);
438 	if(m_Settings.m_ZBuffer)
439 		glEnable(GL_DEPTH_TEST);
440 }
441 
viewTrack_displaylist()442 void CGameRenderer::viewTrack_displaylist()
443 {
444 	static vector<int> x;
445 	static vector<int> y;
446 	static vector<int> z;
447 	static vector<unsigned int> dispList;
448 
449 	while(m_CurrentCamera >= x.size())
450 	{
451 		//generate new camera info
452 		x.push_back(-1);
453 		y.push_back(-1);
454 		z.push_back(-1);
455 		dispList.push_back(glGenLists(1));
456 	}
457 
458 	unsigned int cam = m_CurrentCamera;
459 	//fprintf(stderr, "Camera %d\n", cam);
460 
461 	if(camx != x[cam] || camy != y[cam] || camz != z[cam]) //the display list should be updated
462 	{
463 		x[cam] = camx;
464 		y[cam] = camy;
465 		z[cam] = camz;
466 		//float tstart = _DebugTimer.getTime();
467 		glNewList(dispList[cam], GL_COMPILE);
468 		viewTrack_normal();
469 		glEndList();
470 		//fprintf(stderr, "Updating dispList: %.5f\n", _DebugTimer.getTime() - tstart);
471 	}
472 
473 	//float tstart = _DebugTimer.getTime();
474 	glCallList(dispList[cam]);
475 	//fprintf(stderr, "Calling dispList: %.5f\n", _DebugTimer.getTime() - tstart);
476 
477 	//TODO: find some way to delete unused lists
478 }
479 
viewTrack_normal()480 void CGameRenderer::viewTrack_normal()
481 {
482 	glPushMatrix();
483 
484 	//Nu volgt de weergave-routine
485 	int lengte = theWorld->getTrack()->m_L;
486 	int  breedte = theWorld->getTrack()->m_W;
487 
488 	//printf ("x,y,z = %d,%d,%d\n",camx,camy,camz);
489 
490 	//Nu: de dynamische begrenzing om weergavesnelheid te vergroten
491 	int xmin = (camx-m_Settings.m_VisibleTiles < 0)? 0 : camx-m_Settings.m_VisibleTiles;
492 	int xmax = (camx+m_Settings.m_VisibleTiles >= lengte)? lengte : camx+m_Settings.m_VisibleTiles+1;
493 	int zmin = (camz-m_Settings.m_VisibleTiles < 0)? 0 : camz-m_Settings.m_VisibleTiles;
494 	int zmax = (camz+m_Settings.m_VisibleTiles >= breedte)? breedte : camz+m_Settings.m_VisibleTiles+1;
495 
496 	//if(!m_ZBuffer)
497 	//always back to front (because of transparency)
498 	{
499 		if (camx >= 0) //Linker deel
500 		{
501 			if (camz <= breedte) viewTrackPart(xmin,zmax-1, camx,camz, 1,-1, camy); //achter
502 			if (camz >= 0) viewTrackPart(xmin,zmin, camx,camz+1, 1,1, camy); //voor+linker strook
503 		}
504 		if (camx <= lengte) //Rechter deel
505 		{
506 			if (camz <= breedte) viewTrackPart(xmax-1,zmax-1, camx-1,camz, -1,-1, camy); //achter
507 			if (camz >= 0) viewTrackPart(xmax-1,zmin, camx-1,camz+1, -1,1, camy); //voor+rechter strook
508 		}
509 
510 	}
511 	/*
512 	else //zbuffer
513 	{
514 		//printf("Using z-buffering\n");
515 		viewTrackPart(xmin, zmin, xmax, zmax, 1, 1, camy);
516 	}
517 	*/
518 
519 	glPopMatrix();
520 }
521 
viewTrackPart(int xmin,int ymin,int xmax,int ymax,int dx,int dy,int cur_zpos)522 void CGameRenderer::viewTrackPart(
523 	int xmin,int ymin,
524 	int xmax,int ymax,
525 	int dx,  int dy,
526 	int cur_zpos)
527 {
528 	int lengte = theWorld->getTrack()->m_L;
529 	int  breedte = theWorld->getTrack()->m_W;
530 
531 	glPushMatrix();
532 	glTranslatef(xmin * TILESIZE, 0, ymin * TILESIZE);
533 
534 	if(xmin<0) xmin=0;
535 	if(ymin<0) ymin=0;
536 	if(xmin>=lengte) xmin=lengte-1;
537 	if(ymin>=breedte) ymin=breedte-1;
538 	if(xmax<-1) xmax=-1;
539 	if(ymax<-1) ymax=-1;
540 	if(xmax>lengte) xmax=lengte;
541 	if(ymax>breedte) ymax=breedte;
542 
543 	for (int i = xmin; dx*i < dx*xmax; i+=dx)
544 	{
545 		glPushMatrix();
546 		for (int j = ymin; dy*j < dy*ymax; j+=dy)
547 		{
548 			viewPilaar(i, j, cur_zpos);
549 			glTranslatef(0, 0, dy * TILESIZE);
550 		}
551 		glPopMatrix();
552 		glTranslatef(dx * TILESIZE, 0, 0);
553 	}
554 
555 	glPopMatrix();
556 }
557 
viewPilaar(int x,int y,int cur_zpos)558 void CGameRenderer::viewPilaar(int x, int y, int cur_zpos)
559 {
560 	int  breedte = theWorld->getTrack()->m_W;
561 	int hoogte = theWorld->getTrack()->m_H;
562 
563 	CVector tilepos;
564 
565 
566 	glPushMatrix();
567 
568 		int lod;
569 		int dx=abs(camx-x);
570 		int dy=abs(camz-y); //This (camz) is not a typo!!!
571 
572 		int d = dx;
573 		if(dy>d) d=dy; //d is the largest of the 2
574 
575 		if(d>7)
576 			lod = 4;
577 		else if(d>3)
578 			lod = 3;
579 		else if(d>1)
580 			lod = 2;
581 		else
582 			lod = 1;
583 
584 		float dist = TILESIZE*sqrt((double)(dx*dx+dy*dy));
585 		CReflection *refl = NULL;
586 		if(dist < m_Settings.m_ReflectionDist)
587 			refl = m_GraphicWorld->m_EnvMap;
588 
589 		int pilaar_index = hoogte * y + hoogte * breedte * x;
590 		int ynu = 0;
591 		int rnu = 0;
592 
593 		for (int i = 0; i < hoogte; i++) //bottom to top
594 		{
595 			STile temp = theWorld->getTrack()->m_Track[pilaar_index + i]; //which tile?
596 
597 			if(temp.m_Model == 0) break; //0 = empty tile
598 
599 			//right height
600 			int ystrax = temp.m_Z;
601 
602 			tilepos = CVector(x*TILESIZE, ystrax*VERTSIZE, y*TILESIZE);
603 			if(tilepos.dotProduct(m_CamPlaneNor) < m_CamPlaneDist-TILESIZE)
604 				continue; //behind clipping plane
605 
606 			if(ystrax >= camy)
607 			{
608 				for(int j = hoogte-1; j >= i; j--) //top to bottom
609 				{
610 					temp = theWorld->getTrack()->m_Track[pilaar_index + j]; //which tile?
611 
612 					if(temp.m_Model > 0) //0 = empty tile
613 					{
614 						//right height
615 						ystrax = temp.m_Z;
616 
617 						tilepos = CVector(x*TILESIZE, ystrax*VERTSIZE, y*TILESIZE);
618 						if(tilepos.dotProduct(m_CamPlaneNor) < m_CamPlaneDist-TILESIZE)
619 							continue; //behind clipping plane
620 
621 						glTranslatef(0, VERTSIZE*(ystrax-ynu),0);
622 						ynu = ystrax;
623 
624 						//right orientatie
625 						int rstrax = temp.m_R;
626 						if (rstrax != rnu)
627 						{
628 							glRotatef(90*(rstrax-rnu),0,1,0);
629 							rnu = rstrax;
630 						}
631 
632 						//draw the model
633 						m_GraphicWorld->getTile(temp.m_Model)->draw(
634 							&m_Settings, refl, lod, theWorld->m_LastTime);
635 					}
636 				}
637 				break;
638 			}
639 
640 			glTranslatef(0, VERTSIZE*(ystrax-ynu),0);
641 			ynu = ystrax;
642 
643 			//right orientatie
644 			int rstrax = temp.m_R;
645 			if (rstrax != rnu)
646 			{
647 				glRotatef(90*(rstrax-rnu),0,1,0);
648 				rnu = rstrax;
649 			}
650 
651 			//draw
652 			m_GraphicWorld->getTile(temp.m_Model)->draw(
653 				&m_Settings, refl, lod, theWorld->m_LastTime);
654 		}
655 
656 	glPopMatrix();
657 }
658 
viewMovObj(unsigned int n)659 void CGameRenderer::viewMovObj(unsigned int n)
660 {
661 	CMovingObject *mo = theWorld->getMovingObject(n);
662 	CGraphicMovObj *gmo = m_GraphicWorld->getMovObj(n);
663 
664 	//Determine lighting
665 	//TODO: cache the results of this for split screen
666 	bool inShadow = false;
667 	{
668 		CVector lightdir = -(theWorld->getTrack()->m_Environment.m_LightDirection);
669 
670 		//Check whether we are in the shadow of something
671 		CCollisionDetector &detector = theWorld->m_Detector;
672 		float colDist = detector.getLineCollision(mo->m_Position, lightdir);
673 		if(colDist > 0.0) inShadow = true;
674 	}
675 
676 	if(inShadow) glDisable(GL_LIGHT0);
677 
678 	for(unsigned int i=mo->m_Bodies.size(); i > 0; i--) //TODO: depth sorting?
679 	{
680 		CBody &b = mo->m_Bodies[i-1];
681 		CVector r = b.m_Position;
682 
683 		float dist = (m_Camera->getPosition() - r).abs();
684 		if(dist > TILESIZE * m_Settings.m_VisibleTiles) continue; //not visible
685 
686 		int lod;
687 		if(dist > TILESIZE * 7)
688 			lod = 4;
689 		else if(dist > TILESIZE * 3)
690 			lod = 3;
691 		else if(dist > TILESIZE * 1)
692 			lod = 2;
693 		else
694 			lod = 1;
695 
696 		lod += m_Settings.m_MovingObjectLOD;
697 		if(lod > 4) lod = 4;
698 		if(lod < 1) lod = 1;
699 
700 		glPushMatrix();
701 		glTranslatef (r.x, r.y, r.z);
702 		glMultMatrixf(b.m_OrientationMatrix.gl_mtr());
703 
704 		//The model and the reflection
705 		if(dist < m_Settings.m_ReflectionDist)
706 		{
707 			CDynamicReflection &theRefl = gmo->m_Reflections[m_CurrentCamera];
708 
709 			m_GraphicWorld->getMovObjBound(b.m_Body)->draw(
710 				&m_Settings, &theRefl, lod, theWorld->m_LastTime);
711 		}
712 		else
713 		{
714 			m_GraphicWorld->getMovObjBound(b.m_Body)->draw(
715 				&m_Settings, NULL, lod, theWorld->m_LastTime);
716 		}
717 
718 		glPopMatrix();
719 	}
720 
721 	if(inShadow) glEnable(GL_LIGHT0);
722 
723 
724 	//The shadow
725 	if(!inShadow && m_Settings.m_ShadowSize > 4)
726 	{
727 		CVector r = mo->m_Bodies[0].m_Position;
728 		const CCollisionFace *plane = theWorld->m_Detector.getGroundFace(r);
729 		if(plane != NULL)
730 		{
731 			CVector lightDir = theWorld->getTrack()->m_Environment.m_LightDirection.normal();
732 			float ldotn = lightDir.dotProduct(plane->nor);
733 			if(ldotn < -0.001) //plane is lighted
734 			{
735 				CVector difference = lightDir / ldotn;
736 
737 				CDynamicShadow *shadow = gmo->m_Shadow;
738 
739 				float ps = shadow->getPhysicalSize();
740 				CVector texcoords[] = {
741 					CVector(0,0,0),
742 					CVector(1,0,0),
743 					CVector(1,1,0),
744 					CVector(0,1,0)
745 					};
746 				CVector corners[4];
747 				for(unsigned int i=0; i<4; i++)
748 				{
749 					corners[i] = ps*(2*texcoords[i]-CVector(1,1,0));
750 					corners[i] *= shadow->getLightOrientation();
751 					corners[i] += r;
752 					corners[i] -= difference * (corners[i].dotProduct(plane->nor) - plane->d - 0.01);
753 				}
754 
755 				shadow->enable();
756 
757 				glBegin(GL_QUADS);
758 				for(unsigned int i=0; i<4; i++)
759 				{
760 					glTexCoord2f(texcoords[i].x,texcoords[i].y);
761 					glVertex3f(corners[i].x,corners[i].y,corners[i].z);
762 				}
763 				glEnd();
764 
765 				shadow->disable();
766 			}
767 		}
768 	}
769 
770 	//Crash smoke
771 	if(m_Settings.m_CrashSmoke)
772 		gmo->m_CrashSmoke.draw(m_Camera->getOrientation());
773 }
774 
viewDashboard(unsigned int n)775 void CGameRenderer::viewDashboard(unsigned int n)
776 {
777 	if(m_Settings.m_ZBuffer) glDisable(GL_DEPTH_TEST);
778 	if(m_Settings.m_FogMode >= 0) glDisable(GL_FOG);
779 	glDisable(GL_LIGHTING);
780 	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
781 
782 	if( ((CGameCamera *)m_Camera)->getCameraMode() == CGameCamera::In )
783 	{
784 		m_GraphicWorld->getMovObjDashboard(n)->draw(m_ViewportW, m_ViewportH, CDashboard::eFull);
785 	}
786 	else
787 	{
788 		m_GraphicWorld->getMovObjDashboard(n)->draw(m_ViewportW, m_ViewportH, CDashboard::eGauges);
789 	}
790 
791 	//Reflection debugging:
792 	/*
793 	glPushMatrix();
794 	glScalef(m_ViewportW, m_ViewportH, 1.0);
795 	glTranslatef(0.75, 0.75, 0.0);
796 
797 	//glDisable(GL_BLEND);
798 	glColor4f(1,1,1,1);
799 	CDynamicReflection *theRefl = m_GraphicWorld->getMovObjReflection(0, 0);
800 	theRefl->enable(&m_Settings);
801 	theRefl->disable();
802 
803 	glBegin(GL_QUADS);
804 	glTexCoord2f(0,0);
805 	glVertex2f(-0.2,-0.2);
806 	glTexCoord2f(1,0);
807 	glVertex2f( 0.2,-0.2);
808 	glTexCoord2f(1,1);
809 	glVertex2f( 0.2, 0.2);
810 	glTexCoord2f(0,1);
811 	glVertex2f(-0.2, 0.2);
812 	glEnd();
813 
814 	//glEnable(GL_BLEND);
815 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //default blending function
816 	glPopMatrix();
817 	*/
818 
819 	glLoadIdentity();
820 	viewLensFlare();
821 
822 	glEnable(GL_LIGHTING);
823 	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
824 	if(m_Settings.m_ZBuffer) glEnable(GL_DEPTH_TEST);
825 	if(m_Settings.m_FogMode >= 0) glEnable(GL_FOG);
826 }
827 
viewLensFlare()828 void CGameRenderer::viewLensFlare()
829 {
830 	//No lens flare if no images are specified
831 	if(m_GraphicWorld->m_LensFlare.size() == 0) return;
832 
833 	CVector lightdir = -(theWorld->getTrack()->m_Environment.m_LightDirection);
834 
835 	//Check whether we are in the shadow of something
836 	CCollisionDetector &detector = theWorld->m_Detector;
837 	float colDist = detector.getLineCollision(m_Camera->getPosition(), lightdir);
838 	if(colDist > 0.0) return; //collision: we are in a shadow
839 
840 	CVector lightcol = theWorld->getTrack()->m_Environment.m_LightColor;
841 	const CMatrix &cammat = m_Camera->getOrientation();
842 
843 	lightdir /= cammat;
844 
845 	if(lightdir.z > -0.01) return; //behind camera
846 	lightdir.z = -lightdir.z;
847 
848 	lightdir.x /= lightdir.z;
849 	lightdir.y /= lightdir.z;
850 	lightdir.z = 0.0;
851 
852 	lightdir *= 0.5 / FOV_MULTIPLIER;
853 	lightdir.x *= float(m_ViewportH) / m_ViewportW;
854 
855 	float distance = lightdir.abs();
856 	if(distance >= 2.0) return; //out of view
857 	float intensity = 0.5 * (2.0 - distance);
858 
859 	float angle = atan2f(lightdir.y, lightdir.x) * (180.0/M_PI);
860 
861 	glBlendFunc(GL_SRC_ALPHA, GL_ONE); //additive blending
862 
863 	glPushMatrix();
864 	glTranslatef(0.5*m_ViewportW, 0.5*m_ViewportH, 0.0);
865 	glScalef(m_ViewportW, m_ViewportW, 1.0);
866 
867 	//Flare images
868 	for(unsigned int i=0; i < m_GraphicWorld->m_LensFlare.size(); i++)
869 	{
870 		const CGraphicWorld::SLensFlare &flare = m_GraphicWorld->m_LensFlare[i];
871 
872 		CVector flarepos = flare.distance * lightdir;
873 
874 		float flaresize = flare.size;
875 		float flareintensity = intensity;
876 		//if(i > 0) flareintensity *= 0.5; //Everything half the intensity of the sun
877 
878 		glColor4f(lightcol.x, lightcol.y, lightcol.z, flareintensity);
879 		flare.image->draw();
880 
881 		glPushMatrix();
882 		glTranslatef(flarepos.x, flarepos.y, 0.0);
883 		glRotatef(2 * angle, 0.0, 0.0, 1.0);
884 
885 		glBegin(GL_QUADS);
886 		glTexCoord2f(0,0);
887 		glVertex2f(-flaresize,-flaresize);
888 		glTexCoord2f(1,0);
889 		glVertex2f( flaresize,-flaresize);
890 		glTexCoord2f(1,1);
891 		glVertex2f( flaresize, flaresize);
892 		glTexCoord2f(0,1);
893 		glVertex2f(-flaresize, flaresize);
894 		glEnd();
895 
896 		glPopMatrix();
897 	}
898 
899 	//Whitening
900 	glColor4f(lightcol.x, lightcol.y, lightcol.z, 0.5*intensity);
901 	glBindTexture(GL_TEXTURE_2D, 0); //no texture
902 	glRectf(-0.5,-0.5,0.5,0.5);
903 
904 	glPopMatrix();
905 
906 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //default blending function
907 	glColor4f(1,1,1,1);
908 }
909