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