1 //
2 // Copyright (C) 2004-2006 Jasmine Langridge, ja-reiko@users.sourceforge.net
3 // Copyright (C) 2015 Andrei Bondor, ab396356@users.sourceforge.net
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 //
19 
20 #include <cmath>
21 #include "main.h"
22 
resize()23 void MainApp::resize()
24 {
25     glClearColor(1.0,1.0,1.0,1.0);
26     glEnable(GL_TEXTURE_2D);
27 
28     glEnable(GL_BLEND);
29     glBlendFunc(GL_ONE,GL_ZERO);
30 
31     glDepthFunc(GL_LEQUAL);
32     glEnable(GL_DEPTH_TEST);
33     glClearDepth(1.0);
34 
35     glEnable(GL_CULL_FACE);
36 
37     glEnable(GL_FOG);
38     glFogi(GL_FOG_MODE, GL_EXP);
39 
40     glEnable(GL_LIGHT0);
41     glEnable(GL_LIGHTING);
42 
43     const GLfloat ambcol[] = {0.1f, 0.1f, 0.1f, 0.0f};
44     glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambcol);
45 
46     float white[] = { 1.0,1.0,1.0,1.0 };
47     //float black[] = { 0.0,0.0,0.0,1.0 };
48     glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,white);
49 
50     float spec[] = { 0.3f, 0.5f, 0.5f, 1.0f };
51     glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, spec);
52     glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 6.0f);
53 
54     float litcol[] = { 0.6,0.6,0.6,0.0 };
55     glLightfv(GL_LIGHT0,GL_DIFFUSE,litcol);
56     glLightfv(GL_LIGHT0,GL_SPECULAR,litcol);
57 
58     glEnable(GL_NORMALIZE);
59 }
60 
drawBlades(float radius,float ang,float trace)61 void drawBlades(float radius, float ang, float trace)
62 {
63     float invtrace = 1.0 / trace;
64     glPushMatrix();
65     glScalef(radius, radius, 1.0);
66     for (float ba=0; ba<PI*2.0-0.01; ba+=PI/2.0)
67     {
68         glBegin(GL_TRIANGLE_FAN);
69         glColor4f(0.1,0.1,0.1,0.24 * invtrace);
70         glVertex2f(0.0,0.0);
71         glColor4f(0.1,0.1,0.1,0.06 * invtrace);
72         int num = (int)(trace / 0.1);
73         if (num < 2) num = 2;
74         float mult = trace / (float)(num-1);
75         float angadd = ba + ang;
76         for (int i=0; i<num; ++i)
77         {
78             float a = (float)i * mult + angadd;
79             glVertex2f(cos(a),sin(a));
80         }
81         glEnd();
82     }
83     glPopMatrix();
84 }
85 
renderWater()86 void MainApp::renderWater()
87 {
88     tex_water->bind();
89     {
90         float tgens[] = { 0.5,0,0,0 };
91         float tgent[] = { 0,0.5,0,0 };
92         glTexGeni(GL_S,GL_TEXTURE_GEN_MODE,GL_OBJECT_LINEAR);
93         glTexGenfv(GL_S,GL_OBJECT_PLANE,tgens);
94         glTexGeni(GL_T,GL_TEXTURE_GEN_MODE,GL_OBJECT_LINEAR);
95         glTexGenfv(GL_T,GL_OBJECT_PLANE,tgent);
96     }
97     glEnable(GL_TEXTURE_GEN_S);
98     glEnable(GL_TEXTURE_GEN_T);
99     glPushMatrix();
100     glScalef(20.0,20.0,1.0);
101     glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
102     glEnable(GL_BLEND);
103     {
104         int minx = (int)(campos.x / 20.0)-20,
105             maxx = minx + 40,
106             miny = (int)(campos.y / 20.0)-20,
107             maxy = miny + 40;
108         for (int y=miny; y<maxy; ++y)
109         {
110             glBegin(GL_TRIANGLE_STRIP);
111             for (int x=minx; x<=maxx; ++x)
112             {
113                 float maxalpha = 0.5f;
114 
115                 if (game->water.useralpha)
116                     maxalpha = game->water.alpha;
117 
118                 if (game->water.fixedalpha)
119                 {
120                     glColor4f(1.0f, 1.0f, 1.0f, maxalpha);
121                     glVertex3f(x, y+1, game->water.height);
122                     glVertex3f(x, y, game->water.height);
123                 }
124                 else
125                 {
126                     float ht,alpha;
127                     ht = game->terrain->getHeight((x)*20.0,(y+1)*20.0);
128                     alpha = 1.0 - exp(ht - game->water.height);
129                     CLAMP(alpha, 0.0f, maxalpha);
130                     glColor4f(1.0,1.0,1.0,alpha);
131                     glVertex3f(x, y+1, game->water.height);
132                     ht = game->terrain->getHeight((x)*20.0,(y)*20.0);
133                     alpha = 1.0 - exp(ht - game->water.height);
134                     CLAMP(alpha, 0.0f, maxalpha);
135                     glColor4f(1.0,1.0,1.0,alpha);
136                     glVertex3f(x, y, game->water.height);
137                 }
138             }
139             glEnd();
140         }
141     }
142     glPopMatrix();
143     glBlendFunc(GL_ONE,GL_ZERO);
144 
145     glDisable(GL_TEXTURE_GEN_S);
146     glDisable(GL_TEXTURE_GEN_T);
147 }
148 
renderSky(const mat44f & cammat)149 void MainApp::renderSky(const mat44f &cammat)
150 {
151     glFogf(GL_FOG_DENSITY, game->weather.fog.density_sky);
152     glDepthRange(0.999,1.0);
153     glDisable(GL_CULL_FACE);
154     glPushMatrix(); // 1
155     glLoadIdentity();
156     glMultMatrixf(cammat);
157     tex_sky[0]->bind();
158 #define CLRANGE     10
159 #define CLFACTOR    0.02//0.014
160     glMatrixMode(GL_TEXTURE);
161     glPushMatrix();
162     glTranslatef(cloudscroll,0.0,0.0);
163     glRotatef(30.0,0.0,0.0,1.0);
164     glScalef(0.4,0.4,1.0);
165     for (int y=-CLRANGE; y<CLRANGE; y++)
166     {
167         glBegin(GL_TRIANGLE_STRIP);
168         for (int x=-CLRANGE; x<CLRANGE+1; x++)
169         {
170             glTexCoord2i(x,y);
171             glVertex3f(x,y,0.3-(x*x+y*y)*CLFACTOR);
172             glTexCoord2i(x,y+1);
173             glVertex3f(x,y+1,0.3-(x*x+(y+1)*(y+1))*CLFACTOR);
174         }
175         glEnd();
176     }
177     glPopMatrix();
178     glMatrixMode(GL_MODELVIEW);
179     glPopMatrix(); // 1
180     glEnable(GL_CULL_FACE);
181     glDepthRange(0.0,0.999);
182     glFogf(GL_FOG_DENSITY, game->weather.fog.density);
183 }
184 
render(float eyetranslation)185 void MainApp::render(float eyetranslation)
186 {
187     switch (appstate)
188     {
189         case AS_LOAD_1:
190             renderStateLoading(eyetranslation);
191             break;
192 
193         case AS_LOAD_2:
194         case AS_LOAD_3:
195             break;
196 
197         case AS_LEVEL_SCREEN:
198             renderStateLevel(eyetranslation);
199             break;
200 
201         case AS_CHOOSE_VEHICLE:
202             renderStateChoose(eyetranslation);
203             break;
204 
205         case AS_IN_GAME:
206             renderStateGame(eyetranslation);
207             break;
208 
209         case AS_END_SCREEN:
210             renderStateEnd(eyetranslation);
211             break;
212     }
213 
214     glFinish();
215 }
216 
renderStateLoading(float eyetranslation)217 void MainApp::renderStateLoading(float eyetranslation)
218 {
219     UNREFERENCED_PARAMETER(eyetranslation);
220 
221     glMatrixMode(GL_PROJECTION);
222     glPushMatrix();
223     glLoadIdentity();
224     glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
225     glMatrixMode(GL_MODELVIEW);
226 
227     tex_splash_screen->bind();
228 
229     glDisable(GL_DEPTH_TEST);
230     glDisable(GL_FOG);
231     glDisable(GL_LIGHTING);
232     glEnable(GL_BLEND);
233     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
234 
235     glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
236 
237     glBegin(GL_QUADS);
238     // the background image is square and cut out a piece based on aspect ratio
239     // -------- if aspect ratio is larger than 4:3
240     // if aspect ratio is larger than 1:1
241     if ((float)getWidth()/(float)getHeight() > 1.0f)
242     {
243 
244       // lower and upper offset based on aspect ratio
245       float off_l = (1 - ((float)getHeight() / (float)getWidth())) / 2.f;
246       float off_u = 1 - off_l;
247       glTexCoord2f(1.0f,off_u); glVertex2f(1.0f, 1.0f);
248       glTexCoord2f(0.0f,off_u); glVertex2f(-1.0f, 1.0f);
249       glTexCoord2f(0.0f,off_l); glVertex2f(-1.0f, -1.0f);
250       glTexCoord2f(1.0f,off_l); glVertex2f(1.0f, -1.0f);
251     }
252     // other cases (including 4:3, in which case off_l and off_u are = 1)
253     else
254     {
255 
256       float off_l = (1 - ((float)getWidth() / (float)getHeight())) / 2.f;
257       float off_u = 1 - off_l;
258       glTexCoord2f(off_u,1.0f); glVertex2f(1.0f, 1.0f);
259       glTexCoord2f(off_l,1.0f); glVertex2f(-1.0f, 1.0f);
260       glTexCoord2f(off_l,0.0f); glVertex2f(-1.0f, -1.0f);
261       glTexCoord2f(off_u,0.0f); glVertex2f(1.0f, -1.0f);
262     }
263     glEnd();
264 
265     tex_loading_screen->bind();
266 
267     GLfloat logovratio = static_cast<float> (getWidth()) / getHeight();
268     GLfloat logohratio = static_cast<float> (getHeight()) / getWidth();
269 
270     // FIXME: nasty, nasty code
271     if (logovratio > 1.0f)
272         logohratio = 1.0f;
273     else
274     if (logohratio > 1.0f)
275         logovratio = 1.0f;
276 
277 #define LOGO_VRATIO     (logovratio/3.5)
278 #define LOGO_HRATIO     (logohratio/3.5)
279     glBegin(GL_QUADS);
280       glTexCoord2f(1.0f, 1.0f); glVertex2f( LOGO_HRATIO,  LOGO_VRATIO);
281       glTexCoord2f(0.0f, 1.0f); glVertex2f(-LOGO_HRATIO,  LOGO_VRATIO);
282       glTexCoord2f(0.0f, 0.0f); glVertex2f(-LOGO_HRATIO, -LOGO_VRATIO);
283       glTexCoord2f(1.0f, 0.0f); glVertex2f( LOGO_HRATIO, -LOGO_VRATIO);
284     glEnd();
285 #undef LOGO_VRATIO
286 #undef LOGO_HRATIO
287 
288     glEnable(GL_DEPTH_TEST);
289     glEnable(GL_FOG);
290     glEnable(GL_LIGHTING);
291 
292     glMatrixMode(GL_PROJECTION);
293     glPopMatrix();
294     glMatrixMode(GL_MODELVIEW);
295 }
296 
297 const char *creditstext[] =
298 {
299     "Trigger Rally " PACKAGE_VERSION,
300     "",
301     "Copyright (C) 2004-2006",
302     "Jasmine Langridge and Richard Langridge",
303     "Posit Interactive",
304     "",
305     "Copyright (C) 2006-2016",
306     "Various Contributors",
307     "(see DATA_AUTHORS.txt)",
308     "",
309     "",
310     "",
311     "Coding",
312     "Jasmine Langridge",
313     "",
314     "Art & SFX",
315     "Richard Langridge",
316     "",
317     "",
318     "",
319     "Contributors",
320     "",
321     "Build system",
322     "Matze Braune",
323     "",
324     "Stereo support",
325     "Chuck Sites",
326     "",
327     "Mac OS X porting",
328     "Tim Douglas",
329     "",
330     "Fixes",
331     "LavaPunk",
332     "Bernhard Kaindl",
333     "Liviu Andronic",
334     "Ishmael Turner",
335     "Iwan 'qubodup' Gabovitch",
336     "Farrer",
337     "Andrei Bondor",
338     "Nikolay Orlyuk",
339 	"Emanuele Sorce",
340     "",
341     "New levels",
342     "Tim Wintle",
343     "David Pagnier",
344     "Jared Buckner",
345     "Andreas Rosdal",
346     "Ivan",
347     "Viktor Radnai",
348     "Pierre-Alexis",
349     "Bruno 'Fuddl' Kleinert",
350     "Agnius Vasiliauskas",
351     "Matthias Keysermann",
352     "Marcio Bremm",
353     "Onsemeliot",
354     "",
355     "Graphics",
356     "Alex",
357     "Roberto Diez Gonzalez",
358     "",
359     "",
360     "",
361     "",
362     "",
363     "Thanks to Jonathan C. Hatfull",
364     "",
365     "",
366     "",
367     "",
368     "And thanks to Simon Brown too",
369     "",
370     "",
371     "",
372     "",
373     "",
374     "",
375     "Thanks for playing Trigger"
376 };
377 
378 #define NUMCREDITSTRINGS (sizeof(creditstext) / sizeof(char*))
379 
renderStateEnd(float eyetranslation)380 void MainApp::renderStateEnd(float eyetranslation)
381 {
382     eyetranslation = eyetranslation;
383 
384     glMatrixMode(GL_PROJECTION);
385     glPushMatrix();
386     glLoadIdentity();
387     glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
388     glMatrixMode(GL_MODELVIEW);
389 
390     tex_end_screen->bind();
391 
392     glDisable(GL_DEPTH_TEST);
393     glDisable(GL_FOG);
394     glDisable(GL_LIGHTING);
395     glBlendFunc(GL_ONE, GL_ZERO);
396 
397     glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
398 
399     glBegin(GL_QUADS);
400     // the background image is square and cut out a piece based on aspect ratio
401     // -------- if aspect ratio is larger than 4:3
402     // if aspect ratio is larger than 1:1
403     if ((float)getWidth()/(float)getHeight() > 1.0f)
404     {
405 
406       // lower and upper offset based on aspect ratio
407       float off_l = (1 - ((float)getHeight() / (float)getWidth())) / 2.f;
408       float off_u = 1 - off_l;
409       glTexCoord2f(1.0f,off_u); glVertex2f(1.0f, 1.0f);
410       glTexCoord2f(0.0f,off_u); glVertex2f(-1.0f, 1.0f);
411       glTexCoord2f(0.0f,off_l); glVertex2f(-1.0f, -1.0f);
412       glTexCoord2f(1.0f,off_l); glVertex2f(1.0f, -1.0f);
413     }
414     // other cases (including 4:3, in which case off_l and off_u are = 1)
415     else
416     {
417 
418       float off_l = (1 - ((float)getWidth() / (float)getHeight())) / 2.f;
419       float off_u = 1 - off_l;
420       glTexCoord2f(off_u,1.0f); glVertex2f(1.0f, 1.0f);
421       glTexCoord2f(off_l,1.0f); glVertex2f(-1.0f, 1.0f);
422       glTexCoord2f(off_l,0.0f); glVertex2f(-1.0f, -1.0f);
423       glTexCoord2f(off_u,0.0f); glVertex2f(1.0f, -1.0f);
424     }
425     glEnd();
426 
427     tex_fontSourceCodeOutlined->bind();
428 
429     glMatrixMode(GL_PROJECTION);
430     glPopMatrix();
431     glPushMatrix();
432     glLoadIdentity();
433     glOrtho(0 - hratio, hratio, 0 - vratio, vratio, 0 - 1.0, 1.0);
434     //glOrtho(-1, 1, -1, 1, -1, 1);
435     //glOrtho(800, 0, 600, 0, -1, 1);
436     glMatrixMode(GL_MODELVIEW);
437 
438     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
439 
440     glPushMatrix();
441 
442     float scroll = splashtimeout;
443     const float maxscroll = (float)(NUMCREDITSTRINGS - 1) * 2.0f;
444     RANGEADJUST(scroll, 0.0f, 0.9f, -10.0f, maxscroll);
445     CLAMP_UPPER(scroll, maxscroll);
446 
447     glScalef(0.1f, 0.1f, 1.0f);
448 
449     glTranslatef(0.0f, scroll, 0.0f);
450 
451     for (int i = 0; i < (int)NUMCREDITSTRINGS; i++)
452     {
453         float level = fabsf(scroll + (float)i * -2.0f);
454         RANGEADJUST(level, 0.0f, 9.0f, 3.0f, 0.0f);
455 
456         if (level > 0.0f)
457         {
458             CLAMP_UPPER(level, 1.0f);
459 
460             glPushMatrix();
461             glTranslatef(0.0f, (float)i * -2.0f, 0.0f);
462 
463             float enlarge = 1.0f;
464 
465 #if 1
466             if (splashtimeout > 0.9f)
467             {
468                 float amt = (splashtimeout - 0.9f) * 10.0f;
469                 float amt2 = amt * amt;
470 
471                 enlarge += amt2 / ((1.0001f - amt) * (1.0001f - amt));
472                 level -= amt2;
473             }
474 #endif
475 
476             glScalef(enlarge, enlarge, 0.0f);
477             glColor4f(1.0f, 1.0f, 1.0f, level);
478 
479             getSSRender().drawText(creditstext[i], PTEXT_HZA_CENTER | PTEXT_VTA_CENTER);
480             glPopMatrix();
481         }
482     }
483 
484     glPopMatrix();
485 
486     glEnable(GL_DEPTH_TEST);
487     glEnable(GL_FOG);
488     glEnable(GL_LIGHTING);
489 
490     glMatrixMode(GL_PROJECTION);
491     glPopMatrix();
492     glMatrixMode(GL_MODELVIEW);
493 }
494 
renderStateChoose(float eyetranslation)495 void MainApp::renderStateChoose(float eyetranslation)
496 {
497     PVehicleType *vtype = game->vehiclechoices[choose_type];
498 
499     glClearColor(0.0, 0.0, 0.0, 1.0);
500     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
501 
502 glMatrixMode(GL_PROJECTION);
503 
504   glPushMatrix();
505   glLoadIdentity();
506   glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
507 
508     glMatrixMode(GL_MODELVIEW);
509 
510   // draw background image
511 
512   glBlendFunc(GL_ONE, GL_ZERO);
513   glDisable(GL_DEPTH_TEST);
514   glDisable(GL_FOG);
515   glDisable(GL_LIGHTING);
516 
517   tex_splash_screen->bind();
518 
519   //glColor4f(0.0f, 0.0f, 0.2f, 1.0f); // make image dark blue
520   glColor4f(1.0f, 1.0f, 1.0f, 1.0f); // use image's normal colors
521   //glColor4f(0.5f, 0.5f, 0.5f, 1.0f); // make image darker
522 
523     glBegin(GL_QUADS);
524     // the background image is square and cut out a piece based on aspect ratio
525     // -------- if aspect ratio is larger than 4:3
526     // if aspect ratio is larger than 1:1
527     if ((float)getWidth()/(float)getHeight() > 1.0f)
528     {
529 
530       // lower and upper offset based on aspect ratio
531       float off_l = (1 - ((float)getHeight() / (float)getWidth())) / 2.f;
532       float off_u = 1 - off_l;
533       glTexCoord2f(1.0f,off_u); glVertex2f(1.0f, 1.0f);
534       glTexCoord2f(0.0f,off_u); glVertex2f(-1.0f, 1.0f);
535       glTexCoord2f(0.0f,off_l); glVertex2f(-1.0f, -1.0f);
536       glTexCoord2f(1.0f,off_l); glVertex2f(1.0f, -1.0f);
537     }
538     // other cases (including 4:3, in which case off_l and off_u are = 1)
539     else
540     {
541 
542       float off_l = (1 - ((float)getWidth() / (float)getHeight())) / 2.f;
543       float off_u = 1 - off_l;
544       glTexCoord2f(off_u,1.0f); glVertex2f(1.0f, 1.0f);
545       glTexCoord2f(off_l,1.0f); glVertex2f(-1.0f, 1.0f);
546       glTexCoord2f(off_l,0.0f); glVertex2f(-1.0f, -1.0f);
547       glTexCoord2f(off_u,0.0f); glVertex2f(1.0f, -1.0f);
548     }
549     glEnd();
550 
551     glMatrixMode(GL_PROJECTION);
552     glPopMatrix();
553 
554     glMatrixMode(GL_PROJECTION);
555     glLoadIdentity();
556 
557     float fnear = 0.1f, fov = 0.6f;
558     float aspect = (float)getWidth() / (float)getHeight();
559     stereoFrustum(-fnear*aspect*fov,fnear*aspect*fov,-fnear*fov,fnear*fov,fnear,100000.0f,
560                   0.8f, eyetranslation);
561     glMatrixMode(GL_MODELVIEW);
562 
563 
564     glPushMatrix(); // 0
565 
566 //    glTranslatef(-eyetranslation, 0.5f, -5.0f);
567     glTranslatef(-eyetranslation, 0.9f, -5.0f);
568     glRotatef(28.0f, 1.0f, 0.0f, 0.0f);
569 
570     glDisable(GL_FOG);
571     glEnable(GL_LIGHTING);
572     glEnable(GL_DEPTH_TEST);
573 
574     vec4f lpos = vec4f(0.0f, 1.0f, 0.0f, 0.0f);
575     glLightfv(GL_LIGHT0, GL_POSITION, lpos);
576 
577     //float tmp = 1.0f;
578     //float tmp = sinf(choose_spin * 2.0f) * 0.5f;
579     float tmp = cosf(choose_spin * 2.0f) * 0.5f;
580     tmp += choose_spin;
581     glRotatef(90.0f, -1.0f, 0.0f, 0.0f);
582     glRotatef(DEGREES(tmp), 0.0f, 0.0f, 1.0f);
583 
584     {
585         for (unsigned int i=0; i<vtype->part.size(); ++i)
586         {
587             glPushMatrix(); // 1
588 
589             vec3f vpos = vtype->part[i].ref_local.pos;
590             glTranslatef(vpos.x, vpos.y, vpos.z);
591 
592             mat44f vorim = vtype->part[i].ref_local.ori_mat_inv;
593             glMultMatrixf(vorim);
594             if (vtype->part[i].model)
595             {
596 
597                 glPushMatrix(); // 2
598 
599                 float scale = vtype->part[i].scale;
600                 glScalef(scale,scale,scale);
601                 drawModel(*vtype->part[i].model);
602 
603                 glPopMatrix(); // 2
604             }
605 
606             if (vtype->wheelmodel)
607             {
608                 for (unsigned int j=0; j<vtype->part[i].wheel.size(); j++)
609                 {
610 
611                     glPushMatrix(); // 2
612 
613                     vec3f &wpos = vtype->part[i].wheel[j].pt;
614                     glTranslatef(wpos.x, wpos.y, wpos.z);
615 
616                     float scale = vtype->wheelscale * vtype->part[i].wheel[j].radius;
617                     glScalef(scale,scale,scale);
618 
619                     drawModel(*vtype->wheelmodel);
620 
621                     glPopMatrix(); // 2
622                 }
623             }
624 
625             glPopMatrix(); // 1
626         }
627     }
628 
629     glPopMatrix(); // 0
630 
631     glDisable(GL_LIGHTING);
632 
633     glMatrixMode(GL_PROJECTION);
634     glPushMatrix();
635     glLoadIdentity();
636     glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
637     glMatrixMode(GL_MODELVIEW);
638 
639     // use the same colors as the menu
640     const GuiWidgetColors gwc = gui.getColors();
641 
642     tex_fontSourceCodeShadowed->bind();
643 
644     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
645     glDisable(GL_DEPTH_TEST);
646     glDisable(GL_LIGHTING);
647 
648     glPushMatrix(); // 0
649 
650     const GLdouble margin = (800.0 - 600.0 * cx / cy) / 2.0;
651 
652     glOrtho(margin, 600.0 * cx / cy + margin, 0.0, 600.0, -1.0, 1.0);
653 
654     glPushMatrix(); // 1
655     glTranslatef(10.0f, 570.0f, 0.0f);
656     glScalef(30.0f, 30.0f, 1.0f);
657     glColor4f(gwc.weak.x, gwc.weak.y, gwc.weak.z, gwc.weak.w);
658     getSSRender().drawText("Trigger Rally", PTEXT_HZA_LEFT | PTEXT_VTA_CENTER);
659     glPopMatrix(); // 1
660 
661     glPushMatrix(); // 1
662     glTranslatef(790.0f, 570.0f, 0.0f);
663     glScalef(20.0f, 20.0f, 1.0f);
664     glColor4f(gwc.weak.x, gwc.weak.y, gwc.weak.z, gwc.weak.w);
665     getSSRender().drawText(
666         "car selection " + std::to_string(choose_type + 1) + '/' + std::to_string(game->vehiclechoices.size()),
667         PTEXT_HZA_RIGHT | PTEXT_VTA_CENTER);
668     glPopMatrix(); // 1
669 
670     glPushMatrix(); // 1
671     glTranslatef(100.0f, 230.0f, 0.0f);
672     glScalef(30.0f, 30.0f, 1.0f);
673     glColor4f(gwc.header.x, gwc.header.y, gwc.header.z, gwc.header.w);
674     getSSRender().drawText(vtype->proper_name.substr(0, 9), PTEXT_HZA_LEFT | PTEXT_VTA_CENTER);
675     glPopMatrix(); // 1
676 
677     glPushMatrix(); // 1
678     glTranslatef(100.0f, 200.0f, 0.0f);
679     glScalef(20.0f, 20.0f, 1.0f);
680     glColor4f(gwc.strong.x, gwc.strong.y, gwc.strong.z, gwc.strong.w);
681     getSSRender().drawText(vtype->proper_class.substr(0, 8), PTEXT_HZA_LEFT | PTEXT_VTA_CENTER);
682     glPopMatrix(); // 1
683 
684     glPushMatrix(); // 1
685     glTranslatef(500.0f, 230.0f, 0.0f);
686     glScalef(20.0f, 20.0f, 1.0f);
687     glColor4f(gwc.weak.x, gwc.weak.y, gwc.weak.z, gwc.weak.w);
688     getSSRender().drawText("Weight (Kg)", PTEXT_HZA_RIGHT | PTEXT_VTA_CENTER);
689     glPopMatrix(); // 1
690 
691     glPushMatrix(); // 1
692     glTranslatef(500.0f, 190.0f, 0.0f);
693     glScalef(20.0f, 20.0f, 1.0f);
694     glColor4f(gwc.weak.x, gwc.weak.y, gwc.weak.z, gwc.weak.w);
695     getSSRender().drawText("Engine (BHP)", PTEXT_HZA_RIGHT | PTEXT_VTA_CENTER);
696     glPopMatrix(); // 1
697 
698     glPushMatrix(); // 1
699     glTranslatef(500.0f, 150.0f, 0.0f);
700     glScalef(20.0f, 20.0f, 1.0f);
701     glColor4f(gwc.weak.x, gwc.weak.y, gwc.weak.z, gwc.weak.w);
702     getSSRender().drawText("Wheel drive", PTEXT_HZA_RIGHT | PTEXT_VTA_CENTER);
703     glPopMatrix(); // 1
704 
705     glPushMatrix(); // 1
706     glTranslatef(500.0f, 110.0f, 0.0f);
707     glScalef(20.0f, 20.0f, 1.0f);
708     glColor4f(gwc.weak.x, gwc.weak.y, gwc.weak.z, gwc.weak.w);
709     getSSRender().drawText("Roadholding", PTEXT_HZA_RIGHT | PTEXT_VTA_CENTER);
710     glPopMatrix(); // 1
711 
712     glPushMatrix(); // 1
713     glTranslatef(520.0f, 230.0f, 0.0f);
714     glScalef(30.0f, 30.0f, 1.0f);
715     glColor4f(gwc.strong.x, gwc.strong.y, gwc.strong.z, gwc.strong.w);
716     getSSRender().drawText(std::to_string(static_cast<int>(vtype->mass)), PTEXT_HZA_LEFT | PTEXT_VTA_CENTER);
717     glPopMatrix(); // 1
718 
719     glPushMatrix(); // 1
720     glTranslatef(520.0f, 190.0f, 0.0f);
721     glScalef(30.0f, 30.0f, 1.0f);
722     glColor4f(gwc.strong.x, gwc.strong.y, gwc.strong.z, gwc.strong.w);
723     getSSRender().drawText(vtype->pstat_enginepower, PTEXT_HZA_LEFT | PTEXT_VTA_CENTER);
724     glPopMatrix(); // 1
725 
726     glPushMatrix(); // 1
727     glTranslatef(520.0f, 150.0f, 0.0f);
728     glScalef(30.0f, 30.0f, 1.0f);
729     glColor4f(gwc.strong.x, gwc.strong.y, gwc.strong.z, gwc.strong.w);
730     getSSRender().drawText(vtype->pstat_wheeldrive, PTEXT_HZA_LEFT | PTEXT_VTA_CENTER);
731     glPopMatrix(); // 1
732 
733     glPushMatrix(); // 1
734     glTranslatef(520.0f, 110.0f, 0.0f);
735     glScalef(30.0f, 30.0f, 1.0f);
736     glColor4f(gwc.strong.x, gwc.strong.y, gwc.strong.z, gwc.strong.w);
737     getSSRender().drawText(vtype->pstat_roadholding, PTEXT_HZA_LEFT | PTEXT_VTA_CENTER);
738     glPopMatrix(); // 1
739 
740     std::string racename;
741 
742     if (lss.state == AM_TOP_EVT_PREP || lss.state == AM_TOP_PRAC_SEL_PREP)
743         racename = events[lss.currentevent].name + ": " + events[lss.currentevent].levels[lss.currentlevel].name;
744     else
745     if (lss.state == AM_TOP_LVL_PREP)
746         racename = levels[lss.currentlevel].name;
747 
748     glPushMatrix(); // 1
749     glTranslatef(400.0f, 30.0f, 0.0f);
750     glScalef(20.0f, 20.0f, 1.0f);
751     glColor4f(gwc.weak.x, gwc.weak.y, gwc.weak.z, gwc.weak.w);
752     getSSRender().drawText(racename, PTEXT_HZA_CENTER | PTEXT_VTA_CENTER);
753     glPopMatrix(); // 1
754 
755     glPopMatrix(); // 0
756 
757     glBlendFunc(GL_ONE, GL_ZERO);
758     glEnable(GL_DEPTH_TEST);
759     glEnable(GL_FOG);
760     glEnable(GL_LIGHTING);
761 
762     glMatrixMode(GL_PROJECTION);
763     glPopMatrix();
764     glMatrixMode(GL_MODELVIEW);
765 }
766 
renderStateGame(float eyetranslation)767 void MainApp::renderStateGame(float eyetranslation)
768 {
769     PVehicle *vehic = game->vehicle[0];
770 
771     glClear(GL_DEPTH_BUFFER_BIT);
772     //glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
773 
774     glMatrixMode(GL_PROJECTION);
775     glLoadIdentity();
776 
777     float fnear = 0.1f, fov = 0.6f;
778     float aspect = (float)getWidth() / (float)getHeight();
779     stereoFrustum(-fnear*aspect*fov,fnear*aspect*fov,-fnear*fov,fnear*fov,fnear,100000.0f,
780                   0.8f, eyetranslation);
781     glMatrixMode(GL_MODELVIEW);
782 
783     glColor3f(1.0,1.0,1.0);
784 
785     vec4f fogcolor(game->weather.fog.color, 1.0f);
786     glFogfv(GL_FOG_COLOR, fogcolor);
787 
788     glDepthRange(0.0,0.999);
789 
790     glPushMatrix(); // 0
791 
792     mat44f cammat = camori.getMatrix();
793     mat44f cammat_inv = cammat.transpose();
794 
795     //glTranslatef(0.0,0.0,-40.0);
796     glTranslatef(-eyetranslation, 0.0f, 0.0f);
797 
798     glMultMatrixf(cammat);
799 
800     glTranslatef(-campos.x, -campos.y, -campos.z);
801 
802     float lpos[] = { 0.2, 0.5, 1.0, 0.0 };
803     glLightfv(GL_LIGHT0, GL_POSITION, lpos);
804 
805     glColor3ub(255,255,255);
806 
807     glDisable(GL_LIGHTING);
808 
809     glActiveTextureARB(GL_TEXTURE1_ARB);
810     glEnable(GL_TEXTURE_2D);
811     glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE);
812     glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_ADD_SIGNED);
813     glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_ALPHA,GL_MODULATE);
814     tex_detail->bind();
815     glTexGeni(GL_S,GL_TEXTURE_GEN_MODE,GL_OBJECT_LINEAR);
816     glTexGeni(GL_T,GL_TEXTURE_GEN_MODE,GL_OBJECT_LINEAR);
817     float tgens[] = { 0.05, 0.0, 0.0, 0.0 };
818     float tgent[] = { 0.0, 0.05, 0.0, 0.0 };
819     glTexGenfv(GL_S,GL_OBJECT_PLANE,tgens);
820     glTexGenfv(GL_T,GL_OBJECT_PLANE,tgent);
821     glEnable(GL_TEXTURE_GEN_S);
822     glEnable(GL_TEXTURE_GEN_T);
823     glActiveTextureARB(GL_TEXTURE0_ARB);
824 
825     // draw terrain
826     game->terrain->render(campos, cammat_inv);
827 
828     glDisable(GL_TEXTURE_GEN_S);
829     glDisable(GL_TEXTURE_GEN_T);
830 
831     glActiveTextureARB(GL_TEXTURE1_ARB);
832     glDisable(GL_TEXTURE_2D);
833     glActiveTextureARB(GL_TEXTURE0_ARB);
834 
835     if (renderowncar)
836     {
837         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
838 
839         tex_shadow->bind();
840 
841         glColor4f(1.0f, 1.0f, 1.0f, 0.7f);
842 
843         vec3f vpos = game->vehicle[0]->body->pos;
844         vec3f forw = makevec3f(game->vehicle[0]->body->getOrientationMatrix().row[0]);
845         float forwangle = atan2(forw.y, forw.x);
846         game->terrain->drawSplat(vpos.x, vpos.y, 1.4f, forwangle + PI*0.5f);
847 
848         glBlendFunc(GL_ONE, GL_ZERO);
849     }
850 
851     renderSky(cammat);
852 
853     glEnable(GL_LIGHTING);
854 
855     for (unsigned int v=0; v<game->vehicle.size(); ++v)
856     {
857 
858         if (!renderowncar && v == 0) continue;
859 
860         PVehicle *vehic = game->vehicle[v];
861         for (unsigned int i=0; i<vehic->part.size(); ++i)
862         {
863             if (vehic->type->part[i].model)
864             {
865                 glPushMatrix(); // 1
866 
867                 vec3f vpos = vehic->part[i].ref_world.pos;
868                 glTranslatef(vpos.x, vpos.y, vpos.z);
869 
870                 mat44f vorim = vehic->part[i].ref_world.ori_mat_inv;
871                 glMultMatrixf(vorim);
872 
873                 float scale = vehic->type->part[i].scale;
874                 glScalef(scale,scale,scale);
875 
876                 drawModel(*vehic->type->part[i].model);
877 
878                 glPopMatrix(); // 1
879             }
880 
881             if (vehic->type->wheelmodel)
882             {
883                 for (unsigned int j=0; j<vehic->type->part[i].wheel.size(); j++)
884                 {
885 
886                     glPushMatrix(); // 1
887 
888                     vec3f wpos = vehic->part[i].wheel[j].ref_world.getPosition();
889                     glTranslatef(wpos.x,wpos.y,wpos.z);
890 
891                     mat44f worim = vehic->part[i].wheel[j].ref_world.ori_mat_inv;
892                     glMultMatrixf(worim);
893 
894                     float scale = vehic->type->wheelscale * vehic->type->part[i].wheel[j].radius;
895                     glScalef(scale,scale,scale);
896 
897                     drawModel(*vehic->type->wheelmodel);
898 
899                     glPopMatrix(); // 1
900                 }
901             }
902         }
903     }
904 
905     glDisable(GL_LIGHTING);
906 
907     glDepthMask(GL_FALSE);
908     glDisable(GL_CULL_FACE);
909 
910     glDisable(GL_TEXTURE_2D);
911 
912     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
913 
914 #define RAINDROP_WIDTH          0.015
915     const vec4f raindrop_col(0.5,0.5,0.5,0.4);
916 
917     vec3f offsetdrops = campos - campos_prev;
918 
919     for (unsigned int i = 0; i < rain.size(); i++)
920     {
921         vec3f tempv;
922         const float prevlife = rain[i].prevlife;
923         vec3f pt1 = rain[i].drop_pt + rain[i].drop_vect * prevlife + offsetdrops;
924         vec3f pt2 = rain[i].drop_pt + rain[i].drop_vect * rain[i].life;
925         vec3f zag = campos - rain[i].drop_pt;
926         zag = zag.cross(rain[i].drop_vect);
927         zag *= RAINDROP_WIDTH / zag.length();
928         glBegin(GL_TRIANGLE_STRIP);
929         glColor4f(raindrop_col[0],raindrop_col[1],raindrop_col[2],0.0);
930         tempv = pt1 - zag;
931         glVertex3fv(tempv);
932         tempv = pt2 - zag;
933         glVertex3fv(tempv);
934 
935         glColor4fv(raindrop_col);
936         glVertex3fv(pt1);
937         glVertex3fv(pt2);
938 
939         glColor4f(raindrop_col[0],raindrop_col[1],raindrop_col[2],0.0);
940         tempv = pt1 + zag;
941         glVertex3fv(tempv);
942         tempv = pt2 + zag;
943         glVertex3fv(tempv);
944         glEnd();
945     }
946 
947 #define SNOWFLAKE_POINT_SIZE        3.0f
948 #define SNOWFLAKE_BOX_SIZE          0.175f
949 
950 // NOTE: must be greater than 1.0f
951 #define SNOWFLAKE_MAXLIFE           4.5f
952 
953     GLfloat ops; // Original Point Size, for to be restored
954 
955     if (cfg_snowflaketype == SnowFlakeType::point)
956     {
957         glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
958         glGetFloatv(GL_POINT_SIZE, &ops);
959         glPointSize(SNOWFLAKE_POINT_SIZE);
960     }
961     else
962     if (cfg_snowflaketype == SnowFlakeType::textured)
963     {
964         glEnable(GL_TEXTURE_2D);
965         glBlendFunc(GL_SRC_COLOR, GL_ONE);
966         tex_snowflake->bind();
967     }
968 
969     for (const SnowFlake &sf: snowfall)
970     {
971         const vec3f pt = sf.drop_pt + sf.drop_vect * sf.life;
972         GLfloat alpha;
973 
974         if (sf.life > SNOWFLAKE_MAXLIFE)
975         {
976             alpha = 0.0f;
977         }
978         else
979         if (sf.life > 1.0f)
980         {
981 #define ML      SNOWFLAKE_MAXLIFE
982             // this equation ensures that snowflaks fade in
983             alpha = (sf.life - ML) / (1 - ML);
984 #undef ML
985         }
986         else
987             alpha = 1.0f;
988 
989         if (cfg_snowflaketype == SnowFlakeType::point)
990         {
991             glBegin(GL_POINTS);
992             glColor4f(1.0f, 1.0f, 1.0f, alpha);
993             glVertex3fv(pt);
994             glEnd();
995         }
996         else
997         {
998 #define SBS     SNOWFLAKE_BOX_SIZE
999             vec3f zag = campos - sf.drop_pt;
1000 
1001             zag = zag.cross(sf.drop_vect);
1002             zag.normalize();
1003             zag *= SBS;
1004 
1005             if (cfg_snowflaketype == SnowFlakeType::square)
1006             {
1007                 glBegin(GL_TRIANGLE_STRIP);
1008                 glColor4f(1.0f, 1.0f, 1.0f, alpha);
1009                 glVertex3f(pt.x,            pt.y,           pt.z                );
1010                 glVertex3f(pt.x,            pt.y,           pt.z + zag.z + SBS  );
1011                 glVertex3f(pt.x + zag.x,    pt.y + zag.y,   pt.z                );
1012                 glVertex3f(pt.x + zag.x,    pt.y + zag.y,   pt.z + zag.z + SBS  );
1013                 glEnd();
1014             }
1015             else // cfg_snowflaketype == SnowFlakeType::textured
1016             {
1017                 glBegin(GL_TRIANGLE_STRIP);
1018                 glColor4f(1.0f, 1.0f, 1.0f, alpha);
1019                 glTexCoord2f(1.0f, 1.0f);
1020                 glVertex3f(pt.x,            pt.y,           pt.z                );
1021                 glTexCoord2f(0.0f, 1.0f);
1022                 glVertex3f(pt.x,            pt.y,           pt.z + zag.z + SBS  );
1023                 glTexCoord2f(1.0f, 0.0f);
1024                 glVertex3f(pt.x + zag.x,    pt.y + zag.y,   pt.z                );
1025                 glTexCoord2f(0.0f, 0.0f);
1026                 glVertex3f(pt.x + zag.x,    pt.y + zag.y,   pt.z + zag.z + SBS  );
1027                 glEnd();
1028             }
1029 #undef SBS
1030         }
1031     }
1032 
1033     if (cfg_snowflaketype == SnowFlakeType::point)
1034         glPointSize(ops); // restore original point size
1035 
1036     // disable textures
1037     if (cfg_snowflaketype == SnowFlakeType::textured)
1038     {
1039         glDisable(GL_TEXTURE_2D);
1040         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1041     }
1042 
1043     const vec4f checkpoint_col[3] =
1044     {
1045         vec4f(1.0f, 0.0f, 0.0f, 0.8f),  // 0 = next checkpoint
1046         vec4f(0.7f, 0.7f, 0.1f, 0.6f),  // 1 = checkpoint after next
1047         vec4f(0.2f, 0.8f, 0.2f, 0.4f)  // 2 = all other checkpoints
1048     };
1049 
1050     if (showcheckpoint)
1051     {
1052         for (unsigned int i=0; i<game->checkpt.size(); i++)
1053         {
1054             vec4f colr = checkpoint_col[2];
1055 
1056             if ((int)i == vehic->nextcp)
1057                 colr = checkpoint_col[0];
1058             else if ((int)i == (vehic->nextcp + 1) % (int)game->checkpt.size())
1059                 colr = checkpoint_col[1];
1060 
1061             glPushMatrix(); // 1
1062             glTranslatef(game->checkpt[i].pt.x, game->checkpt[i].pt.y, game->checkpt[i].pt.z);
1063             glScalef(25.0f, 25.0f, 1.0f);
1064 
1065 #if 0 // Checkpoint style one
1066             glBegin(GL_TRIANGLE_STRIP);
1067 
1068             for (float a = 0.0f; a < 0.99f; a += 0.05f)
1069             {
1070                 glColor4f(colr[0], colr[1], colr[2], colr[3] * a);
1071                 float ang = cprotate + a * 6.0f;
1072                 float ht = sinf(ang * 1.7f) * 7.0f + 8.0f;
1073                 glVertex3f(cosf(ang), sinf(ang), ht - 1.0f);
1074                 glVertex3f(cosf(ang), sinf(ang), ht + 1.0f);
1075             }
1076 
1077             for (float a = 1.0f; a < 2.01f; a += 0.05f)
1078             {
1079                 glColor4f(colr[0], colr[1], colr[2], colr[3] * (2.0f - a));
1080                 float ang = cprotate + a * 6.0f;
1081                 float ht = sinf(ang * 1.7f) * 7.0f + 8.0f;
1082                 glVertex3f(cosf(ang), sinf(ang), ht - 1.0f);
1083                 glVertex3f(cosf(ang), sinf(ang), ht + 1.0f);
1084             }
1085 
1086             glEnd();
1087 #else // Regular checkpoint style
1088             glBegin(GL_TRIANGLE_STRIP);
1089             float ht = sinf(cprotate * 6.0f) * 7.0f + 8.0f;
1090             glColor4f(colr[0], colr[1], colr[2], 0.0f);
1091             glVertex3f(1.0f, 0.0f, ht - 1.0f);
1092             glColor4f(colr[0], colr[1], colr[2], colr[3]);
1093             glVertex3f(1.0f, 0.0f, ht + 0.0f);
1094             for (float a = PI/10.0f; a < PI*2.0f-0.01f; a += PI/10.0f)
1095             {
1096                 glColor4f(colr[0], colr[1], colr[2], 0.0f);
1097                 glVertex3f(cosf(a), sinf(a), ht - 1.0f);
1098                 glColor4f(colr[0], colr[1], colr[2], colr[3]);
1099                 glVertex3f(cosf(a), sinf(a), ht + 0.0f);
1100             }
1101             glColor4f(colr[0], colr[1], colr[2], 0.0f);
1102             glVertex3f(1.0f, 0.0f, ht - 1.0f);
1103             glColor4f(colr[0], colr[1], colr[2], colr[3]);
1104             glVertex3f(1.0f, 0.0f, ht + 0.0f);
1105             glEnd();
1106 
1107             glBegin(GL_TRIANGLE_STRIP);
1108             glColor4f(colr[0], colr[1], colr[2], colr[3]);
1109             glVertex3f(1.0f, 0.0f, ht - 0.0f);
1110             glColor4f(colr[0], colr[1], colr[2], 0.0f);
1111             glVertex3f(1.0f, 0.0f, ht + 1.0f);
1112             for (float a = PI/10.0f; a < PI*2.0f-0.01f; a += PI/10.0f)
1113             {
1114                 glColor4f(colr[0], colr[1], colr[2], colr[3]);
1115                 glVertex3f(cosf(a), sinf(a), ht - 0.0f);
1116                 glColor4f(colr[0], colr[1], colr[2], 0.0f);
1117                 glVertex3f(cosf(a), sinf(a), ht + 1.0f);
1118             }
1119             glColor4f(colr[0], colr[1], colr[2], colr[3]);
1120             glVertex3f(1.0f, 0.0f, ht - 0.0f);
1121             glColor4f(colr[0], colr[1], colr[2], 0.0f);
1122             glVertex3f(1.0f, 0.0f, ht + 1.0f);
1123             glEnd();
1124 #endif
1125             glPopMatrix(); // 1
1126         }
1127 
1128 // codriver checkpoints rendering
1129 #ifdef INDEVEL
1130 
1131     // codriver checkpoints for debugging purposes
1132     const vec4f cdcheckpoint_col[3] =
1133     {
1134         {0.0f, 0.0f, 1.0f, 0.8f},       // 0 = next checkpoint
1135         {0.3f, 0.3f, 1.0f, 0.6f},       // 1 = checkpoint after next
1136         {0.6f, 0.6f, 1.0f, 0.4f}        // 2 = all other checkpoints
1137     };
1138 
1139         for (unsigned int i=0; i<game->codrivercheckpt.size(); i++)
1140         {
1141             vec4f colr = cdcheckpoint_col[2];
1142 
1143             if (game->cdcheckpt_ordered)
1144             {
1145                 if ((int)i == vehic->nextcdcp)
1146                     colr = cdcheckpoint_col[0];
1147                 else if ((int)i == (vehic->nextcdcp + 1) % (int)game->codrivercheckpt.size())
1148                     colr = cdcheckpoint_col[1];
1149             }
1150             else
1151                 colr = cdcheckpoint_col[1];
1152 
1153             glPushMatrix(); // 1
1154             glTranslatef(game->codrivercheckpt[i].pt.x, game->codrivercheckpt[i].pt.y, game->codrivercheckpt[i].pt.z);
1155             glScalef(15.0f, 15.0f, 1.0f);
1156 
1157             glBegin(GL_TRIANGLE_STRIP);
1158             float ht = sinf(cprotate * 6.0f) * 7.0f + 8.0f;
1159             glColor4f(colr[0], colr[1], colr[2], 0.0f);
1160             glVertex3f(1.0f, 0.0f, ht - 1.0f);
1161             glColor4f(colr[0], colr[1], colr[2], colr[3]);
1162             glVertex3f(1.0f, 0.0f, ht + 0.0f);
1163             for (float a = PI/10.0f; a < PI*2.0f-0.01f; a += PI/10.0f)
1164             {
1165                 glColor4f(colr[0], colr[1], colr[2], 0.0f);
1166                 glVertex3f(cosf(a), sinf(a), ht - 1.0f);
1167                 glColor4f(colr[0], colr[1], colr[2], colr[3]);
1168                 glVertex3f(cosf(a), sinf(a), ht + 0.0f);
1169             }
1170             glColor4f(colr[0], colr[1], colr[2], 0.0f);
1171             glVertex3f(1.0f, 0.0f, ht - 1.0f);
1172             glColor4f(colr[0], colr[1], colr[2], colr[3]);
1173             glVertex3f(1.0f, 0.0f, ht + 0.0f);
1174             glEnd();
1175 
1176             glBegin(GL_TRIANGLE_STRIP);
1177             glColor4f(colr[0], colr[1], colr[2], colr[3]);
1178             glVertex3f(1.0f, 0.0f, ht - 0.0f);
1179             glColor4f(colr[0], colr[1], colr[2], 0.0f);
1180             glVertex3f(1.0f, 0.0f, ht + 1.0f);
1181             for (float a = PI/10.0f; a < PI*2.0f-0.01f; a += PI/10.0f)
1182             {
1183                 glColor4f(colr[0], colr[1], colr[2], colr[3]);
1184                 glVertex3f(cosf(a), sinf(a), ht - 0.0f);
1185                 glColor4f(colr[0], colr[1], colr[2], 0.0f);
1186                 glVertex3f(cosf(a), sinf(a), ht + 1.0f);
1187             }
1188             glColor4f(colr[0], colr[1], colr[2], colr[3]);
1189             glVertex3f(1.0f, 0.0f, ht - 0.0f);
1190             glColor4f(colr[0], colr[1], colr[2], 0.0f);
1191             glVertex3f(1.0f, 0.0f, ht + 1.0f);
1192             glEnd();
1193             glPopMatrix(); // 1
1194         }
1195 #endif
1196     }
1197 
1198     glEnable(GL_TEXTURE_2D);
1199 
1200     if (game->water.enabled)
1201         renderWater();
1202 
1203     if (psys_dirt != nullptr) // cfg_dirteffect == false
1204         getSSRender().render(psys_dirt);
1205 
1206     glDepthMask(GL_TRUE);
1207     glBlendFunc(GL_ONE,GL_ZERO);
1208     glEnable(GL_LIGHTING);
1209     glEnable(GL_CULL_FACE);
1210     glEnable(GL_FOG);
1211 
1212     glDisable(GL_LIGHTING);
1213 
1214     glPopMatrix(); // 0
1215 
1216     glDisable(GL_DEPTH_TEST);
1217 
1218     glMatrixMode(GL_PROJECTION);
1219     glPushMatrix();
1220     glLoadIdentity();
1221 
1222     glOrtho(0 - hratio, hratio, 0 - vratio, vratio, 0 - 1.0, 1.0);
1223     glMatrixMode(GL_MODELVIEW);
1224 
1225     glPushMatrix(); // 0
1226 
1227     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1228 
1229     if (showui)
1230     {
1231         game->renderCodriverSigns();
1232 
1233       glPushMatrix(); // 1
1234       // position of rpm dial and needle
1235       //glTranslatef( hratio * (1.f - (5.75f/50.f)) - 0.3f, -vratio * (40.f/50.f) + 0.22f, 0.0f);
1236       glTranslatef( hratio * (1.f - (2.5f/50.f)) - 0.3f, -vratio * (43.5f/50.f) + 0.22f, 0.0f);
1237       glScalef(0.30f, 0.30f, 1.0f);
1238 
1239       tex_hud_revs->bind();
1240       glColor3f(1.0f, 1.0f, 1.0f);
1241       glBegin(GL_QUADS);
1242       glTexCoord2f(1.0f,1.0f);
1243       glVertex2f(1.0f,1.0f);
1244       glTexCoord2f(0.0f,1.0f);
1245       glVertex2f(-1.0f,1.0f);
1246       glTexCoord2f(0.0f,0.0f);
1247       glVertex2f(-1.0f,-1.0f);
1248       glTexCoord2f(1.0f,0.0f);
1249       glVertex2f(1.0f,-1.0f);
1250       glEnd();
1251 
1252       // draw the needle of the RPM dial
1253       glRotatef(225.0f - vehic->getEngineRPM() * 15.0f / 1000.0f, 0.0f, 0.0f, 1.0f);
1254       tex_hud_revneedle->bind();
1255       glColor3f(1.0f, 1.0f, 1.0f);
1256       glPushMatrix(); // 2
1257       glTranslatef(0.62f, 0.0f, 0.0f);
1258       glScalef(0.16f, 0.16f, 0.16f);
1259       glBegin(GL_QUADS);
1260       glTexCoord2f(1.0f,1.0f);
1261       glVertex2f(1.0f,1.0f);
1262       glTexCoord2f(0.0f,1.0f);
1263       glVertex2f(-1.0f,1.0f);
1264       glTexCoord2f(0.0f,0.0f);
1265       glVertex2f(-1.0f,-1.0f);
1266       glTexCoord2f(1.0f,0.0f);
1267       glVertex2f(1.0f,-1.0f);
1268       glEnd();
1269       glPopMatrix(); // 2
1270       glDisable(GL_TEXTURE_2D);
1271       glPopMatrix(); // 1
1272     }
1273 
1274     // checkpoint pointing arrow thing
1275 #if 0
1276     glPushMatrix(); // 1
1277 
1278     glTranslatef(0.0f, 0.8f, 0.0f);
1279 
1280     glScalef(0.2f, 0.2f, 0.2f);
1281 
1282     glRotatef(-30.0f, 1.0f, 0.0f, 0.0f);
1283     glRotatef(DEGREES(nextcpangle), 0.0f, -1.0f, 0.0f);
1284 
1285     glBegin(GL_TRIANGLES);
1286     glColor4f(0.8f, 0.4f, 0.4f, 0.6f);
1287     glVertex3f(0.0f, 0.0f, -2.0f);
1288     glColor4f(0.8f, 0.8f, 0.8f, 0.6f);
1289     glVertex3f(1.0f, 0.0f, 1.0f);
1290     glVertex3f(-1.0f, 0.0f, 1.0f);
1291     glEnd();
1292     glBegin(GL_TRIANGLE_STRIP);
1293     glColor4f(0.8f, 0.4f, 0.4f, 0.6f);
1294     glVertex3f(0.0f, 0.0f, -2.0f);
1295     glColor4f(1.0f, 0.5f, 0.5f, 0.6f);
1296     glVertex3f(0.0f, 0.2f, -2.0f);
1297     glColor4f(0.8f, 0.8f, 0.8f, 0.6f);
1298     glVertex3f(1.0f, 0.0f, 1.0f);
1299     glColor4f(1.0f, 1.0f, 1.0f, 0.6f);
1300     glVertex3f(1.0f, 0.2f, 1.0f);
1301     glColor4f(0.8f, 0.8f, 0.8f, 0.6f);
1302     glVertex3f(-1.0f, 0.0f, 1.0f);
1303     glColor4f(1.0f, 1.0f, 1.0f, 0.6f);
1304     glVertex3f(-1.0f, 0.2f, 1.0f);
1305     glColor4f(0.8f, 0.4f, 0.4f, 0.6f);
1306     glVertex3f(0.0f, 0.0f, -2.0f);
1307     glColor4f(1.0f, 0.5f, 0.5f, 0.6f);
1308     glVertex3f(0.0f, 0.2f, -2.0f);
1309     glEnd();
1310 
1311     glPopMatrix(); // 1
1312 #endif
1313 
1314     if (showmap)
1315     {
1316         // position and size of map
1317         //glViewport(getWidth() * (5.75f/100.f), getHeight() * (6.15f/100.f), getHeight()/3.5f, getHeight()/3.5f);
1318         glViewport(getWidth() * (2.5f/100.f), getHeight() * (2.5f/100.f), getHeight()/3.5f, getHeight()/3.5f);
1319 
1320         glPushMatrix(); // 1
1321         glScalef(hratio, vratio, 1.0f);
1322 
1323         if (game->terrain->getHUDMapTexture())
1324         {
1325             glEnable(GL_TEXTURE_2D);
1326             game->terrain->getHUDMapTexture()->bind();
1327         }
1328 
1329         glMatrixMode(GL_TEXTURE);
1330         glPushMatrix();
1331         float scalefac = 1.0f / game->terrain->getMapSize();
1332         glScalef(scalefac, scalefac, 1.0f);
1333         glTranslatef(campos.x, campos.y, 0.0f);
1334         glRotatef(DEGREES(camera_angle), 0.0f, 0.0f, 1.0f);
1335         glScalef(1.0f / 0.003f, 1.0f / 0.003f, 1.0f);
1336 
1337         glBegin(GL_QUADS);
1338         glColor4f(1.0f, 1.0f, 1.0f, 0.7f);
1339         glTexCoord2f(1.0f, 1.0f);
1340         glVertex2f(1.0f, 1.0f);
1341         glTexCoord2f(-1.0f, 1.0f);
1342         glVertex2f(-1.0f, 1.0f);
1343         glTexCoord2f(-1.0f, -1.0f);
1344         glVertex2f(-1.0f, -1.0f);
1345         glTexCoord2f(1.0f, -1.0f);
1346         glVertex2f(1.0f, -1.0f);
1347         glEnd();
1348 
1349         glPopMatrix();
1350         glMatrixMode(GL_MODELVIEW);
1351 
1352         glDisable(GL_TEXTURE_2D);
1353 
1354         glPushMatrix(); // 2
1355         glScalef(0.003f, 0.003f, 1.0f);
1356         glRotatef(DEGREES(-camera_angle), 0.0f, 0.0f, 1.0f);
1357         glTranslatef(-campos.x, -campos.y, 0.0f);
1358         for (unsigned int i=0; i<game->checkpt.size(); i++)
1359         {
1360             glPushMatrix();
1361             vec3f vpos = game->checkpt[i].pt;
1362             glTranslatef(vpos.x, vpos.y, 0.0f);
1363             glRotatef(DEGREES(camera_angle), 0.0f, 0.0f, 1.0f);
1364             glScalef(30.0f, 30.0f, 1.0f);
1365             vec4f colr = checkpoint_col[2];
1366             if ((int)i == vehic->nextcp)
1367             {
1368                 float sc = 1.5f + sinf(cprotate * 10.0f) * 0.5f;
1369                 glScalef(sc, sc, 1.0f);
1370                 colr = checkpoint_col[0];
1371             }
1372             else if ((int)i == (vehic->nextcp + 1) % (int)game->checkpt.size())
1373             {
1374                 colr = checkpoint_col[1];
1375             }
1376             glBegin(GL_TRIANGLE_FAN);
1377             glColor4fv(colr);
1378             glVertex2f(0.0f, 0.0f);
1379             glColor4f(colr[0], colr[1], colr[2], 0.0f);
1380             //glColor4f(1.0f, 1.0f, 1.0f, 0.0f);
1381             glVertex2f(1.0f, 0.0f);
1382             glVertex2f(0.0f, 1.0f);
1383             glVertex2f(-1.0f, 0.0f);
1384             glVertex2f(0.0f, -1.0f);
1385             glVertex2f(1.0f, 0.0f);
1386             glEnd();
1387             glPopMatrix();
1388         }
1389         for (unsigned int i=0; i<game->vehicle.size(); i++)
1390         {
1391             glPushMatrix();
1392             vec3f vpos = game->vehicle[i]->body->getPosition();
1393             glTranslatef(vpos.x, vpos.y, 0.0f);
1394             glRotatef(DEGREES(camera_angle), 0.0f, 0.0f, 1.0f);
1395             glScalef(30.0f, 30.0f, 1.0f);
1396             glBegin(GL_TRIANGLE_FAN);
1397             glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1398             glVertex2f(0.0f, 0.0f);
1399             glColor4f(1.0f, 1.0f, 1.0f, 0.0f);
1400             glVertex2f(1.0f, 0.0f);
1401             glVertex2f(0.0f, 1.0f);
1402             glVertex2f(-1.0f, 0.0f);
1403             glVertex2f(0.0f, -1.0f);
1404             glVertex2f(1.0f, 0.0f);
1405             glEnd();
1406             glPopMatrix();
1407         }
1408         glPopMatrix(); // 2
1409 
1410         glPopMatrix(); // 1
1411 
1412         glViewport(0, 0, getWidth(), getHeight());
1413     }
1414 
1415     glEnable(GL_TEXTURE_2D);
1416 
1417     if (showui)
1418     {
1419 
1420       glPushMatrix(); // 1
1421 
1422       /*
1423       tex_hud_gear->bind();
1424       glPushMatrix(); // 2
1425 
1426       glTranslatef(1.0f, 0.35f, 0.0f);
1427       glScalef(0.2f, 0.2f, 1.0f);
1428       glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1429       glBegin(GL_QUADS);
1430       glTexCoord2f(1.0f,1.0f); glVertex2f(1.0f,1.0f);
1431       glTexCoord2f(0.0f,1.0f); glVertex2f(-1.0f,1.0f);
1432       glTexCoord2f(0.0f,0.0f); glVertex2f(-1.0f,-1.0f);
1433       glTexCoord2f(1.0f,0.0f); glVertex2f(1.0f,-1.0f);
1434       glEnd();
1435 
1436       glPopMatrix(); // 2
1437       */
1438 
1439       tex_fontSourceCodeOutlined->bind();
1440 
1441       // time counter
1442 
1443       glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1444       glPushMatrix(); // 2
1445 
1446       // time position (other time strings inherit this position)
1447       // -hratio is left border, 0 is center, +hratio is right
1448       // hratio * (1/50) gives 1% of the entire width
1449       // +vratio is top border, 0 is middle, -vratio is bottom
1450 
1451       glTranslatef( -hratio + hratio * (2.5f/50.f), vratio - vratio * (5.5f/50.f), 0.0f);
1452       glScalef(0.125f, 0.125f, 1.0f);
1453 
1454       if (game->gamestate == Gamestate::finished)
1455       {
1456           getSSRender().drawText(
1457               PUtil::formatTime(game->coursetime),
1458               PTEXT_HZA_LEFT | PTEXT_VTA_TOP);
1459       }
1460       else if (game->coursetime < game->cptime + 1.50f)
1461       {
1462           getSSRender().drawText(
1463               PUtil::formatTime(game->cptime),
1464               PTEXT_HZA_LEFT | PTEXT_VTA_TOP);
1465       }
1466       else if (game->coursetime < game->cptime + 3.50f)
1467       {
1468           float a = (((game->cptime + 3.50f) - game->coursetime) / 2);
1469           glColor4f(1.0f, 1.0f, 1.0f, a);
1470           getSSRender().drawText(
1471               PUtil::formatTime(game->cptime),
1472               PTEXT_HZA_LEFT | PTEXT_VTA_TOP);
1473       }
1474       else
1475       {
1476           getSSRender().drawText(
1477               PUtil::formatTime(game->coursetime),
1478               PTEXT_HZA_LEFT | PTEXT_VTA_TOP);
1479       }
1480 
1481       // show target time
1482 
1483       glColor4f(0.5f, 1.0f, 0.5f, 1.0f);
1484       glPushMatrix(); // 2
1485       glTranslatef(0.0f, -0.8f, 0.0f);
1486       getSSRender().drawText(PUtil::formatTime(game->targettime), PTEXT_HZA_LEFT | PTEXT_VTA_TOP);
1487 
1488     {
1489         // show the time penalty if there is any
1490         const float timepen = game->uservehicle->offroadtime_total * game->offroadtime_penalty_multiplier;
1491 
1492         // FIXME: why do glPushMatrix() and glPopMatrix() not work for me?
1493         if (timepen >= 0.1f)
1494         {
1495             glColor4f(1.0f, 1.0f, 0.5f, 1.0f);
1496             glTranslatef(0.0f, -1.60f, 0.0f);
1497             getSSRender().drawText(PUtil::formatTime(timepen) + '+', PTEXT_HZA_LEFT | PTEXT_VTA_TOP);
1498             glTranslatef(0.0f, +1.60f, 0.0f);
1499         }
1500     }
1501 
1502       // time label
1503 
1504       glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1505       glTranslatef(0.0f, .52f, 0.0f);
1506       glScalef(0.65f, 0.65f, 1.0f);
1507       getSSRender().drawText("TIME", PTEXT_HZA_LEFT | PTEXT_VTA_TOP);
1508 
1509       glPopMatrix(); // 2
1510 
1511       // show Next/Total checkpoints
1512       {
1513 
1514           // checkpoint counter
1515 
1516           glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1517           glPushMatrix(); // 2
1518           const std::string totalcp = std::to_string(game->checkpt.size());
1519           const std::string nextcp = std::to_string(vehic->nextcp);
1520 
1521           // checkpoint position
1522           glTranslatef( hratio - hratio * (2.5f/50.f), vratio - vratio * (5.5f/50.f), 0.0f);
1523           glScalef(0.125f, 0.125f, 1.0f);
1524 
1525             if (game->getFinishState() != Gamefinish::not_finished)
1526                 getSSRender().drawText(totalcp + '/' + totalcp, PTEXT_HZA_RIGHT | PTEXT_VTA_TOP);
1527             else
1528                 getSSRender().drawText(nextcp + '/' + totalcp, PTEXT_HZA_RIGHT | PTEXT_VTA_TOP);
1529 
1530           // checkpoint label
1531 
1532           //glPushMatrix(); // 3
1533           glTranslatef(0, 0.52f, 0.0f);
1534           glScalef(0.65f, 0.65f, 1.0f);
1535           getSSRender().drawText("CKPT", PTEXT_HZA_RIGHT | PTEXT_VTA_TOP);
1536 
1537           //glPopMatrix(); // 3
1538           glPopMatrix(); // 2
1539       }
1540 
1541         // show Current/Total laps
1542         if (game->number_of_laps > 1)
1543         {
1544             const std::string currentlap = std::to_string(vehic->currentlap);
1545             const std::string number_of_laps = std::to_string(game->number_of_laps);
1546 
1547             glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1548             glPushMatrix(); // 2
1549             glTranslatef( hratio - hratio * (2.5f/50.f), vratio - vratio * (5.5f/50.f) - 0.20f, 0.0f);
1550             glScalef(0.125f, 0.125f, 1.0f);
1551 
1552             if (game->getFinishState() != Gamefinish::not_finished)
1553                 getSSRender().drawText(number_of_laps + '/' + number_of_laps, PTEXT_HZA_RIGHT | PTEXT_VTA_TOP);
1554             else
1555                 getSSRender().drawText(currentlap + '/' + number_of_laps, PTEXT_HZA_RIGHT | PTEXT_VTA_TOP);
1556 
1557             glTranslatef(0, 0.52f, 0.0f);
1558             glScalef(0.65f, 0.65f, 1.0f);
1559             getSSRender().drawText("LAP", PTEXT_HZA_RIGHT | PTEXT_VTA_TOP);
1560 
1561             glPopMatrix(); // 2
1562         }
1563 
1564 #ifdef INDEVEL
1565         // show codriver checkpoint text (the pace notes)
1566         if (!game->codrivercheckpt.empty() && vehic->nextcdcp != 0)
1567         {
1568             glColor3f(1.0f, 1.0f, 0.0f);
1569             glPushMatrix();
1570             glTranslatef(0.0f, 0.3f, 0.0f);
1571             glScalef(0.1f, 0.1f, 1.0f);
1572             getSSRender().drawText(game->codrivercheckpt[vehic->nextcdcp - 1].notes, PTEXT_HZA_CENTER | PTEXT_VTA_CENTER);
1573             glPopMatrix();
1574         }
1575 #endif
1576 
1577         glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1578 
1579       tex_fontSourceCodeBold->bind();
1580 
1581       // show current gear and speed
1582       {
1583           // gear number
1584           const int gear = vehic->getCurrentGear();
1585           const std::string buff = (gear >= 0) ? PUtil::formatInt(gear + 1, 1) : "R";
1586 
1587           glPushMatrix(); // 2
1588           // position of gear & speed number & label
1589           //glTranslatef( hratio * (1.f - (5.75f/50.f)) - 0.3f, -vratio * (40.f/50.f) + 0.21f, 0.0f);
1590           glTranslatef( hratio * (1.f - (2.5f/50.f)) - 0.3f, -vratio * (43.5f/50.f) + 0.21f, 0.0f);
1591           glScalef(0.20f, 0.20f, 1.0f);
1592           getSSRender().drawText(buff, PTEXT_HZA_CENTER | PTEXT_VTA_CENTER);
1593 
1594           // speed number
1595           const int speed = std::fabs(vehic->getWheelSpeed()) * hud_speedo_mps_speed_mult;
1596           std::string speedstr = std::to_string(speed);
1597 
1598           //glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1599           glTranslatef(1.1f, -0.625f, 0.0f);
1600           glScalef(0.5f, 0.5f, 1.0f);
1601           getSSRender().drawText(speedstr, PTEXT_HZA_RIGHT | PTEXT_VTA_CENTER);
1602 
1603           // speed label
1604           glTranslatef(0.0f, -0.82f, 0.0f);
1605           glScalef(0.5f, 0.5f, 1.0f);
1606 
1607           if (cfg_speed_unit == MainApp::Speedunit::mph)
1608               getSSRender().drawText("MPH", PTEXT_HZA_RIGHT | PTEXT_VTA_CENTER);
1609           else
1610               getSSRender().drawText("km/h", PTEXT_HZA_RIGHT | PTEXT_VTA_CENTER);
1611 
1612           glPopMatrix(); // 2
1613       }
1614 
1615   #ifndef NDEBUG
1616       // draw revs for debugging
1617       glPushMatrix(); // 2
1618       glTranslatef(1.17f, 0.52f, 0.0f);
1619       glScalef(0.2f, 0.2f, 1.0f);
1620       getSSRender().drawText(std::to_string(vehic->getEngineRPM()), PTEXT_HZA_RIGHT | PTEXT_VTA_TOP);
1621       glPopMatrix(); // 2
1622   #endif
1623 
1624 #ifndef NDEBUG
1625     // draw real time penalty for debugging
1626     glPushMatrix();
1627     glScalef(0.1f, 0.1f, 1.0f);
1628     glTranslatef(0.0f, -4.0f, 0.0f);
1629     glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1630     tex_fontSourceCodeOutlined->bind();
1631     getSSRender().drawText(std::string("true time penalty: ") +
1632         std::to_string(game->offroadtime_total * game->offroadtime_penalty_multiplier),
1633         PTEXT_HZA_CENTER | PTEXT_VTA_TOP);
1634     glPopMatrix();
1635 #endif
1636 
1637     tex_fontSourceCodeShadowed->bind();
1638 
1639     // draw "off road" warning sign and text
1640     if (game->isRacing())
1641     {
1642         //const vec3f bodypos = vehic->part[0].ref_world.getPosition();
1643         const vec3f bodypos = vehic->body->getPosition();
1644 
1645         if (!game->terrain->getRmapOnRoad(bodypos))
1646         {
1647             glPushMatrix();
1648             glLoadIdentity();
1649             glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1650             glScalef(0.25f, 0.25f, 1.0f);
1651             tex_hud_offroad->bind();
1652             glBegin(GL_QUADS);
1653                 glTexCoord2f(   1.0f,   1.0f);
1654                 glVertex2f(     1.0f,   1.0f);
1655                 glTexCoord2f(   0.0f,   1.0f);
1656                 glVertex2f(    -1.0f,   1.0f);
1657                 glTexCoord2f(   0.0f,   0.0f);
1658                 glVertex2f(    -1.0f,  -1.0f);
1659                 glTexCoord2f(   1.0f,   0.0f);
1660                 glVertex2f(     1.0f,  -1.0f);
1661             glEnd();
1662             glPopMatrix();
1663             glPushMatrix();
1664             glScalef(0.1f, 0.1f, 1.0f);
1665             glTranslatef(0.0f, -2.5f, 0.0f);
1666             glColor4f(1.0f, 1.0f, 0.0f, 1.0f);
1667             tex_fontSourceCodeOutlined->bind();
1668             getSSRender().drawText(
1669                 std::to_string(static_cast<int> (game->getOffroadTime() * game->offroadtime_penalty_multiplier)) +
1670                 " seconds",
1671                 PTEXT_HZA_CENTER | PTEXT_VTA_TOP);
1672             glPopMatrix();
1673         }
1674     }
1675 
1676     // draw terrain info for debugging
1677     #ifdef INDEVEL
1678     {
1679         const vec3f wheelpos = vehic->part[0].wheel[0].ref_world.getPosition(); // wheel 0
1680         const TerrainType tt = game->terrain->getRoadSurface(wheelpos);
1681         const rgbcolor c = PUtil::getTerrainColor(tt);
1682         const std::string s = PUtil::getTerrainInfo(tt);
1683 
1684         glPushMatrix(); // 2
1685         glTranslatef(0.0f, 0.5f, 0.0f);
1686         glScalef(0.1f, 0.1f, 1.0f);
1687 
1688         if (tt != TerrainType::Unknown)
1689         {
1690             const GLfloat endx = s.length() * 8.0f / 12.0f + 0.1f;
1691 
1692             glPushMatrix();
1693             glDisable(GL_TEXTURE_2D);
1694             glTranslatef(-0.5f * s.length() * 8.0f / 12.0f, 0.0f, 0.0f);
1695             glTranslatef(0.0f, -1.0f, 0.0f);
1696             glBegin(GL_TRIANGLE_STRIP);
1697                 glColor3f(c.r / 255.0f, c.g / 255.0f, c.b / 255.0f);
1698                 glVertex2f(-0.2f,   0.0f);
1699                 glVertex2f(endx,    0.0f);
1700                 glVertex2f(-0.2f,   1.1f);
1701                 glVertex2f(endx,    1.1f);
1702             glEnd();
1703             glEnable(GL_TEXTURE_2D);
1704             glPopMatrix();
1705         }
1706 
1707         glColor3f(1.0f, 1.0f, 1.0f);
1708         getSSRender().drawText(s, PTEXT_HZA_CENTER | PTEXT_VTA_TOP);
1709         glPopMatrix(); // 2
1710     }
1711     #endif
1712 
1713     // draw if we're on road for debugging
1714     //#ifdef INDEVEL
1715     #if 0
1716     {
1717         const vec3f wheelpos = vehic->part[0].wheel[0].ref_world.getPosition(); // wheel 0
1718         std::string s;
1719         rgbcolor c;
1720 
1721         if (game->terrain->getRmapOnRoad(wheelpos))
1722         {
1723             c = rgbcolor(0xFF, 0xFF, 0xFF);
1724             s = "on the road";
1725         }
1726         else
1727         {
1728             c = rgbcolor(0x00, 0x00, 0x00);
1729             s = "off-road";
1730         }
1731 
1732         const GLfloat endx = s.length() * 8.0f / 12.0f + 0.1f;
1733 
1734         glPushMatrix(); // 2
1735         glTranslatef(0.0f, 0.25f, 0.0f);
1736         glScalef(0.1f, 0.1f, 1.0f);
1737         glPushMatrix();
1738         glDisable(GL_TEXTURE_2D);
1739         glTranslatef(-0.5f * s.length() * 8.0f / 12.0f, 0.0f, 0.0f);
1740         glTranslatef(0.0f, -1.0f, 0.0f);
1741         glBegin(GL_TRIANGLE_STRIP);
1742             glColor3f(c.r / 255.0f, c.g / 255.0f, c.b / 255.0f);
1743             glVertex2f(-0.2f,   0.0f);
1744             glVertex2f(endx,    0.0f);
1745             glVertex2f(-0.2f,   1.1f);
1746             glVertex2f(endx,    1.1f);
1747         glEnd();
1748         glEnable(GL_TEXTURE_2D);
1749         glPopMatrix();
1750         glColor3f(1.0f, 1.0f, 1.0f);
1751         getSSRender().drawText(s, PTEXT_HZA_CENTER | PTEXT_VTA_TOP);
1752         glPopMatrix(); // 2
1753     }
1754     #endif
1755 
1756       tex_fontSourceCodeOutlined->bind();
1757 
1758       glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
1759       glPushMatrix(); // 2
1760       glTranslatef(0.0f, 0.2f, 0.0f);
1761       glScalef(0.6f, 0.6f, 1.0f);
1762       if (game->gamestate == Gamestate::countdown)
1763       {
1764           float sizer = fmodf(game->othertime, 1.0f) + 0.5f;
1765           glScalef(sizer, sizer, 1.0f);
1766           getSSRender().drawText(
1767               PUtil::formatInt(((int)game->othertime + 1), 1),
1768               PTEXT_HZA_CENTER | PTEXT_VTA_CENTER);
1769       }
1770       else if (game->gamestate == Gamestate::finished)
1771       {
1772           if (game->getFinishState() == Gamefinish::pass)
1773           {
1774               glColor4f(0.5f, 1.0f, 0.5f, 1.0f);
1775               getSSRender().drawText("WIN", PTEXT_HZA_CENTER | PTEXT_VTA_CENTER);
1776           }
1777           else
1778           {
1779               glScalef(0.5f, 0.5f, 1.0f);
1780               glColor4f(0.5f, 0.0f, 0.0f, 1.0f);
1781               getSSRender().drawText("TIME EXCEEDED", PTEXT_HZA_CENTER | PTEXT_VTA_CENTER);
1782           }
1783       }
1784       else if (game->coursetime < 1.0f)
1785       {
1786           glColor4f(0.5f, 1.0f, 0.5f, 1.0f);
1787           getSSRender().drawText("GO!", PTEXT_HZA_CENTER | PTEXT_VTA_CENTER);
1788       }
1789       else if (game->coursetime < 2.0f)
1790       {
1791           float a = 1.0f - (game->coursetime - 1.0f);
1792           glColor4f(0.5f, 1.0f, 0.5f, a);
1793           getSSRender().drawText("GO!", PTEXT_HZA_CENTER | PTEXT_VTA_CENTER);
1794       }
1795       glPopMatrix(); // 2
1796 
1797       if (game->gamestate == Gamestate::countdown)
1798       {
1799           glPushMatrix(); // 2
1800           glTranslatef(0.0f, 0.6f, 0.0f);
1801           glScalef(0.08f, 0.08f, 1.0f);
1802           if (game->othertime < 1.0f)
1803           {
1804               glColor4f(1.0f, 1.0f, 1.0f, game->othertime);
1805               getSSRender().drawText(game->comment, PTEXT_HZA_CENTER | PTEXT_VTA_CENTER);
1806           }
1807           else
1808           {
1809               glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
1810               getSSRender().drawText(game->comment, PTEXT_HZA_CENTER | PTEXT_VTA_CENTER);
1811           }
1812           glPopMatrix(); // 2
1813       }
1814 
1815         if (pauserace)
1816         {
1817             glPushMatrix(); // 2
1818             glColor4f(0.25f, 0.25f, 1.0f, 1.0f);
1819             glScalef(0.25f, 0.25f, 1.0f);
1820             getSSRender().drawText("PAUSED", PTEXT_HZA_CENTER | PTEXT_VTA_CENTER);
1821             glPopMatrix(); // 2
1822         }
1823 
1824       glPopMatrix(); // 1
1825 
1826     }
1827 
1828     glPopMatrix(); // 0
1829 
1830     glMatrixMode(GL_PROJECTION);
1831     glPopMatrix();
1832     glMatrixMode(GL_MODELVIEW);
1833 
1834     glBlendFunc(GL_ONE, GL_ZERO);
1835 
1836     glEnable(GL_DEPTH_TEST);
1837     glEnable(GL_LIGHTING);
1838 }
1839