Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
5131 | clevermous | 1 | /* |
2 | Copyright (C) 1996-1997 Id Software, Inc. |
||
3 | |||
4 | This program is free software; you can redistribute it and/or |
||
5 | modify it under the terms of the GNU General Public License |
||
6 | as published by the Free Software Foundation; either version 2 |
||
7 | of the License, or (at your option) any later version. |
||
8 | |||
9 | This program is distributed in the hope that it will be useful, |
||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
||
12 | |||
13 | See the 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
||
18 | |||
19 | */ |
||
20 | // r_main.c |
||
21 | |||
22 | #include "quakedef.h" |
||
23 | |||
24 | entity_t r_worldentity; |
||
25 | |||
26 | qboolean r_cache_thrash; // compatability |
||
27 | |||
28 | vec3_t modelorg, r_entorigin; |
||
29 | entity_t *currententity; |
||
30 | |||
31 | int r_visframecount; // bumped when going to a new PVS |
||
32 | int r_framecount; // used for dlight push checking |
||
33 | |||
34 | mplane_t frustum[4]; |
||
35 | |||
36 | int c_brush_polys, c_alias_polys; |
||
37 | |||
38 | qboolean envmap; // true during envmap command capture |
||
39 | |||
40 | int currenttexture = -1; // to avoid unnecessary texture sets |
||
41 | |||
42 | int cnttextures[2] = {-1, -1}; // cached |
||
43 | |||
44 | int particletexture; // little dot for particles |
||
45 | int playertextures; // up to 16 color translated skins |
||
46 | |||
47 | int mirrortexturenum; // quake texturenum, not gltexturenum |
||
48 | qboolean mirror; |
||
49 | mplane_t *mirror_plane; |
||
50 | |||
51 | // |
||
52 | // view origin |
||
53 | // |
||
54 | vec3_t vup; |
||
55 | vec3_t vpn; |
||
56 | vec3_t vright; |
||
57 | vec3_t r_origin; |
||
58 | |||
59 | float r_world_matrix[16]; |
||
60 | float r_base_world_matrix[16]; |
||
61 | |||
62 | // |
||
63 | // screen size info |
||
64 | // |
||
65 | refdef_t r_refdef; |
||
66 | |||
67 | mleaf_t *r_viewleaf, *r_oldviewleaf; |
||
68 | |||
69 | texture_t *r_notexture_mip; |
||
70 | |||
71 | int d_lightstylevalue[256]; // 8.8 fraction of base light value |
||
72 | |||
73 | |||
74 | void R_MarkLeaves (void); |
||
75 | |||
76 | cvar_t r_norefresh = {"r_norefresh","0"}; |
||
77 | cvar_t r_drawentities = {"r_drawentities","1"}; |
||
78 | cvar_t r_drawviewmodel = {"r_drawviewmodel","1"}; |
||
79 | cvar_t r_speeds = {"r_speeds","0"}; |
||
80 | cvar_t r_fullbright = {"r_fullbright","0"}; |
||
81 | cvar_t r_lightmap = {"r_lightmap","0"}; |
||
82 | cvar_t r_shadows = {"r_shadows","0"}; |
||
83 | cvar_t r_mirroralpha = {"r_mirroralpha","1"}; |
||
84 | cvar_t r_wateralpha = {"r_wateralpha","1"}; |
||
85 | cvar_t r_dynamic = {"r_dynamic","1"}; |
||
86 | cvar_t r_novis = {"r_novis","0"}; |
||
87 | |||
88 | cvar_t gl_finish = {"gl_finish","0"}; |
||
89 | cvar_t gl_clear = {"gl_clear","0"}; |
||
90 | cvar_t gl_cull = {"gl_cull","1"}; |
||
91 | cvar_t gl_texsort = {"gl_texsort","1"}; |
||
92 | cvar_t gl_smoothmodels = {"gl_smoothmodels","1"}; |
||
93 | cvar_t gl_affinemodels = {"gl_affinemodels","0"}; |
||
94 | cvar_t gl_polyblend = {"gl_polyblend","1"}; |
||
95 | cvar_t gl_flashblend = {"gl_flashblend","1"}; |
||
96 | cvar_t gl_playermip = {"gl_playermip","0"}; |
||
97 | cvar_t gl_nocolors = {"gl_nocolors","0"}; |
||
98 | cvar_t gl_keeptjunctions = {"gl_keeptjunctions","0"}; |
||
99 | cvar_t gl_reporttjunctions = {"gl_reporttjunctions","0"}; |
||
100 | cvar_t gl_doubleeyes = {"gl_doubleeys", "1"}; |
||
101 | |||
102 | extern cvar_t gl_ztrick; |
||
103 | |||
104 | /* |
||
105 | ================= |
||
106 | R_CullBox |
||
107 | |||
108 | Returns true if the box is completely outside the frustom |
||
109 | ================= |
||
110 | */ |
||
111 | qboolean R_CullBox (vec3_t mins, vec3_t maxs) |
||
112 | { |
||
113 | int i; |
||
114 | |||
115 | for (i=0 ; i<4 ; i++) |
||
116 | if (BoxOnPlaneSide (mins, maxs, &frustum[i]) == 2) |
||
117 | return true; |
||
118 | return false; |
||
119 | } |
||
120 | |||
121 | |||
122 | void R_RotateForEntity (entity_t *e) |
||
123 | { |
||
124 | glTranslatef (e->origin[0], e->origin[1], e->origin[2]); |
||
125 | |||
126 | glRotatef (e->angles[1], 0, 0, 1); |
||
127 | glRotatef (-e->angles[0], 0, 1, 0); |
||
128 | glRotatef (e->angles[2], 1, 0, 0); |
||
129 | } |
||
130 | |||
131 | /* |
||
132 | ============================================================= |
||
133 | |||
134 | SPRITE MODELS |
||
135 | |||
136 | ============================================================= |
||
137 | */ |
||
138 | |||
139 | /* |
||
140 | ================ |
||
141 | R_GetSpriteFrame |
||
142 | ================ |
||
143 | */ |
||
144 | mspriteframe_t *R_GetSpriteFrame (entity_t *currententity) |
||
145 | { |
||
146 | msprite_t *psprite; |
||
147 | mspritegroup_t *pspritegroup; |
||
148 | mspriteframe_t *pspriteframe; |
||
149 | int i, numframes, frame; |
||
150 | float *pintervals, fullinterval, targettime, time; |
||
151 | |||
152 | psprite = currententity->model->cache.data; |
||
153 | frame = currententity->frame; |
||
154 | |||
155 | if ((frame >= psprite->numframes) || (frame < 0)) |
||
156 | { |
||
157 | Con_Printf ("R_DrawSprite: no such frame %d\n", frame); |
||
158 | frame = 0; |
||
159 | } |
||
160 | |||
161 | if (psprite->frames[frame].type == SPR_SINGLE) |
||
162 | { |
||
163 | pspriteframe = psprite->frames[frame].frameptr; |
||
164 | } |
||
165 | else |
||
166 | { |
||
167 | pspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr; |
||
168 | pintervals = pspritegroup->intervals; |
||
169 | numframes = pspritegroup->numframes; |
||
170 | fullinterval = pintervals[numframes-1]; |
||
171 | |||
172 | time = cl.time + currententity->syncbase; |
||
173 | |||
174 | // when loading in Mod_LoadSpriteGroup, we guaranteed all interval values |
||
175 | // are positive, so we don't have to worry about division by 0 |
||
176 | targettime = time - ((int)(time / fullinterval)) * fullinterval; |
||
177 | |||
178 | for (i=0 ; i<(numframes-1) ; i++) |
||
179 | { |
||
180 | if (pintervals[i] > targettime) |
||
181 | break; |
||
182 | } |
||
183 | |||
184 | pspriteframe = pspritegroup->frames[i]; |
||
185 | } |
||
186 | |||
187 | return pspriteframe; |
||
188 | } |
||
189 | |||
190 | |||
191 | /* |
||
192 | ================= |
||
193 | R_DrawSpriteModel |
||
194 | |||
195 | ================= |
||
196 | */ |
||
197 | void R_DrawSpriteModel (entity_t *e) |
||
198 | { |
||
199 | vec3_t point; |
||
200 | mspriteframe_t *frame; |
||
201 | float *up, *right; |
||
202 | vec3_t v_forward, v_right, v_up; |
||
203 | msprite_t *psprite; |
||
204 | |||
205 | // don't even bother culling, because it's just a single |
||
206 | // polygon without a surface cache |
||
207 | frame = R_GetSpriteFrame (e); |
||
208 | psprite = currententity->model->cache.data; |
||
209 | |||
210 | if (psprite->type == SPR_ORIENTED) |
||
211 | { // bullet marks on walls |
||
212 | AngleVectors (currententity->angles, v_forward, v_right, v_up); |
||
213 | up = v_up; |
||
214 | right = v_right; |
||
215 | } |
||
216 | else |
||
217 | { // normal sprite |
||
218 | up = vup; |
||
219 | right = vright; |
||
220 | } |
||
221 | |||
222 | glColor3f (1,1,1); |
||
223 | |||
224 | GL_DisableMultitexture(); |
||
225 | |||
226 | GL_Bind(frame->gl_texturenum); |
||
227 | |||
228 | glEnable (GL_ALPHA_TEST); |
||
229 | glBegin (GL_QUADS); |
||
230 | |||
231 | glTexCoord2f (0, 1); |
||
232 | VectorMA (e->origin, frame->down, up, point); |
||
233 | VectorMA (point, frame->left, right, point); |
||
234 | glVertex3fv (point); |
||
235 | |||
236 | glTexCoord2f (0, 0); |
||
237 | VectorMA (e->origin, frame->up, up, point); |
||
238 | VectorMA (point, frame->left, right, point); |
||
239 | glVertex3fv (point); |
||
240 | |||
241 | glTexCoord2f (1, 0); |
||
242 | VectorMA (e->origin, frame->up, up, point); |
||
243 | VectorMA (point, frame->right, right, point); |
||
244 | glVertex3fv (point); |
||
245 | |||
246 | glTexCoord2f (1, 1); |
||
247 | VectorMA (e->origin, frame->down, up, point); |
||
248 | VectorMA (point, frame->right, right, point); |
||
249 | glVertex3fv (point); |
||
250 | |||
251 | glEnd (); |
||
252 | |||
253 | glDisable (GL_ALPHA_TEST); |
||
254 | } |
||
255 | |||
256 | /* |
||
257 | ============================================================= |
||
258 | |||
259 | ALIAS MODELS |
||
260 | |||
261 | ============================================================= |
||
262 | */ |
||
263 | |||
264 | |||
265 | #define NUMVERTEXNORMALS 162 |
||
266 | |||
267 | float r_avertexnormals[NUMVERTEXNORMALS][3] = { |
||
268 | #include "anorms.h" |
||
269 | }; |
||
270 | |||
271 | vec3_t shadevector; |
||
272 | float shadelight, ambientlight; |
||
273 | |||
274 | // precalculated dot products for quantized angles |
||
275 | #define SHADEDOT_QUANT 16 |
||
276 | float r_avertexnormal_dots[SHADEDOT_QUANT][256] = |
||
277 | #include "anorm_dots.h" |
||
278 | ; |
||
279 | |||
280 | float *shadedots = r_avertexnormal_dots[0]; |
||
281 | |||
282 | int lastposenum; |
||
283 | |||
284 | /* |
||
285 | ============= |
||
286 | GL_DrawAliasFrame |
||
287 | ============= |
||
288 | */ |
||
289 | void GL_DrawAliasFrame (aliashdr_t *paliashdr, int posenum) |
||
290 | { |
||
291 | float s, t; |
||
292 | float l; |
||
293 | int i, j; |
||
294 | int index; |
||
295 | trivertx_t *v, *verts; |
||
296 | int list; |
||
297 | int *order; |
||
298 | vec3_t point; |
||
299 | float *normal; |
||
300 | int count; |
||
301 | |||
302 | lastposenum = posenum; |
||
303 | |||
304 | verts = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata); |
||
305 | verts += posenum * paliashdr->poseverts; |
||
306 | order = (int *)((byte *)paliashdr + paliashdr->commands); |
||
307 | |||
308 | while (1) |
||
309 | { |
||
310 | // get the vertex count and primitive type |
||
311 | count = *order++; |
||
312 | if (!count) |
||
313 | break; // done |
||
314 | if (count < 0) |
||
315 | { |
||
316 | count = -count; |
||
317 | glBegin (GL_TRIANGLE_FAN); |
||
318 | } |
||
319 | else |
||
320 | glBegin (GL_TRIANGLE_STRIP); |
||
321 | |||
322 | do |
||
323 | { |
||
324 | // texture coordinates come from the draw list |
||
325 | glTexCoord2f (((float *)order)[0], ((float *)order)[1]); |
||
326 | order += 2; |
||
327 | |||
328 | // normals and vertexes come from the frame list |
||
329 | l = shadedots[verts->lightnormalindex] * shadelight; |
||
330 | glColor3f (l, l, l); |
||
331 | glVertex3f (verts->v[0], verts->v[1], verts->v[2]); |
||
332 | verts++; |
||
333 | } while (--count); |
||
334 | |||
335 | glEnd (); |
||
336 | } |
||
337 | } |
||
338 | |||
339 | |||
340 | /* |
||
341 | ============= |
||
342 | GL_DrawAliasShadow |
||
343 | ============= |
||
344 | */ |
||
345 | extern vec3_t lightspot; |
||
346 | |||
347 | void GL_DrawAliasShadow (aliashdr_t *paliashdr, int posenum) |
||
348 | { |
||
349 | float s, t, l; |
||
350 | int i, j; |
||
351 | int index; |
||
352 | trivertx_t *v, *verts; |
||
353 | int list; |
||
354 | int *order; |
||
355 | vec3_t point; |
||
356 | float *normal; |
||
357 | float height, lheight; |
||
358 | int count; |
||
359 | |||
360 | lheight = currententity->origin[2] - lightspot[2]; |
||
361 | |||
362 | height = 0; |
||
363 | verts = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata); |
||
364 | verts += posenum * paliashdr->poseverts; |
||
365 | order = (int *)((byte *)paliashdr + paliashdr->commands); |
||
366 | |||
367 | height = -lheight + 1.0; |
||
368 | |||
369 | while (1) |
||
370 | { |
||
371 | // get the vertex count and primitive type |
||
372 | count = *order++; |
||
373 | if (!count) |
||
374 | break; // done |
||
375 | if (count < 0) |
||
376 | { |
||
377 | count = -count; |
||
378 | glBegin (GL_TRIANGLE_FAN); |
||
379 | } |
||
380 | else |
||
381 | glBegin (GL_TRIANGLE_STRIP); |
||
382 | |||
383 | do |
||
384 | { |
||
385 | // texture coordinates come from the draw list |
||
386 | // (skipped for shadows) glTexCoord2fv ((float *)order); |
||
387 | order += 2; |
||
388 | |||
389 | // normals and vertexes come from the frame list |
||
390 | point[0] = verts->v[0] * paliashdr->scale[0] + paliashdr->scale_origin[0]; |
||
391 | point[1] = verts->v[1] * paliashdr->scale[1] + paliashdr->scale_origin[1]; |
||
392 | point[2] = verts->v[2] * paliashdr->scale[2] + paliashdr->scale_origin[2]; |
||
393 | |||
394 | point[0] -= shadevector[0]*(point[2]+lheight); |
||
395 | point[1] -= shadevector[1]*(point[2]+lheight); |
||
396 | point[2] = height; |
||
397 | // height -= 0.001; |
||
398 | glVertex3fv (point); |
||
399 | |||
400 | verts++; |
||
401 | } while (--count); |
||
402 | |||
403 | glEnd (); |
||
404 | } |
||
405 | } |
||
406 | |||
407 | |||
408 | |||
409 | /* |
||
410 | ================= |
||
411 | R_SetupAliasFrame |
||
412 | |||
413 | ================= |
||
414 | */ |
||
415 | void R_SetupAliasFrame (int frame, aliashdr_t *paliashdr) |
||
416 | { |
||
417 | int pose, numposes; |
||
418 | float interval; |
||
419 | |||
420 | if ((frame >= paliashdr->numframes) || (frame < 0)) |
||
421 | { |
||
422 | Con_DPrintf ("R_AliasSetupFrame: no such frame %d\n", frame); |
||
423 | frame = 0; |
||
424 | } |
||
425 | |||
426 | pose = paliashdr->frames[frame].firstpose; |
||
427 | numposes = paliashdr->frames[frame].numposes; |
||
428 | |||
429 | if (numposes > 1) |
||
430 | { |
||
431 | interval = paliashdr->frames[frame].interval; |
||
432 | pose += (int)(cl.time / interval) % numposes; |
||
433 | } |
||
434 | |||
435 | GL_DrawAliasFrame (paliashdr, pose); |
||
436 | } |
||
437 | |||
438 | |||
439 | |||
440 | /* |
||
441 | ================= |
||
442 | R_DrawAliasModel |
||
443 | |||
444 | ================= |
||
445 | */ |
||
446 | void R_DrawAliasModel (entity_t *e) |
||
447 | { |
||
448 | int i, j; |
||
449 | int lnum; |
||
450 | vec3_t dist; |
||
451 | float add; |
||
452 | model_t *clmodel; |
||
453 | vec3_t mins, maxs; |
||
454 | aliashdr_t *paliashdr; |
||
455 | trivertx_t *verts, *v; |
||
456 | int index; |
||
457 | float s, t, an; |
||
458 | int anim; |
||
459 | |||
460 | clmodel = currententity->model; |
||
461 | |||
462 | VectorAdd (currententity->origin, clmodel->mins, mins); |
||
463 | VectorAdd (currententity->origin, clmodel->maxs, maxs); |
||
464 | |||
465 | if (R_CullBox (mins, maxs)) |
||
466 | return; |
||
467 | |||
468 | |||
469 | VectorCopy (currententity->origin, r_entorigin); |
||
470 | VectorSubtract (r_origin, r_entorigin, modelorg); |
||
471 | |||
472 | // |
||
473 | // get lighting information |
||
474 | // |
||
475 | |||
476 | ambientlight = shadelight = R_LightPoint (currententity->origin); |
||
477 | |||
478 | // allways give the gun some light |
||
479 | if (e == &cl.viewent && ambientlight < 24) |
||
480 | ambientlight = shadelight = 24; |
||
481 | |||
482 | for (lnum=0 ; lnum |
||
483 | { |
||
484 | if (cl_dlights[lnum].die >= cl.time) |
||
485 | { |
||
486 | VectorSubtract (currententity->origin, |
||
487 | cl_dlights[lnum].origin, |
||
488 | dist); |
||
489 | add = cl_dlights[lnum].radius - Length(dist); |
||
490 | |||
491 | if (add > 0) { |
||
492 | ambientlight += add; |
||
493 | //ZOID models should be affected by dlights as well |
||
494 | shadelight += add; |
||
495 | } |
||
496 | } |
||
497 | } |
||
498 | |||
499 | // clamp lighting so it doesn't overbright as much |
||
500 | if (ambientlight > 128) |
||
501 | ambientlight = 128; |
||
502 | if (ambientlight + shadelight > 192) |
||
503 | shadelight = 192 - ambientlight; |
||
504 | |||
505 | // ZOID: never allow players to go totally black |
||
506 | i = currententity - cl_entities; |
||
507 | if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */) |
||
508 | if (ambientlight < 8) |
||
509 | ambientlight = shadelight = 8; |
||
510 | |||
511 | // HACK HACK HACK -- no fullbright colors, so make torches full light |
||
512 | if (!strcmp (clmodel->name, "progs/flame2.mdl") |
||
513 | || !strcmp (clmodel->name, "progs/flame.mdl") ) |
||
514 | ambientlight = shadelight = 256; |
||
515 | |||
516 | shadedots = r_avertexnormal_dots[((int)(e->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)]; |
||
517 | shadelight = shadelight / 200.0; |
||
518 | |||
519 | an = e->angles[1]/180*M_PI; |
||
520 | shadevector[0] = cos(-an); |
||
521 | shadevector[1] = sin(-an); |
||
522 | shadevector[2] = 1; |
||
523 | VectorNormalize (shadevector); |
||
524 | |||
525 | // |
||
526 | // locate the proper data |
||
527 | // |
||
528 | paliashdr = (aliashdr_t *)Mod_Extradata (currententity->model); |
||
529 | |||
530 | c_alias_polys += paliashdr->numtris; |
||
531 | |||
532 | // |
||
533 | // draw all the triangles |
||
534 | // |
||
535 | |||
536 | GL_DisableMultitexture(); |
||
537 | |||
538 | glPushMatrix (); |
||
539 | R_RotateForEntity (e); |
||
540 | |||
541 | if (!strcmp (clmodel->name, "progs/eyes.mdl") && gl_doubleeyes.value) { |
||
542 | glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2] - (22 + 8)); |
||
543 | // double size of eyes, since they are really hard to see in gl |
||
544 | glScalef (paliashdr->scale[0]*2, paliashdr->scale[1]*2, paliashdr->scale[2]*2); |
||
545 | } else { |
||
546 | glTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]); |
||
547 | glScalef (paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]); |
||
548 | } |
||
549 | |||
550 | anim = (int)(cl.time*10) & 3; |
||
551 | GL_Bind(paliashdr->gl_texturenum[currententity->skinnum][anim]); |
||
552 | |||
553 | // we can't dynamically colormap textures, so they are cached |
||
554 | // seperately for the players. Heads are just uncolored. |
||
555 | if (currententity->colormap != vid.colormap && !gl_nocolors.value) |
||
556 | { |
||
557 | i = currententity - cl_entities; |
||
558 | if (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, "progs/player.mdl") */) |
||
559 | GL_Bind(playertextures - 1 + i); |
||
560 | } |
||
561 | |||
562 | if (gl_smoothmodels.value) |
||
563 | glShadeModel (GL_SMOOTH); |
||
564 | glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); |
||
565 | |||
566 | if (gl_affinemodels.value) |
||
567 | glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); |
||
568 | |||
569 | R_SetupAliasFrame (currententity->frame, paliashdr); |
||
570 | |||
571 | glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); |
||
572 | |||
573 | glShadeModel (GL_FLAT); |
||
574 | if (gl_affinemodels.value) |
||
575 | glHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); |
||
576 | |||
577 | glPopMatrix (); |
||
578 | |||
579 | if (r_shadows.value) |
||
580 | { |
||
581 | glPushMatrix (); |
||
582 | R_RotateForEntity (e); |
||
583 | glDisable (GL_TEXTURE_2D); |
||
584 | glEnable (GL_BLEND); |
||
585 | glColor4f (0,0,0,0.5); |
||
586 | GL_DrawAliasShadow (paliashdr, lastposenum); |
||
587 | glEnable (GL_TEXTURE_2D); |
||
588 | glDisable (GL_BLEND); |
||
589 | glColor4f (1,1,1,1); |
||
590 | glPopMatrix (); |
||
591 | } |
||
592 | |||
593 | } |
||
594 | |||
595 | //================================================================================== |
||
596 | |||
597 | /* |
||
598 | ============= |
||
599 | R_DrawEntitiesOnList |
||
600 | ============= |
||
601 | */ |
||
602 | void R_DrawEntitiesOnList (void) |
||
603 | { |
||
604 | int i; |
||
605 | |||
606 | if (!r_drawentities.value) |
||
607 | return; |
||
608 | |||
609 | // draw sprites seperately, because of alpha blending |
||
610 | for (i=0 ; i |
||
611 | { |
||
612 | currententity = cl_visedicts[i]; |
||
613 | |||
614 | switch (currententity->model->type) |
||
615 | { |
||
616 | case mod_alias: |
||
617 | R_DrawAliasModel (currententity); |
||
618 | break; |
||
619 | |||
620 | case mod_brush: |
||
621 | R_DrawBrushModel (currententity); |
||
622 | break; |
||
623 | |||
624 | default: |
||
625 | break; |
||
626 | } |
||
627 | } |
||
628 | |||
629 | for (i=0 ; i |
||
630 | { |
||
631 | currententity = cl_visedicts[i]; |
||
632 | |||
633 | switch (currententity->model->type) |
||
634 | { |
||
635 | case mod_sprite: |
||
636 | R_DrawSpriteModel (currententity); |
||
637 | break; |
||
638 | } |
||
639 | } |
||
640 | } |
||
641 | |||
642 | /* |
||
643 | ============= |
||
644 | R_DrawViewModel |
||
645 | ============= |
||
646 | */ |
||
647 | void R_DrawViewModel (void) |
||
648 | { |
||
649 | float ambient[4], diffuse[4]; |
||
650 | int j; |
||
651 | int lnum; |
||
652 | vec3_t dist; |
||
653 | float add; |
||
654 | dlight_t *dl; |
||
655 | int ambientlight, shadelight; |
||
656 | |||
657 | if (!r_drawviewmodel.value) |
||
658 | return; |
||
659 | |||
660 | if (chase_active.value) |
||
661 | return; |
||
662 | |||
663 | if (envmap) |
||
664 | return; |
||
665 | |||
666 | if (!r_drawentities.value) |
||
667 | return; |
||
668 | |||
669 | if (cl.items & IT_INVISIBILITY) |
||
670 | return; |
||
671 | |||
672 | if (cl.stats[STAT_HEALTH] <= 0) |
||
673 | return; |
||
674 | |||
675 | currententity = &cl.viewent; |
||
676 | if (!currententity->model) |
||
677 | return; |
||
678 | |||
679 | j = R_LightPoint (currententity->origin); |
||
680 | |||
681 | if (j < 24) |
||
682 | j = 24; // allways give some light on gun |
||
683 | ambientlight = j; |
||
684 | shadelight = j; |
||
685 | |||
686 | // add dynamic lights |
||
687 | for (lnum=0 ; lnum |
||
688 | { |
||
689 | dl = &cl_dlights[lnum]; |
||
690 | if (!dl->radius) |
||
691 | continue; |
||
692 | if (!dl->radius) |
||
693 | continue; |
||
694 | if (dl->die < cl.time) |
||
695 | continue; |
||
696 | |||
697 | VectorSubtract (currententity->origin, dl->origin, dist); |
||
698 | add = dl->radius - Length(dist); |
||
699 | if (add > 0) |
||
700 | ambientlight += add; |
||
701 | } |
||
702 | |||
703 | ambient[0] = ambient[1] = ambient[2] = ambient[3] = (float)ambientlight / 128; |
||
704 | diffuse[0] = diffuse[1] = diffuse[2] = diffuse[3] = (float)shadelight / 128; |
||
705 | |||
706 | // hack the depth range to prevent view model from poking into walls |
||
707 | glDepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin)); |
||
708 | R_DrawAliasModel (currententity); |
||
709 | glDepthRange (gldepthmin, gldepthmax); |
||
710 | } |
||
711 | |||
712 | |||
713 | /* |
||
714 | ============ |
||
715 | R_PolyBlend |
||
716 | ============ |
||
717 | */ |
||
718 | void R_PolyBlend (void) |
||
719 | { |
||
720 | if (!gl_polyblend.value) |
||
721 | return; |
||
722 | if (!v_blend[3]) |
||
723 | return; |
||
724 | |||
725 | GL_DisableMultitexture(); |
||
726 | |||
727 | glDisable (GL_ALPHA_TEST); |
||
728 | glEnable (GL_BLEND); |
||
729 | glDisable (GL_DEPTH_TEST); |
||
730 | glDisable (GL_TEXTURE_2D); |
||
731 | |||
732 | glLoadIdentity (); |
||
733 | |||
734 | glRotatef (-90, 1, 0, 0); // put Z going up |
||
735 | glRotatef (90, 0, 0, 1); // put Z going up |
||
736 | |||
737 | glColor4fv (v_blend); |
||
738 | |||
739 | glBegin (GL_QUADS); |
||
740 | |||
741 | glVertex3f (10, 100, 100); |
||
742 | glVertex3f (10, -100, 100); |
||
743 | glVertex3f (10, -100, -100); |
||
744 | glVertex3f (10, 100, -100); |
||
745 | glEnd (); |
||
746 | |||
747 | glDisable (GL_BLEND); |
||
748 | glEnable (GL_TEXTURE_2D); |
||
749 | glEnable (GL_ALPHA_TEST); |
||
750 | } |
||
751 | |||
752 | |||
753 | int SignbitsForPlane (mplane_t *out) |
||
754 | { |
||
755 | int bits, j; |
||
756 | |||
757 | // for fast box on planeside test |
||
758 | |||
759 | bits = 0; |
||
760 | for (j=0 ; j<3 ; j++) |
||
761 | { |
||
762 | if (out->normal[j] < 0) |
||
763 | bits |= 1< |
||
764 | } |
||
765 | return bits; |
||
766 | } |
||
767 | |||
768 | |||
769 | void R_SetFrustum (void) |
||
770 | { |
||
771 | int i; |
||
772 | |||
773 | if (r_refdef.fov_x == 90) |
||
774 | { |
||
775 | // front side is visible |
||
776 | |||
777 | VectorAdd (vpn, vright, frustum[0].normal); |
||
778 | VectorSubtract (vpn, vright, frustum[1].normal); |
||
779 | |||
780 | VectorAdd (vpn, vup, frustum[2].normal); |
||
781 | VectorSubtract (vpn, vup, frustum[3].normal); |
||
782 | } |
||
783 | else |
||
784 | { |
||
785 | // rotate VPN right by FOV_X/2 degrees |
||
786 | RotatePointAroundVector( frustum[0].normal, vup, vpn, -(90-r_refdef.fov_x / 2 ) ); |
||
787 | // rotate VPN left by FOV_X/2 degrees |
||
788 | RotatePointAroundVector( frustum[1].normal, vup, vpn, 90-r_refdef.fov_x / 2 ); |
||
789 | // rotate VPN up by FOV_X/2 degrees |
||
790 | RotatePointAroundVector( frustum[2].normal, vright, vpn, 90-r_refdef.fov_y / 2 ); |
||
791 | // rotate VPN down by FOV_X/2 degrees |
||
792 | RotatePointAroundVector( frustum[3].normal, vright, vpn, -( 90 - r_refdef.fov_y / 2 ) ); |
||
793 | } |
||
794 | |||
795 | for (i=0 ; i<4 ; i++) |
||
796 | { |
||
797 | frustum[i].type = PLANE_ANYZ; |
||
798 | frustum[i].dist = DotProduct (r_origin, frustum[i].normal); |
||
799 | frustum[i].signbits = SignbitsForPlane (&frustum[i]); |
||
800 | } |
||
801 | } |
||
802 | |||
803 | |||
804 | |||
805 | /* |
||
806 | =============== |
||
807 | R_SetupFrame |
||
808 | =============== |
||
809 | */ |
||
810 | void R_SetupFrame (void) |
||
811 | { |
||
812 | int edgecount; |
||
813 | vrect_t vrect; |
||
814 | float w, h; |
||
815 | |||
816 | // don't allow cheats in multiplayer |
||
817 | if (cl.maxclients > 1) |
||
818 | Cvar_Set ("r_fullbright", "0"); |
||
819 | |||
820 | R_AnimateLight (); |
||
821 | |||
822 | r_framecount++; |
||
823 | |||
824 | // build the transformation matrix for the given view angles |
||
825 | VectorCopy (r_refdef.vieworg, r_origin); |
||
826 | |||
827 | AngleVectors (r_refdef.viewangles, vpn, vright, vup); |
||
828 | |||
829 | // current viewleaf |
||
830 | r_oldviewleaf = r_viewleaf; |
||
831 | r_viewleaf = Mod_PointInLeaf (r_origin, cl.worldmodel); |
||
832 | |||
833 | V_SetContentsColor (r_viewleaf->contents); |
||
834 | V_CalcBlend (); |
||
835 | |||
836 | r_cache_thrash = false; |
||
837 | |||
838 | c_brush_polys = 0; |
||
839 | c_alias_polys = 0; |
||
840 | |||
841 | } |
||
842 | |||
843 | |||
844 | void MYgluPerspective( GLdouble fovy, GLdouble aspect, |
||
845 | GLdouble zNear, GLdouble zFar ) |
||
846 | { |
||
847 | GLdouble xmin, xmax, ymin, ymax; |
||
848 | |||
849 | ymax = zNear * tan( fovy * M_PI / 360.0 ); |
||
850 | ymin = -ymax; |
||
851 | |||
852 | xmin = ymin * aspect; |
||
853 | xmax = ymax * aspect; |
||
854 | |||
855 | glFrustum( xmin, xmax, ymin, ymax, zNear, zFar ); |
||
856 | } |
||
857 | |||
858 | |||
859 | /* |
||
860 | ============= |
||
861 | R_SetupGL |
||
862 | ============= |
||
863 | */ |
||
864 | void R_SetupGL (void) |
||
865 | { |
||
866 | float screenaspect; |
||
867 | float yfov; |
||
868 | int i; |
||
869 | extern int glwidth, glheight; |
||
870 | int x, x2, y2, y, w, h; |
||
871 | |||
872 | // |
||
873 | // set up viewpoint |
||
874 | // |
||
875 | glMatrixMode(GL_PROJECTION); |
||
876 | glLoadIdentity (); |
||
877 | x = r_refdef.vrect.x * glwidth/vid.width; |
||
878 | x2 = (r_refdef.vrect.x + r_refdef.vrect.width) * glwidth/vid.width; |
||
879 | y = (vid.height-r_refdef.vrect.y) * glheight/vid.height; |
||
880 | y2 = (vid.height - (r_refdef.vrect.y + r_refdef.vrect.height)) * glheight/vid.height; |
||
881 | |||
882 | // fudge around because of frac screen scale |
||
883 | if (x > 0) |
||
884 | x--; |
||
885 | if (x2 < glwidth) |
||
886 | x2++; |
||
887 | if (y2 < 0) |
||
888 | y2--; |
||
889 | if (y < glheight) |
||
890 | y++; |
||
891 | |||
892 | w = x2 - x; |
||
893 | h = y - y2; |
||
894 | |||
895 | if (envmap) |
||
896 | { |
||
897 | x = y2 = 0; |
||
898 | w = h = 256; |
||
899 | } |
||
900 | |||
901 | glViewport (glx + x, gly + y2, w, h); |
||
902 | screenaspect = (float)r_refdef.vrect.width/r_refdef.vrect.height; |
||
903 | // yfov = 2*atan((float)r_refdef.vrect.height/r_refdef.vrect.width)*180/M_PI; |
||
904 | MYgluPerspective (r_refdef.fov_y, screenaspect, 4, 4096); |
||
905 | |||
906 | if (mirror) |
||
907 | { |
||
908 | if (mirror_plane->normal[2]) |
||
909 | glScalef (1, -1, 1); |
||
910 | else |
||
911 | glScalef (-1, 1, 1); |
||
912 | glCullFace(GL_BACK); |
||
913 | } |
||
914 | else |
||
915 | glCullFace(GL_FRONT); |
||
916 | |||
917 | glMatrixMode(GL_MODELVIEW); |
||
918 | glLoadIdentity (); |
||
919 | |||
920 | glRotatef (-90, 1, 0, 0); // put Z going up |
||
921 | glRotatef (90, 0, 0, 1); // put Z going up |
||
922 | glRotatef (-r_refdef.viewangles[2], 1, 0, 0); |
||
923 | glRotatef (-r_refdef.viewangles[0], 0, 1, 0); |
||
924 | glRotatef (-r_refdef.viewangles[1], 0, 0, 1); |
||
925 | glTranslatef (-r_refdef.vieworg[0], -r_refdef.vieworg[1], -r_refdef.vieworg[2]); |
||
926 | |||
927 | glGetFloatv (GL_MODELVIEW_MATRIX, r_world_matrix); |
||
928 | |||
929 | // |
||
930 | // set drawing parms |
||
931 | // |
||
932 | if (gl_cull.value) |
||
933 | glEnable(GL_CULL_FACE); |
||
934 | else |
||
935 | glDisable(GL_CULL_FACE); |
||
936 | |||
937 | glDisable(GL_BLEND); |
||
938 | glDisable(GL_ALPHA_TEST); |
||
939 | glEnable(GL_DEPTH_TEST); |
||
940 | } |
||
941 | |||
942 | /* |
||
943 | ================ |
||
944 | R_RenderScene |
||
945 | |||
946 | r_refdef must be set before the first call |
||
947 | ================ |
||
948 | */ |
||
949 | void R_RenderScene (void) |
||
950 | { |
||
951 | R_SetupFrame (); |
||
952 | |||
953 | R_SetFrustum (); |
||
954 | |||
955 | R_SetupGL (); |
||
956 | |||
957 | R_MarkLeaves (); // done here so we know if we're in water |
||
958 | |||
959 | R_DrawWorld (); // adds static entities to the list |
||
960 | |||
961 | S_ExtraUpdate (); // don't let sound get messed up if going slow |
||
962 | |||
963 | R_DrawEntitiesOnList (); |
||
964 | |||
965 | GL_DisableMultitexture(); |
||
966 | |||
967 | R_RenderDlights (); |
||
968 | |||
969 | R_DrawParticles (); |
||
970 | |||
971 | #ifdef GLTEST |
||
972 | Test_Draw (); |
||
973 | #endif |
||
974 | |||
975 | } |
||
976 | |||
977 | |||
978 | /* |
||
979 | ============= |
||
980 | R_Clear |
||
981 | ============= |
||
982 | */ |
||
983 | void R_Clear (void) |
||
984 | { |
||
985 | if (r_mirroralpha.value != 1.0) |
||
986 | { |
||
987 | if (gl_clear.value) |
||
988 | glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
||
989 | else |
||
990 | glClear (GL_DEPTH_BUFFER_BIT); |
||
991 | gldepthmin = 0; |
||
992 | gldepthmax = 0.5; |
||
993 | glDepthFunc (GL_LEQUAL); |
||
994 | } |
||
995 | else if (gl_ztrick.value) |
||
996 | { |
||
997 | static int trickframe; |
||
998 | |||
999 | if (gl_clear.value) |
||
1000 | glClear (GL_COLOR_BUFFER_BIT); |
||
1001 | |||
1002 | trickframe++; |
||
1003 | if (trickframe & 1) |
||
1004 | { |
||
1005 | gldepthmin = 0; |
||
1006 | gldepthmax = 0.49999; |
||
1007 | glDepthFunc (GL_LEQUAL); |
||
1008 | } |
||
1009 | else |
||
1010 | { |
||
1011 | gldepthmin = 1; |
||
1012 | gldepthmax = 0.5; |
||
1013 | glDepthFunc (GL_GEQUAL); |
||
1014 | } |
||
1015 | } |
||
1016 | else |
||
1017 | { |
||
1018 | if (gl_clear.value) |
||
1019 | glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
||
1020 | else |
||
1021 | glClear (GL_DEPTH_BUFFER_BIT); |
||
1022 | gldepthmin = 0; |
||
1023 | gldepthmax = 1; |
||
1024 | glDepthFunc (GL_LEQUAL); |
||
1025 | } |
||
1026 | |||
1027 | glDepthRange (gldepthmin, gldepthmax); |
||
1028 | } |
||
1029 | |||
1030 | /* |
||
1031 | ============= |
||
1032 | R_Mirror |
||
1033 | ============= |
||
1034 | */ |
||
1035 | void R_Mirror (void) |
||
1036 | { |
||
1037 | float d; |
||
1038 | msurface_t *s; |
||
1039 | entity_t *ent; |
||
1040 | |||
1041 | if (!mirror) |
||
1042 | return; |
||
1043 | |||
1044 | memcpy (r_base_world_matrix, r_world_matrix, sizeof(r_base_world_matrix)); |
||
1045 | |||
1046 | d = DotProduct (r_refdef.vieworg, mirror_plane->normal) - mirror_plane->dist; |
||
1047 | VectorMA (r_refdef.vieworg, -2*d, mirror_plane->normal, r_refdef.vieworg); |
||
1048 | |||
1049 | d = DotProduct (vpn, mirror_plane->normal); |
||
1050 | VectorMA (vpn, -2*d, mirror_plane->normal, vpn); |
||
1051 | |||
1052 | r_refdef.viewangles[0] = -asin (vpn[2])/M_PI*180; |
||
1053 | r_refdef.viewangles[1] = atan2 (vpn[1], vpn[0])/M_PI*180; |
||
1054 | r_refdef.viewangles[2] = -r_refdef.viewangles[2]; |
||
1055 | |||
1056 | ent = &cl_entities[cl.viewentity]; |
||
1057 | if (cl_numvisedicts < MAX_VISEDICTS) |
||
1058 | { |
||
1059 | cl_visedicts[cl_numvisedicts] = ent; |
||
1060 | cl_numvisedicts++; |
||
1061 | } |
||
1062 | |||
1063 | gldepthmin = 0.5; |
||
1064 | gldepthmax = 1; |
||
1065 | glDepthRange (gldepthmin, gldepthmax); |
||
1066 | glDepthFunc (GL_LEQUAL); |
||
1067 | |||
1068 | R_RenderScene (); |
||
1069 | R_DrawWaterSurfaces (); |
||
1070 | |||
1071 | gldepthmin = 0; |
||
1072 | gldepthmax = 0.5; |
||
1073 | glDepthRange (gldepthmin, gldepthmax); |
||
1074 | glDepthFunc (GL_LEQUAL); |
||
1075 | |||
1076 | // blend on top |
||
1077 | glEnable (GL_BLEND); |
||
1078 | glMatrixMode(GL_PROJECTION); |
||
1079 | if (mirror_plane->normal[2]) |
||
1080 | glScalef (1,-1,1); |
||
1081 | else |
||
1082 | glScalef (-1,1,1); |
||
1083 | glCullFace(GL_FRONT); |
||
1084 | glMatrixMode(GL_MODELVIEW); |
||
1085 | |||
1086 | glLoadMatrixf (r_base_world_matrix); |
||
1087 | |||
1088 | glColor4f (1,1,1,r_mirroralpha.value); |
||
1089 | s = cl.worldmodel->textures[mirrortexturenum]->texturechain; |
||
1090 | for ( ; s ; s=s->texturechain) |
||
1091 | R_RenderBrushPoly (s); |
||
1092 | cl.worldmodel->textures[mirrortexturenum]->texturechain = NULL; |
||
1093 | glDisable (GL_BLEND); |
||
1094 | glColor4f (1,1,1,1); |
||
1095 | } |
||
1096 | |||
1097 | /* |
||
1098 | ================ |
||
1099 | R_RenderView |
||
1100 | |||
1101 | r_refdef must be set before the first call |
||
1102 | ================ |
||
1103 | */ |
||
1104 | void R_RenderView (void) |
||
1105 | { |
||
1106 | double time1, time2; |
||
1107 | GLfloat colors[4] = {(GLfloat) 0.0, (GLfloat) 0.0, (GLfloat) 1, (GLfloat) 0.20}; |
||
1108 | |||
1109 | if (r_norefresh.value) |
||
1110 | return; |
||
1111 | |||
1112 | if (!r_worldentity.model || !cl.worldmodel) |
||
1113 | Sys_Error ("R_RenderView: NULL worldmodel"); |
||
1114 | |||
1115 | if (r_speeds.value) |
||
1116 | { |
||
1117 | glFinish (); |
||
1118 | time1 = Sys_FloatTime (); |
||
1119 | c_brush_polys = 0; |
||
1120 | c_alias_polys = 0; |
||
1121 | } |
||
1122 | |||
1123 | mirror = false; |
||
1124 | |||
1125 | if (gl_finish.value) |
||
1126 | glFinish (); |
||
1127 | |||
1128 | R_Clear (); |
||
1129 | |||
1130 | // render normal view |
||
1131 | |||
1132 | /***** Experimental silly looking fog ****** |
||
1133 | ****** Use r_fullbright if you enable ****** |
||
1134 | glFogi(GL_FOG_MODE, GL_LINEAR); |
||
1135 | glFogfv(GL_FOG_COLOR, colors); |
||
1136 | glFogf(GL_FOG_END, 512.0); |
||
1137 | glEnable(GL_FOG); |
||
1138 | ********************************************/ |
||
1139 | |||
1140 | R_RenderScene (); |
||
1141 | R_DrawViewModel (); |
||
1142 | R_DrawWaterSurfaces (); |
||
1143 | |||
1144 | // More fog right here :) |
||
1145 | // glDisable(GL_FOG); |
||
1146 | // End of all fog code... |
||
1147 | |||
1148 | // render mirror view |
||
1149 | R_Mirror (); |
||
1150 | |||
1151 | R_PolyBlend (); |
||
1152 | |||
1153 | if (r_speeds.value) |
||
1154 | { |
||
1155 | // glFinish (); |
||
1156 | time2 = Sys_FloatTime (); |
||
1157 | Con_Printf ("%3i ms %4i wpoly %4i epoly\n", (int)((time2-time1)*1000), c_brush_polys, c_alias_polys); |
||
1158 | } |
||
1159 | }>>>>4> |