1 #include "video/video.h"
2 #include "game/game.h"
3 
4 #include "video/skybox.h"
5 #include "video/recognizer.h"
6 #include "video/explosion.h"
7 
8 // static float arena[] = { 1.0, 1.2, 1, 0.0 };
9 
10 #define MAX_LOD_LEVEL 3
11 static int lod_dist[MAX_LOD_LEVEL + 1][LC_LOD + 1] = {
12   { 1000, 1000, 1000 }, /* insane */
13   { 100, 200, 400 }, /* high */
14   { 30, 100, 200 }, /* low */
15   { 10, 30, 150 } /* ugly */
16 };
17 
18 /* spoke colors */
19 static float SpokeColor[4] = {1.0, 1.0, 1.0, 1.0};
20 static float NoSpokeColor[4] = {0.0, 0.0, 0.0, 1.0};
21 
drawGame(void)22 void drawGame(void) {
23   GLint i;
24 
25   polycount = 0;
26 
27   glEnable(GL_DEPTH_TEST);
28 
29   glClearColor(gSettingsCache.clear_color[0],
30                gSettingsCache.clear_color[1],
31                gSettingsCache.clear_color[2],
32                gSettingsCache.clear_color[3]);
33 
34   if(gSettingsCache.use_stencil) {
35     glClearStencil(0);
36     glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
37   } else {
38     glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
39   }
40 
41   for(i = 0; i < vp_max[gViewportType]; i++) {
42 		Player *p = game->player + viewport_content[i];
43 		PlayerVisual *pV = gPlayerVisuals + viewport_content[i];
44 		Visual *d = & pV->display;
45 
46     if(d->onScreen == 1) {
47       glViewport(d->vp_x, d->vp_y, d->vp_w, d->vp_h);
48 			drawCam(p, pV);
49       glDisable(GL_DEPTH_TEST);
50       glDepthMask(GL_FALSE);
51       if (gSettingsCache.show_scores)
52 				drawScore(p, d);
53       if (gSettingsCache.show_ai_status)
54 				if(p->ai->active == AI_COMPUTER)
55 					drawAI(d);
56     }
57     glDepthMask(GL_TRUE);
58     glEnable(GL_DEPTH_TEST);
59   }
60 
61   if (gSettingsCache.show_fps)
62     drawFPS(gScreen);
63 
64 	if(gSettingsCache.show_console)
65 		drawConsole(gScreen);
66 
67   /* printf("%d polys\n", polycount); */
68 }
69 
GetDistance(float * v,float * p,float * d)70 float GetDistance(float *v, float *p, float *d) {
71   float diff[3];
72   float tmp[3];
73   float t;
74   vsub(v, p, diff);
75   t = scalarprod(d, diff) / scalarprod(d, d);
76   vcopy(d, tmp);
77   vmul(tmp, t);
78   vsub(diff, tmp, tmp);
79   return sqrtf( scalarprod(tmp, tmp) );
80 }
81 
82 static float dirangles[] = { 0, -90, -180, 90, 180, -270 };
83 
getDirAngle(int time,Player * p)84 float getDirAngle(int time, Player *p) {
85   int last_dir;
86   float dirAngle;
87 
88   if(time < TURN_LENGTH) {
89     last_dir = p->data->last_dir;
90     if(p->data->dir == 3 && last_dir == 2)
91       last_dir = 4;
92     if(p->data->dir == 2 && last_dir == 3)
93       last_dir = 5;
94     dirAngle = ((TURN_LENGTH - time) * dirangles[last_dir] +
95 		time * dirangles[p->data->dir]) / TURN_LENGTH;
96   } else
97     dirAngle = dirangles[p->data->dir];
98 
99   return dirAngle;
100 }
101 
doCycleTurnRotation(PlayerVisual * pV,Player * p)102 void doCycleTurnRotation(PlayerVisual *pV, Player *p) {
103   int neigung_dir = -1;
104 	int time = game2->time.current - p->data->turn_time;
105   float dirAngle = getDirAngle(time, p);
106 
107   glRotatef(dirAngle, 0, 0, 1);
108 
109 #define neigung 25
110   if(time < TURN_LENGTH && p->data->last_dir != p->data->dir) {
111     float axis = 1.0f;
112     if(p->data->dir < p->data->last_dir && p->data->last_dir != 3)
113       axis = -1.0;
114     else if((p->data->last_dir == 3 && p->data->dir == 2) ||
115 	    (p->data->last_dir == 0 && p->data->dir == 3))
116       axis = -1.0;
117     glRotated(neigung * sin(PI * time / TURN_LENGTH),
118 	      0.0, axis * neigung_dir, 0.0);
119   }
120 #undef neigung
121 }
122 
drawCycleShadow(PlayerVisual * pV,Player * p,int lod,int drawTurn)123 void drawCycleShadow(PlayerVisual *pV, Player *p, int lod, int drawTurn) {
124   Mesh *cycle;
125   int turn_time = game2->time.current - p->data->turn_time;
126 
127   if(turn_time < TURN_LENGTH && !drawTurn)
128     return;
129 
130   if(pV->exp_radius != 0)
131     return;
132 
133   cycle = lightcycle[lod];
134 
135   /* states */
136 
137   glEnable(GL_CULL_FACE);
138 
139   if(gSettingsCache.use_stencil) {
140     glEnable(GL_STENCIL_TEST);
141     glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
142     glStencilFunc(GL_GREATER, 1, 1);
143     glEnable(GL_BLEND);
144     glColor4fv(shadow_color);
145     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
146   } else {
147     glColor3f(0, 0, 0);
148     glDisable(GL_BLEND);
149   }
150 
151   /* transformations */
152 
153   glPushMatrix();
154 	{
155 		float x, y;
156 		getPositionFromData(&x, &y, p->data);
157 		glTranslatef(x,y, 0.0);
158 	}
159   glMultMatrixf(shadow_matrix);
160   if (gSettingsCache.turn_cycle) {
161     doCycleTurnRotation(pV, p);
162   } else if (pV->exp_radius == 0) {
163     glRotatef(dirangles[p->data->dir], 0.0, 0.0, 1.0);
164   }
165   glTranslatef(0, 0, cycle->BBox.vSize.v[2] / 2);
166 
167   /* render */
168 
169   drawModel(cycle, TRI_MESH);
170 
171   /* restore */
172 
173   if(gSettingsCache.use_stencil)
174     glDisable(GL_STENCIL_TEST);
175 
176   glDisable(GL_BLEND);
177   glDisable(GL_CULL_FACE);
178   glPopMatrix();
179 }
180 
drawCycle(Player * p,PlayerVisual * pV,int lod,int drawTurn)181 void drawCycle(Player *p, PlayerVisual *pV, int lod, int drawTurn) {
182   Mesh *cycle = lightcycle[lod];
183 
184   unsigned int spoke_time = game2->time.current - pV->spoke_time;
185 	int turn_time = game2->time.current - p->data->turn_time;
186 
187   if(turn_time < TURN_LENGTH && !drawTurn)
188     return;
189 
190   glPushMatrix();
191 	{
192 		float x, y;
193 		getPositionFromData(&x, &y, p->data);
194 		glTranslatef(x, y, 0.0);
195 	}
196 
197   if (pV->exp_radius == 0 && gSettingsCache.turn_cycle == 0) {
198     glRotatef(dirangles[p->data->dir], 0.0, 0.0, 1.0);
199   }
200 
201   if (gSettingsCache.turn_cycle) {
202     doCycleTurnRotation(pV, p);
203   }
204 
205 	setupLights(eCycles);
206 
207   SetMaterialColor(cycle, "Hull", eDiffuse, pV->pColorDiffuse);
208   SetMaterialColor(cycle, "Hull", eSpecular, pV->pColorSpecular);
209 
210   if (gSettingsCache.light_cycles) {
211     glEnable(GL_LIGHTING);
212   }
213 
214   glEnable(GL_DEPTH_TEST);
215   glDepthMask(GL_TRUE);
216 
217   if (pV->exp_radius == 0) {
218     glEnable(GL_NORMALIZE);
219 
220     glTranslatef(0, 0, cycle->BBox.vSize.v[2] / 2);
221 
222     /* draw spoke animation */
223     if (spoke_time > 140 - (p->data->speed * 10)
224         && game->pauseflag == PAUSE_GAME_RUNNING) {
225       if (pV->spoke_state == 1) {
226         pV->spoke_state = 0;
227         SetMaterialColor(cycle, "Spoke", eSpecular, SpokeColor);
228         SetMaterialColor(cycle, "Spoke", eAmbient, SpokeColor);
229       } else {
230         pV->spoke_state = 1;
231         SetMaterialColor(cycle, "Spoke", eSpecular, NoSpokeColor);
232         SetMaterialColor(cycle, "Spoke", eAmbient, NoSpokeColor);
233       }
234       pV->spoke_time = game2->time.current;
235     }
236 
237     glEnable(GL_CULL_FACE);
238     drawModel(cycle, TRI_MESH);
239     glDisable(GL_CULL_FACE);
240 
241   } else if(pV->exp_radius < EXP_RADIUS_MAX) {
242 
243     glEnable(GL_BLEND);
244 
245     if (gSettingsCache.show_impact) {
246       drawImpact(pV);
247     }
248 
249     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
250 
251     glTranslatef(0, 0, cycle->BBox.vSize.v[2] / 2);
252 
253     drawModelExplosion(cycle, pV->exp_radius);
254   }
255   glDisable(GL_BLEND);
256   glDisable(GL_LIGHTING);
257   glPopMatrix();
258 }
259 
playerVisible(Player * eye,Player * target)260 int playerVisible(Player *eye, Player *target) {
261   float v1[3];
262   float v2[3];
263   float tmp[3];
264   float s;
265   float d;
266   int i;
267   int lod_level;
268 	float x, y;
269 
270   vsub(eye->camera->target, eye->camera->cam, v1);
271   normalize(v1);
272 
273 	getPositionFromData(&x, &y, target->data);
274 	tmp[0] = x;
275   tmp[1] = y;
276   tmp[2] = 0;
277 
278   lod_level = (gSettingsCache.lod > MAX_LOD_LEVEL) ?
279     MAX_LOD_LEVEL : gSettingsCache.lod;
280 
281   /* calculate lod */
282   vsub(eye->camera->cam, tmp, v2);
283   d = length(v2);
284   for(i = 0; i < LC_LOD && d >= lod_dist[lod_level][i]; i++);
285   if(i >= LC_LOD)
286     return -1;
287 
288   vsub(tmp, eye->camera->cam, v2);
289   normalize(v2);
290   s = scalarprod(v1, v2);
291   /* maybe that's not exactly correct, but I didn't notice anything */
292   d = cosf((gSettingsCache.fov / 2) * 2 * PI / 360.0);
293   /*
294     printf("v1: %.2f %.2f %.2f\nv2: %.2f %.2f %.2f\ns: %.2f d: %.2f\n\n",
295     v1[0], v1[1], v1[2], v2[0], v2[1], v2[2],
296     s, d);
297   */
298   if(s < d-(lightcycle[i]->BBox.fRadius*2))
299     return -1;
300   else
301     return i;
302 }
303 
drawPlayers(Player * p,PlayerVisual * pV)304 void drawPlayers(Player *p, PlayerVisual *pV) {
305   int i;
306 
307   for(i = 0; i < game->players; i++) {
308 		int lod;
309 		int drawTurn = 1;
310 
311 		if (gSettingsCache.camType == CAM_TYPE_COCKPIT &&
312 				p == &game->player[i])
313 			drawTurn = 0;
314 
315 		lod = playerVisible(p, &(game->player[i]));
316 		if (lod >= 0) {
317 			drawCycle(game->player + i, gPlayerVisuals + i, lod, drawTurn);
318 		}
319 	}
320 }
321 
drawCam(Player * p,PlayerVisual * pV)322 void drawCam(Player *p, PlayerVisual* pV) {
323   int i;
324   float up[3] = { 0, 0, 1 };
325 	Visual *d = & pV->display;
326 
327   glColor3f(0.0, 1.0, 0.0);
328 
329   glMatrixMode(GL_PROJECTION);
330   glLoadIdentity();
331   doPerspective(gSettingsCache.fov, d->vp_w / d->vp_h,
332                 gSettingsCache.znear, game2->rules.grid_size * 6.5f);
333 
334   glMatrixMode(GL_MODELVIEW);
335   glLoadIdentity();
336   /* set positions for GL lights in world coordinates */
337   glLightfv(GL_LIGHT1, GL_POSITION, p->camera->cam);
338 
339   doLookAt(p->camera->cam, p->camera->target, up);
340   glDisable(GL_LIGHTING);
341   glDisable(GL_BLEND);
342 
343   glDepthMask(GL_FALSE);
344   glDisable(GL_DEPTH_TEST);
345 
346   /* skybox */
347   if (gSettingsCache.show_skybox) {
348     drawSkybox(game2->rules.grid_size);
349   }
350 
351   /* fixme: clear z-buffer handling */
352   /* glDepthMask(GL_TRUE); */
353 
354   /* floor */
355   if (gSettingsCache.show_floor_texture) {
356     drawFloorTextured(game2->rules.grid_size,
357                       gScreen->textures[TEX_FLOOR]);
358   } else {
359     /* should this be an artpack setting? */
360     float line_color[] = {1.0, 1.0, 1.0};
361 
362     drawFloorGrid(game2->rules.grid_size,
363                   gSettingsCache.line_spacing,
364                   line_color,
365                   gSettingsCache.clear_color);
366   }
367 
368   /* glDepthMask(GL_FALSE); */
369 
370   /* shadows on the floor: cycle, recognizer, trails */
371   if (gSettingsCache.show_recognizer) {
372     drawRecognizerShadow();
373   }
374 
375   for(i = 0; i < game->players; i++) {
376     int lod = playerVisible(p, game->player + i);
377 		if (lod >= 0) {
378 			int drawTurn = 1;
379 			if (! gSettingsCache.camType == CAM_TYPE_COCKPIT ||
380 	 			p != &game->player[i])
381 				drawTurn = 0;
382 			drawCycleShadow(gPlayerVisuals + i, game->player + i, lod, drawTurn);
383 		}
384 		if (game->player[i].data->trail_height > 0 )
385 			drawTrailShadow(game->player + i, gPlayerVisuals + i);
386 	}
387 
388   glDepthMask(GL_TRUE);
389   glEnable(GL_DEPTH_TEST);
390 
391   if (gSettingsCache.show_recognizer &&
392       p->data->speed != SPEED_GONE) {
393     drawRecognizer();
394   }
395 
396   if (gSettingsCache.show_wall == 1) {
397     drawWalls();
398   }
399 
400   drawPlayers(p, pV);
401 
402 	setupLights(eWorld);
403 
404   glEnable(GL_POLYGON_OFFSET_FILL);
405   glPolygonOffset(1,1);
406 
407 	{
408 		TrailMesh mesh;
409 		mesh.pVertices = (vec3*) malloc(1000 * sizeof(vec3));
410 		mesh.pNormals = (vec3*) malloc(1000 * sizeof(vec3));
411 		mesh.pColors = (unsigned char*) malloc(1000 * 4 * sizeof(float));
412 		mesh.pTexCoords = (vec2*) malloc(1000 * sizeof(vec2));
413 		mesh.pIndices = (unsigned short*) malloc(1000 * 2);
414 
415 		for(i = 0; i < game->players; i++) {
416 			if (game->player[i].data->trail_height > 0 ) {
417 				int vOffset = 0;
418 				int iOffset = 0;
419 				mesh.iUsed = 0;
420 				trailGeometry(game->player + i, gPlayerVisuals + i,
421 											&mesh, &vOffset, &iOffset);
422 				bowGeometry(game->player + i, gPlayerVisuals + i,
423 										&mesh, &vOffset, &iOffset);
424 				trailStatesNormal(game->player + i, gScreen->textures[TEX_DECAL]);
425 				trailRender(&mesh);
426 				trailStatesRestore();
427 			}
428 		}
429 		free(mesh.pVertices);
430 		free(mesh.pNormals);
431 		free(mesh.pColors);
432 		free(mesh.pTexCoords);
433 		free(mesh.pIndices);
434 	}
435 
436   glDisable(GL_POLYGON_OFFSET_FILL);
437 
438   for(i = 0; i < game->players; i++)
439     if (game->player[i].data->trail_height > 0 )
440 			drawTrailLines(game->player + i, gPlayerVisuals + i);
441 
442   /* transparent stuff */
443   /* draw the glow around the other players: */
444   if (gSettingsCache.show_glow == 1) {
445     glEnable(GL_BLEND);
446     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
447 
448     for (i = 0; i < game->players; i++) {
449       if (p != game->player + i && PLAYER_IS_ACTIVE(game->player + i)) {
450 	      drawGlow(p->camera, game->player + i, gPlayerVisuals + i,
451 								 d, TRAIL_HEIGHT * 4);
452       }
453 
454     glDisable(GL_BLEND);
455     }
456   }
457 	/* 2d hack */
458 	if(gSettingsCache.map_ratio_w > 0)
459 	{
460 		Visual d2d;
461 		memcpy(&d2d, d, sizeof(Visual));
462 		d2d.vp_w *= gSettingsCache.map_ratio_w;
463 		d2d.vp_h *= gSettingsCache.map_ratio_h;
464 
465 		d2d.vp_x += 20;
466 		d2d.vp_y += 20;
467 
468 		glDepthMask(GL_FALSE);
469 		glDisable(GL_DEPTH_TEST);
470 		draw2D(&d2d);
471 		glDepthMask(GL_TRUE);
472 		glEnable(GL_DEPTH_TEST);
473 	}
474 }
475 
initGLGame(void)476 void initGLGame(void) {
477   glShadeModel( GL_SMOOTH );
478   glDepthMask(GL_TRUE);
479   glEnable(GL_DEPTH_TEST);
480 }
481