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