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