1 /*
2 	gl_mod_alias.c
3 
4 	Draw Alias Model
5 
6 	Copyright (C) 1996-1997  Id Software, Inc.
7 
8 	This program is free software; you can redistribute it and/or
9 	modify it under the terms of the GNU General Public License
10 	as published by the Free Software Foundation; either version 2
11 	of the License, or (at your option) any later version.
12 
13 	This program is distributed in the hope that it will be useful,
14 	but WITHOUT ANY WARRANTY; without even the implied warranty of
15 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 
17 	See the GNU General Public License for more details.
18 
19 	You should have received a copy of the GNU General Public License
20 	along with this program; if not, write to:
21 
22 		Free Software Foundation, Inc.
23 		59 Temple Place - Suite 330
24 		Boston, MA  02111-1307, USA
25 
26 */
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30 
31 #define NH_DEFINE
32 #include "namehack.h"
33 
34 #ifdef HAVE_STRING_H
35 # include <string.h>
36 #endif
37 #ifdef HAVE_STRINGS_H
38 # include <strings.h>
39 #endif
40 
41 #include <math.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 
45 #include "QF/cvar.h"
46 #include "QF/locs.h"
47 #include "QF/mathlib.h"
48 #include "QF/qargs.h"
49 #include "QF/render.h"
50 #include "QF/skin.h"
51 #include "QF/sound.h"
52 #include "QF/sys.h"
53 #include "QF/vid.h"
54 #include "QF/GL/defines.h"
55 #include "QF/GL/funcs.h"
56 #include "QF/GL/qf_rlight.h"
57 #include "QF/GL/qf_rmain.h"
58 #include "QF/GL/qf_rsurf.h"
59 #include "QF/GL/qf_vid.h"
60 
61 #include "compat.h"
62 #include "r_internal.h"
63 
64 typedef struct {
65 	vec3_t      normal;
66 	vec3_t      vert;
67 } blended_vert_t;
68 
69 typedef struct {
70 	blended_vert_t *verts;
71 	int        *order;
72 	tex_coord_t *tex_coord;
73 	int         count;
74 } vert_order_t;
75 
76 static vec3_t		shadevector;
77 
78 
79 static void
GL_DrawAliasFrameTri(vert_order_t * vo)80 GL_DrawAliasFrameTri (vert_order_t *vo)
81 {
82 	int         count = vo->count;
83 	blended_vert_t *verts = vo->verts;
84 	tex_coord_t *tex_coord = vo->tex_coord;
85 
86 	qfglBegin (GL_TRIANGLES);
87 	do {
88 		// texture coordinates come from the draw list
89 		qfglTexCoord2fv (tex_coord->st);
90 		tex_coord++;
91 
92 		// normals and vertices come from the frame list
93 		qfglNormal3fv (verts->normal);
94 		qfglVertex3fv (verts->vert);
95 		verts++;
96 	} while (count--);
97 	qfglEnd ();
98 }
99 
100 static inline void
GL_DrawAliasFrameTriMulti(vert_order_t * vo)101 GL_DrawAliasFrameTriMulti (vert_order_t *vo)
102 {
103 	int         count = vo->count;
104 	blended_vert_t *verts = vo->verts;
105 	tex_coord_t *tex_coord = vo->tex_coord;
106 
107 	qfglBegin (GL_TRIANGLES);
108 	do {
109 		// texture coordinates come from the draw list
110 		qglMultiTexCoord2fv (gl_mtex_enum + 0, tex_coord->st);
111 		qglMultiTexCoord2fv (gl_mtex_enum + 1, tex_coord->st);
112 		tex_coord++;
113 
114 		// normals and vertices come from the frame list
115 		qfglNormal3fv (verts->normal);
116 		qfglVertex3fv (verts->vert);
117 		verts++;
118 	} while (--count);
119 	qfglEnd ();
120 }
121 
122 static void
GL_DrawAliasFrame(vert_order_t * vo)123 GL_DrawAliasFrame (vert_order_t *vo)
124 {
125 	int         count;
126 	int        *order = vo->order;
127 	blended_vert_t *verts = vo->verts;
128 
129 	while ((count = *order++)) {
130 		// get the vertex count and primitive type
131 		if (count < 0) {
132 			count = -count;
133 			qfglBegin (GL_TRIANGLE_FAN);
134 		} else {
135 			qfglBegin (GL_TRIANGLE_STRIP);
136 		}
137 
138 		do {
139 			// texture coordinates come from the draw list
140 			qfglTexCoord2fv ((float *) order);
141 			order += 2;
142 
143 			// normals and vertices come from the frame list
144 			qfglNormal3fv (verts->normal);
145 			qfglVertex3fv (verts->vert);
146 			verts++;
147 		} while (--count);
148 
149 		qfglEnd ();
150 	}
151 }
152 
153 static inline void
GL_DrawAliasFrameMulti(vert_order_t * vo)154 GL_DrawAliasFrameMulti (vert_order_t *vo)
155 {
156 	int         count;
157 	int        *order = vo->order;
158 	blended_vert_t *verts = vo->verts;
159 
160 	while ((count = *order++)) {
161 		// get the vertex count and primitive type
162 		if (count < 0) {
163 			count = -count;
164 			qfglBegin (GL_TRIANGLE_FAN);
165 		} else {
166 			qfglBegin (GL_TRIANGLE_STRIP);
167 		}
168 
169 		do {
170 			// texture coordinates come from the draw list
171 			qglMultiTexCoord2fv (gl_mtex_enum + 0, (float *) order);
172 			qglMultiTexCoord2fv (gl_mtex_enum + 1, (float *) order);
173 			order += 2;
174 
175 			// normals and vertices come from the frame list
176 			qfglNormal3fv (verts->normal);
177 			qfglVertex3fv (verts->vert);
178 			verts++;
179 		} while (--count);
180 
181 		qfglEnd ();
182 	}
183 }
184 
185 /*
186 	GL_DrawAliasShadowTri
187 
188 	Standard shadow drawing (triangles version)
189 */
190 static void
GL_DrawAliasShadowTri(const aliashdr_t * paliashdr,const vert_order_t * vo)191 GL_DrawAliasShadowTri (const aliashdr_t *paliashdr, const vert_order_t *vo)
192 {
193 	int         count = vo->count;;
194 	const blended_vert_t *verts = vo->verts;
195 	float       height, lheight;
196 	vec3_t      point;
197 	const vec_t *scale = paliashdr->mdl.scale;
198 	const vec_t *scale_origin = paliashdr->mdl.scale_origin;
199 
200 	lheight = currententity->origin[2] - lightspot[2];
201 	height = -lheight + 1.0;
202 
203 	qfglBegin (GL_TRIANGLES);
204 
205 	do {
206 		// normals and vertices come from the frame list
207 		point[0] = verts->vert[0] * scale[0] + scale_origin[0];
208 		point[1] = verts->vert[1] * scale[1] + scale_origin[1];
209 		point[2] = verts->vert[2] * scale[2] + scale_origin[2] + lheight;
210 
211 		point[0] -= shadevector[0] * point[2];
212 		point[1] -= shadevector[1] * point[2];
213 		point[2] = height;
214 		qfglVertex3fv (point);
215 
216 		verts++;
217 	} while (--count);
218 
219 	qfglEnd ();
220 }
221 
222 /*
223 	GL_DrawAliasShadow
224 
225 	Standard shadow drawing
226 */
227 static void
GL_DrawAliasShadow(const aliashdr_t * paliashdr,const vert_order_t * vo)228 GL_DrawAliasShadow (const aliashdr_t *paliashdr, const vert_order_t *vo)
229 {
230 	float       height, lheight;
231 	int         count;
232 	const int  *order = vo->order;
233 	vec3_t      point;
234 	const blended_vert_t *verts = vo->verts;
235 
236 	lheight = currententity->origin[2] - lightspot[2];
237 	height = -lheight + 1.0;
238 
239 	while ((count = *order++)) {
240 		// get the vertex count and primitive type
241 		if (count < 0) {
242 			count = -count;
243 			qfglBegin (GL_TRIANGLE_FAN);
244 		} else
245 			qfglBegin (GL_TRIANGLE_STRIP);
246 
247 		order += 2 * count;		// skip texture coords
248 		do {
249 			// normals and vertices come from the frame list
250 			point[0] =
251 				verts->vert[0] * paliashdr->mdl.scale[0] +
252 				paliashdr->mdl.scale_origin[0];
253 			point[1] =
254 				verts->vert[1] * paliashdr->mdl.scale[1] +
255 				paliashdr->mdl.scale_origin[1];
256 			point[2] =
257 				verts->vert[2] * paliashdr->mdl.scale[2] +
258 				paliashdr->mdl.scale_origin[2] + lheight;
259 
260 			point[0] -= shadevector[0] * point[2];
261 			point[1] -= shadevector[1] * point[2];
262 			point[2] = height;
263 			qfglVertex3fv (point);
264 
265 			verts++;
266 		} while (--count);
267 
268 		qfglEnd ();
269 	}
270 }
271 
272 static inline vert_order_t *
GL_GetAliasFrameVerts16(aliashdr_t * paliashdr,entity_t * e)273 GL_GetAliasFrameVerts16 (aliashdr_t *paliashdr, entity_t *e)
274 {
275 	float         blend;
276 	int           count, i;
277 	trivertx16_t *verts;
278 	vert_order_t *vo;
279 	blended_vert_t *vo_v;
280 
281 	blend = R_AliasGetLerpedFrames (e, paliashdr);
282 
283 	verts = (trivertx16_t *) ((byte *) paliashdr + paliashdr->posedata);
284 
285 	count = paliashdr->poseverts;
286 	vo = Hunk_TempAlloc (sizeof (*vo) + count * sizeof (blended_vert_t));
287 	vo->order = (int *) ((byte *) paliashdr + paliashdr->commands);
288 	vo->verts = (blended_vert_t *) &vo[1];
289 	if (paliashdr->tex_coord) {
290 		vo->tex_coord = (tex_coord_t *) ((byte *) paliashdr
291 										 + paliashdr->tex_coord);
292 	} else {
293 		vo->tex_coord = NULL;
294 	}
295 	vo->count = count;
296 
297 	if (!gl_lerp_anim->int_val)
298 		blend = 1.0;
299 
300 
301 	if (blend == 0.0) {
302 		verts = verts + e->pose1 * count;
303 	} else if (blend == 1.0) {
304 		verts = verts + e->pose2 * count;
305 	} else {
306 		trivertx16_t *verts1, *verts2;
307 
308 		verts1 = verts + e->pose1 * count;
309 		verts2 = verts + e->pose2 * count;
310 
311 		for (i = 0, vo_v = vo->verts; i < count;
312 			 i++, vo_v++, verts1++, verts2++) {
313 			float      *n1, *n2;
314 
315 			VectorBlend (verts1->v, verts2->v, blend, vo_v->vert);
316 			n1 = r_avertexnormals[verts1->lightnormalindex];
317 			n2 = r_avertexnormals[verts2->lightnormalindex];
318 			VectorBlend (n1, n2, blend, vo_v->normal);
319 			if (VectorIsZero (vo_v->normal)) {
320 				if (blend < 0.5) {
321 					VectorCopy (n1, vo_v->normal);
322 				} else {
323 					VectorCopy (n2, vo_v->normal);
324 				}
325 			}
326 		}
327 		return vo;
328 	}
329 
330 	for (i = 0, vo_v = vo->verts; i < count; i++, vo_v++, verts++) {
331 		VectorCopy (verts->v, vo_v->vert);
332 		VectorCopy (r_avertexnormals[verts->lightnormalindex], vo_v->normal);
333 	}
334 	return vo;
335 }
336 
337 static inline vert_order_t *
GL_GetAliasFrameVerts(aliashdr_t * paliashdr,entity_t * e)338 GL_GetAliasFrameVerts (aliashdr_t *paliashdr, entity_t *e)
339 {
340 	float       blend;
341 	int         count, i;
342 	trivertx_t *verts;
343 	vert_order_t *vo;
344 	blended_vert_t *vo_v;
345 
346 	blend = R_AliasGetLerpedFrames (e, paliashdr);
347 
348 	verts = (trivertx_t *) ((byte *) paliashdr + paliashdr->posedata);
349 
350 	count = paliashdr->poseverts;
351 	vo = Hunk_TempAlloc (sizeof (*vo) + count * sizeof (blended_vert_t));
352 	vo->order = (int *) ((byte *) paliashdr + paliashdr->commands);
353 	vo->verts = (blended_vert_t *) &vo[1];
354 	if (paliashdr->tex_coord) {
355 		vo->tex_coord = (tex_coord_t *) ((byte *) paliashdr + paliashdr->tex_coord);
356 	} else {
357 		vo->tex_coord = NULL;
358 	}
359 	vo->count = count;
360 
361 	if (!gl_lerp_anim->int_val)
362 		blend = 1.0;
363 
364 	if (blend == 0.0) {
365 		verts = verts + e->pose1 * count;
366 	} else if (blend == 1.0) {
367 		verts = verts + e->pose2 * count;
368 	} else {
369 		trivertx_t *verts1, *verts2;
370 
371 		verts1 = verts + e->pose1 * count;
372 		verts2 = verts + e->pose2 * count;
373 
374 		for (i = 0, vo_v = vo->verts; i < count;
375 			 i++, vo_v++, verts1++, verts2++) {
376 			float      *n1, *n2;
377 
378 			VectorBlend (verts1->v, verts2->v, blend, vo_v->vert);
379 			n1 = r_avertexnormals[verts1->lightnormalindex];
380 			n2 = r_avertexnormals[verts2->lightnormalindex];
381 			VectorBlend (n1, n2, blend, vo_v->normal);
382 			if (VectorIsZero (vo_v->normal)) {
383 				if (blend < 0.5) {
384 					VectorCopy (n1, vo_v->normal);
385 				} else {
386 					VectorCopy (n2, vo_v->normal);
387 				}
388 			}
389 		}
390 		return vo;
391 	}
392 
393 	for (i = 0, vo_v = vo->verts; i < count; i++, vo_v++, verts++) {
394 		VectorCopy (verts->v, vo_v->vert);
395 		VectorCopy (r_avertexnormals[verts->lightnormalindex], vo_v->normal);
396 	}
397 	return vo;
398 }
399 
400 void
gl_R_DrawAliasModel(entity_t * e)401 gl_R_DrawAliasModel (entity_t *e)
402 {
403 	float       radius, minlight, d;
404 	float       position[4] = {0.0, 0.0, 0.0, 1.0},
405 				color[4] = {0.0, 0.0, 0.0, 1.0},
406 				dark[4] = {0.0, 0.0, 0.0, 1.0},
407 				emission[4] = {0.0, 0.0, 0.0, 1.0};
408 	int         gl_light, texture;
409 	int         fb_texture = 0, used_lights = 0;
410 	qboolean    is_fullbright = false;
411 	unsigned    lnum;
412 	aliashdr_t *paliashdr;
413 	dlight_t   *l;
414 	model_t    *model;
415 	vec3_t      dist, scale;
416 	vert_order_t *vo;
417 
418 	model = e->model;
419 
420 	radius = model->radius;
421 	if (e->scale != 1.0)
422 		radius *= e->scale;
423 	if (R_CullSphere (e->origin, radius))
424 		return;
425 
426 	VectorSubtract (r_origin, e->origin, modelorg);
427 
428 	gl_modelalpha = e->colormod[3];
429 
430 	is_fullbright = (model->fullbright || e->fullbright);
431 	minlight = max (model->min_light, e->min_light);
432 
433 	qfglColor4fv (e->colormod);
434 
435 	if (!is_fullbright) {
436 		float lightadj;
437 
438 		// get lighting information
439 		R_LightPoint (e->origin);
440 
441 		lightadj = (ambientcolor[0] + ambientcolor[1] + ambientcolor[2]) / 765.0;
442 
443 		// Do minlight stuff here since that's how software does it :)
444 
445 		if (lightadj > 0) {
446 			if (lightadj < minlight)
447 				lightadj = minlight / lightadj;
448 			else
449 				lightadj = 1.0;
450 
451 			// 255 is fullbright
452 			VectorScale (ambientcolor, lightadj / 255.0, ambientcolor);
453 		} else {
454 			ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = minlight;
455 		}
456 
457 		if (gl_vector_light->int_val) {
458 			for (l = r_dlights, lnum = 0; lnum < r_maxdlights; lnum++, l++) {
459 				if (l->die >= vr_data.realtime) {
460 					VectorSubtract (l->origin, e->origin, dist);
461 					if ((d = DotProduct (dist, dist)) >	// Out of range
462 						((l->radius + radius) * (l->radius + radius))) {
463 						continue;
464 					}
465 
466 
467 					if (used_lights >= gl_max_lights) {
468 						// For solid lighting, multiply by 0.5 since it's cos
469 						// 60 and 60 is a good guesstimate at the average
470 						// incident angle. Seems to match vector lighting
471 						// best, too.
472 						VectorMultAdd (emission,
473 							0.5 / ((d * 0.01 / l->radius) + 0.5),
474 							l->color, emission);
475 						continue;
476 					}
477 
478 					VectorCopy (l->origin, position);
479 
480 					VectorCopy (l->color, color);
481 					color[3] = 1.0;
482 
483 					gl_light = GL_LIGHT0 + used_lights;
484 					qfglEnable (gl_light);
485 					qfglLightfv (gl_light, GL_POSITION, position);
486 					qfglLightfv (gl_light, GL_AMBIENT, color);
487 					qfglLightfv (gl_light, GL_DIFFUSE, color);
488 					qfglLightfv (gl_light, GL_SPECULAR, color);
489 					// 0.01 is used here because it just seemed to match
490 					// the bmodel lighting best. it's over r instead of r*r
491 					// so that larger-radiused lights will be brighter
492 					qfglLightf (gl_light, GL_QUADRATIC_ATTENUATION,
493 								0.01 / (l->radius));
494 					used_lights++;
495 				}
496 			}
497 
498 			VectorAdd (ambientcolor, emission, emission);
499 			d = max (emission[0], max (emission[1], emission[2]));
500 			// 1.5 to allow some pastelization (curb darkness from dlight)
501 			if (d > 1.5) {
502 				VectorScale (emission, 1.5 / d, emission);
503 			}
504 
505 			qfglMaterialfv (GL_FRONT, GL_EMISSION, emission);
506 		} else {
507 			VectorCopy (ambientcolor, emission);
508 
509 			for (l = r_dlights, lnum = 0; lnum < r_maxdlights; lnum++, l++) {
510 				if (l->die >= vr_data.realtime) {
511 					VectorSubtract (l->origin, e->origin, dist);
512 
513 					if ((d = DotProduct (dist, dist)) > (l->radius + radius) *
514 						(l->radius + radius)) {
515 							continue;
516 					}
517 
518 					// For solid lighting, multiply by 0.5 since it's cos 60
519 					// and 60 is a good guesstimate at the average incident
520 					// angle. Seems to match vector lighting best, too.
521 					VectorMultAdd (emission,
522 						(0.5 / ((d * 0.01 / l->radius) + 0.5)),
523 						l->color, emission);
524 				}
525 			}
526 
527 			d = max (emission[0], max (emission[1], emission[2]));
528 			// 1.5 to allow some fading (curb emission making stuff dark)
529 			if (d > 1.5) {
530 				VectorScale (emission, 1.5 / d, emission);
531 			}
532 
533 			emission[0] *= e->colormod[0];
534 			emission[1] *= e->colormod[1];
535 			emission[2] *= e->colormod[2];
536 			emission[3] *= e->colormod[3];
537 
538 			qfglColor4fv (emission);
539 		}
540 	}
541 
542 	// locate the proper data
543 	if (!(paliashdr = e->model->aliashdr))
544 		paliashdr = Cache_Get (&e->model->cache);
545 	gl_c_alias_polys += paliashdr->mdl.numtris;
546 
547 	// if the model has a colorised/external skin, use it, otherwise use
548 	// the skin embedded in the model data
549 	if (e->skin && e->skin->texnum && !gl_nocolors->int_val) {
550 		skin_t *skin = e->skin;
551 
552 		texture = skin->texnum;
553 		if (gl_fb_models->int_val) {
554 			fb_texture = skin->auxtex;
555 		}
556 	} else {
557 		maliasskindesc_t *skindesc;
558 
559 		skindesc = R_AliasGetSkindesc (e->skinnum, paliashdr);
560 		texture = skindesc->texnum;
561 		if (gl_fb_models->int_val && !is_fullbright)
562 			fb_texture = skindesc->fb_texnum;
563 	}
564 
565 	if (paliashdr->mdl.ident == HEADER_MDL16) {
566 		// because we multipled by 256 when we loaded the verts, we have to
567 		// scale by 1/256 when drawing.
568 		VectorScale (paliashdr->mdl.scale, e->scale / 256.0, scale);
569 		vo = GL_GetAliasFrameVerts16 (paliashdr, e);
570 	} else {
571 		VectorScale (paliashdr->mdl.scale, e->scale, scale);
572 		vo = GL_GetAliasFrameVerts (paliashdr, e);
573 	}
574 
575 	// setup the transform
576 	qfglPushMatrix ();
577 	gl_R_RotateForEntity (e);
578 
579 	qfglTranslatef (paliashdr->mdl.scale_origin[0],
580 					paliashdr->mdl.scale_origin[1],
581 					paliashdr->mdl.scale_origin[2]);
582 	qfglScalef (scale[0], scale[1], scale[2]);
583 
584 	if (gl_modelalpha < 1.0)
585 		qfglDepthMask (GL_FALSE);
586 
587 	// draw all the triangles
588 	if (is_fullbright) {
589 		qfglBindTexture (GL_TEXTURE_2D, texture);
590 
591 		if (gl_vector_light->int_val) {
592 			qfglDisable (GL_LIGHTING);
593 			if (!gl_tess)
594 				qfglDisable (GL_NORMALIZE);
595 		}
596 
597 		if (vo->tex_coord)
598 			GL_DrawAliasFrameTri (vo);
599 		else
600 			GL_DrawAliasFrame (vo);
601 
602 		if (gl_vector_light->int_val) {
603 			if (!gl_tess)
604 				qfglEnable (GL_NORMALIZE);
605 			qfglEnable (GL_LIGHTING);
606 		}
607 	} else if (!fb_texture) {
608 		// Model has no fullbrights, don't bother with multi
609 		qfglBindTexture (GL_TEXTURE_2D, texture);
610 		if (vo->tex_coord)
611 			GL_DrawAliasFrameTri (vo);
612 		else
613 			GL_DrawAliasFrame (vo);
614 	} else {	// try multitexture
615 		if (gl_mtex_active_tmus >= 2) {	// set up the textures
616 			qglActiveTexture (gl_mtex_enum + 0);
617 			qfglBindTexture (GL_TEXTURE_2D, texture);
618 
619 			qglActiveTexture (gl_mtex_enum + 1);
620 			qfglEnable (GL_TEXTURE_2D);
621 			qfglBindTexture (GL_TEXTURE_2D, fb_texture);
622 
623 			// do the heavy lifting
624 			if (vo->tex_coord)
625 				GL_DrawAliasFrameTriMulti (vo);
626 			else
627 				GL_DrawAliasFrameMulti (vo);
628 
629 			// restore the settings
630 			qfglDisable (GL_TEXTURE_2D);
631 			qglActiveTexture (gl_mtex_enum + 0);
632 		} else {
633 			if (vo->tex_coord) {
634 				qfglBindTexture (GL_TEXTURE_2D, texture);
635 				GL_DrawAliasFrameTri (vo);
636 
637 				if (gl_vector_light->int_val) {
638 					qfglDisable (GL_LIGHTING);
639 					if (!gl_tess)
640 						qfglDisable (GL_NORMALIZE);
641 				}
642 
643 				qfglColor4fv (e->colormod);
644 
645 				qfglBindTexture (GL_TEXTURE_2D, fb_texture);
646 				GL_DrawAliasFrameTri (vo);
647 
648 				if (gl_vector_light->int_val) {
649 					qfglEnable (GL_LIGHTING);
650 					if (!gl_tess)
651 						qfglEnable (GL_NORMALIZE);
652 				}
653 			} else {
654 				qfglBindTexture (GL_TEXTURE_2D, texture);
655 				GL_DrawAliasFrame (vo);
656 
657 				if (gl_vector_light->int_val) {
658 					qfglDisable (GL_LIGHTING);
659 					if (!gl_tess)
660 						qfglDisable (GL_NORMALIZE);
661 				}
662 
663 				qfglColor4fv (e->colormod);
664 
665 				qfglBindTexture (GL_TEXTURE_2D, fb_texture);
666 				GL_DrawAliasFrame (vo);
667 
668 				if (gl_vector_light->int_val) {
669 					qfglEnable (GL_LIGHTING);
670 					if (!gl_tess)
671 						qfglEnable (GL_NORMALIZE);
672 				}
673 			}
674 		}
675 	}
676 
677 	qfglPopMatrix ();
678 
679 	// torches, grenades, and lightning bolts do not have shadows
680 	if (r_shadows->int_val && model->shadow_alpha) {
681 		mat4_t      shadow_mat;
682 
683 		qfglPushMatrix ();
684 		gl_R_RotateForEntity (e);
685 
686 		if (!gl_tess)
687 			qfglDisable (GL_NORMALIZE);
688 		qfglDisable (GL_LIGHTING);
689 		qfglDisable (GL_TEXTURE_2D);
690 		qfglDepthMask (GL_FALSE);
691 
692 		if (gl_modelalpha < 1.0) {
693 			VectorBlend (e->colormod, dark, 0.5, color);
694 			color[3] = gl_modelalpha * (model->shadow_alpha / 255.0);
695 			qfglColor4fv (color);
696 		} else {
697 			color_black[3] = model->shadow_alpha;
698 			qfglColor4ubv (color_black);
699 		}
700 		shadevector[0] = 1;
701 		shadevector[1] = 0;
702 		shadevector[2] = 1;
703 		VectorNormalize (shadevector);
704 		Mat4Transpose (e->transform, shadow_mat);
705 		Mat4as3MultVec (shadow_mat, shadevector, shadevector);
706 		if (vo->tex_coord)
707 			GL_DrawAliasShadowTri (paliashdr, vo);
708 		else
709 			GL_DrawAliasShadow (paliashdr, vo);
710 
711 		qfglDepthMask (GL_TRUE);
712 		qfglEnable (GL_TEXTURE_2D);
713 		qfglEnable (GL_LIGHTING);
714 		if (!gl_tess)
715 			qfglEnable (GL_NORMALIZE);
716 		qfglPopMatrix ();
717 	} else if (gl_modelalpha < 1.0) {
718 		qfglDepthMask (GL_TRUE);
719 	}
720 
721 	while (used_lights--) {
722 		qfglDisable (GL_LIGHT0 + used_lights);
723 	}
724 
725 	if (!e->model->aliashdr)
726 		Cache_Release (&e->model->cache);
727 }
728