1 /* $Id: gl_mesh.c,v 1.3 2002/09/25 13:22:55 bburns Exp $
2  *
3  * triangle model functions
4  *
5  * Copyright (C) 1997-2001 Id Software, Inc.
6  * Copyright (c) 2002 The Quakeforge Project.
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 the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  */
23 
24 #include "gl_local.h"
25 
26 /*
27 =============================================================
28 
29   ALIAS MODELS
30 
31 =============================================================
32 */
33 
34 #define NUMVERTEXNORMALS	162
35 
36 float	r_avertexnormals[NUMVERTEXNORMALS][3] = {
37 #include "anorms.h"
38 };
39 
40 typedef float vec4_t[4];
41 
42 static	vec4_t	s_lerped[MAX_VERTS];
43 //static	vec3_t	lerped[MAX_VERTS];
44 
45 vec3_t	shadevector;
46 float	shadelight[3];
47 
48 // precalculated dot products for quantized angles
49 #define SHADEDOT_QUANT 16
50 float	r_avertexnormal_dots[SHADEDOT_QUANT][256] =
51 #include "anormtab.h"
52 ;
53 
54 float	*shadedots = r_avertexnormal_dots[0];
55 
GL_LerpVerts(int nverts,dtrivertx_t * v,dtrivertx_t * ov,dtrivertx_t * verts,float * lerp,float move[3],float frontv[3],float backv[3])56 void GL_LerpVerts( int nverts, dtrivertx_t *v, dtrivertx_t *ov, dtrivertx_t *verts, float *lerp, float move[3], float frontv[3], float backv[3] )
57 {
58 	int i;
59 
60 	//PMM -- added RF_SHELL_DOUBLE, RF_SHELL_HALF_DAM
61 	if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) )
62 	{
63 		for (i=0 ; i < nverts; i++, v++, ov++, lerp+=4 )
64 		{
65 			float *normal = r_avertexnormals[verts[i].lightnormalindex];
66 
67 			lerp[0] = move[0] + ov->v[0]*backv[0] + v->v[0]*frontv[0] + normal[0] * POWERSUIT_SCALE;
68 			lerp[1] = move[1] + ov->v[1]*backv[1] + v->v[1]*frontv[1] + normal[1] * POWERSUIT_SCALE;
69 			lerp[2] = move[2] + ov->v[2]*backv[2] + v->v[2]*frontv[2] + normal[2] * POWERSUIT_SCALE;
70 		}
71 	}
72 	else
73 	{
74 		for (i=0 ; i < nverts; i++, v++, ov++, lerp+=4)
75 		{
76 			lerp[0] = move[0] + ov->v[0]*backv[0] + v->v[0]*frontv[0];
77 			lerp[1] = move[1] + ov->v[1]*backv[1] + v->v[1]*frontv[1];
78 			lerp[2] = move[2] + ov->v[2]*backv[2] + v->v[2]*frontv[2];
79 		}
80 	}
81 
82 }
83 
84 /*
85 =============
86 GL_DrawAliasFrameLerp
87 
88 interpolates between two frames and origins
89 FIXME: batch lerp all vertexes
90 =============
91 */
GL_DrawAliasFrameLerp(dmdl_t * paliashdr,float backlerp)92 void GL_DrawAliasFrameLerp (dmdl_t *paliashdr, float backlerp)
93 {
94 	float 	l;
95 	daliasframe_t	*frame, *oldframe;
96 	dtrivertx_t	*v, *ov, *verts;
97 	int		*order;
98 	int		count;
99 	float	frontlerp;
100 	float	alpha;
101 	vec3_t	move, delta, vectors[3];
102 	vec3_t	frontv, backv;
103 	int		i;
104 	int		index_xyz;
105 	float	*lerp;
106 
107 	frame = (daliasframe_t *)((byte *)paliashdr + paliashdr->ofs_frames
108 		+ currententity->frame * paliashdr->framesize);
109 	verts = v = frame->verts;
110 
111 	oldframe = (daliasframe_t *)((byte *)paliashdr + paliashdr->ofs_frames
112 		+ currententity->oldframe * paliashdr->framesize);
113 	ov = oldframe->verts;
114 
115 	order = (int *)((byte *)paliashdr + paliashdr->ofs_glcmds);
116 
117 //	glTranslatef (frame->translate[0], frame->translate[1], frame->translate[2]);
118 //	glScalef (frame->scale[0], frame->scale[1], frame->scale[2]);
119 
120 	if (currententity->flags & RF_TRANSLUCENT)
121 		alpha = currententity->alpha;
122 	else
123 		alpha = 1.0;
124 
125 	// PMM - added double shell
126 	if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) )
127 		qglDisable( GL_TEXTURE_2D );
128 
129 	frontlerp = 1.0 - backlerp;
130 
131 	// move should be the delta back to the previous frame * backlerp
132 	VectorSubtract (currententity->oldorigin, currententity->origin, delta);
133 	AngleVectors (currententity->angles, vectors[0], vectors[1], vectors[2]);
134 
135 	move[0] = DotProduct (delta, vectors[0]);	// forward
136 	move[1] = -DotProduct (delta, vectors[1]);	// left
137 	move[2] = DotProduct (delta, vectors[2]);	// up
138 
139 	VectorAdd (move, oldframe->translate, move);
140 
141 	for (i=0 ; i<3 ; i++)
142 	{
143 		move[i] = backlerp*move[i] + frontlerp*frame->translate[i];
144 	}
145 
146 	for (i=0 ; i<3 ; i++)
147 	{
148 		frontv[i] = frontlerp*frame->scale[i];
149 		backv[i] = backlerp*oldframe->scale[i];
150 	}
151 
152 	lerp = s_lerped[0];
153 
154 	GL_LerpVerts( paliashdr->num_xyz, v, ov, verts, lerp, move, frontv, backv );
155 
156 	if ( gl_vertex_arrays->value )
157 	{
158 		float colorArray[MAX_VERTS*4];
159 
160 		qglEnableClientState( GL_VERTEX_ARRAY );
161 		qglVertexPointer( 3, GL_FLOAT, 16, s_lerped );	// padded for SIMD
162 
163 //		if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE ) )
164 		// PMM - added double damage shell
165 		if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) )
166 		{
167 			qglColor4f( shadelight[0], shadelight[1], shadelight[2], alpha );
168 		}
169 		else
170 		{
171 			qglEnableClientState( GL_COLOR_ARRAY );
172 			qglColorPointer( 3, GL_FLOAT, 0, colorArray );
173 
174 			//
175 			// pre light everything
176 			//
177 			for ( i = 0; i < paliashdr->num_xyz; i++ )
178 			{
179 				float l = shadedots[verts[i].lightnormalindex];
180 
181 				colorArray[i*3+0] = l * shadelight[0];
182 				colorArray[i*3+1] = l * shadelight[1];
183 				colorArray[i*3+2] = l * shadelight[2];
184 			}
185 		}
186 
187 		if ( qglLockArraysEXT != 0 )
188 			qglLockArraysEXT( 0, paliashdr->num_xyz );
189 
190 		while (1)
191 		{
192 			// get the vertex count and primitive type
193 			count = *order++;
194 			if (!count)
195 				break;		// done
196 			if (count < 0)
197 			{
198 				count = -count;
199 				qglBegin (GL_TRIANGLE_FAN);
200 			}
201 			else
202 			{
203 				qglBegin (GL_TRIANGLE_STRIP);
204 			}
205 
206 			// PMM - added double damage shell
207 			if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) )
208 			{
209 				do
210 				{
211 					index_xyz = order[2];
212 					order += 3;
213 
214 					qglVertex3fv( s_lerped[index_xyz] );
215 
216 				} while (--count);
217 			}
218 			else
219 			{
220 				do
221 				{
222 					// texture coordinates come from the draw list
223 					qglTexCoord2f (((float *)order)[0], ((float *)order)[1]);
224 					index_xyz = order[2];
225 
226 					order += 3;
227 
228 					// normals and vertexes come from the frame list
229 //					l = shadedots[verts[index_xyz].lightnormalindex];
230 
231 //					qglColor4f (l* shadelight[0], l*shadelight[1], l*shadelight[2], alpha);
232 					qglArrayElement( index_xyz );
233 
234 				} while (--count);
235 			}
236 			qglEnd ();
237 		}
238 
239 		if ( qglUnlockArraysEXT != 0 )
240 			qglUnlockArraysEXT();
241 	}
242 	else
243 	{
244 		while (1)
245 		{
246 			// get the vertex count and primitive type
247 			count = *order++;
248 			if (!count)
249 				break;		// done
250 			if (count < 0)
251 			{
252 				count = -count;
253 				qglBegin (GL_TRIANGLE_FAN);
254 			}
255 			else
256 			{
257 				qglBegin (GL_TRIANGLE_STRIP);
258 			}
259 
260 			if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE ) )
261 			{
262 				do
263 				{
264 					index_xyz = order[2];
265 					order += 3;
266 
267 					qglColor4f( shadelight[0], shadelight[1], shadelight[2], alpha);
268 					qglVertex3fv (s_lerped[index_xyz]);
269 
270 				} while (--count);
271 			}
272 			else
273 			{
274 				do
275 				{
276 					// texture coordinates come from the draw list
277 					qglTexCoord2f (((float *)order)[0], ((float *)order)[1]);
278 					index_xyz = order[2];
279 					order += 3;
280 
281 					// normals and vertexes come from the frame list
282 					l = shadedots[verts[index_xyz].lightnormalindex];
283 
284 					qglColor4f (l* shadelight[0], l*shadelight[1], l*shadelight[2], alpha);
285 					qglVertex3fv (s_lerped[index_xyz]);
286 				} while (--count);
287 			}
288 
289 			qglEnd ();
290 		}
291 	}
292 
293 //	if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE ) )
294 	// PMM - added double damage shell
295 	if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM) )
296 		qglEnable( GL_TEXTURE_2D );
297 }
298 
299 
300 #if 1
301 /*
302 =============
303 GL_DrawAliasShadow
304 =============
305 */
306 extern	vec3_t			lightspot;
307 /* stencilbuffer shadows */
308 extern qboolean have_stencil;
309 
GL_DrawAliasShadow(dmdl_t * paliashdr,int posenum)310 void GL_DrawAliasShadow (dmdl_t *paliashdr, int posenum)
311 {
312 	dtrivertx_t	*verts;
313 	int		*order;
314 	vec3_t	point;
315 	float	height, lheight;
316 	int		count;
317 	daliasframe_t	*frame;
318 
319 	lheight = currententity->origin[2] - lightspot[2];
320 
321 	frame = (daliasframe_t *)((byte *)paliashdr + paliashdr->ofs_frames
322 		+ currententity->frame * paliashdr->framesize);
323 	verts = frame->verts;
324 
325 	height = 0;
326 
327 	order = (int *)((byte *)paliashdr + paliashdr->ofs_glcmds);
328 
329 	height = -lheight + 0.1f;
330 
331 	/* stencilbuffer shadows */
332 	if (have_stencil && gl_stencilshadow->value) {
333 		qglEnable(GL_STENCIL_TEST);
334 		qglStencilFunc(GL_EQUAL, 1, 2);
335 		qglStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
336 	}
337 
338 	while (1)
339 	{
340 		// get the vertex count and primitive type
341 		count = *order++;
342 		if (!count)
343 			break;		// done
344 		if (count < 0)
345 		{
346 			count = -count;
347 			qglBegin (GL_TRIANGLE_FAN);
348 		}
349 		else
350 			qglBegin (GL_TRIANGLE_STRIP);
351 
352 		do
353 		{
354 			// normals and vertexes come from the frame list
355 /*
356 			point[0] = verts[order[2]].v[0] * frame->scale[0] + frame->translate[0];
357 			point[1] = verts[order[2]].v[1] * frame->scale[1] + frame->translate[1];
358 			point[2] = verts[order[2]].v[2] * frame->scale[2] + frame->translate[2];
359 */
360 
361 			memcpy( point, s_lerped[order[2]], sizeof( point )  );
362 
363 			point[0] -= shadevector[0]*(point[2]+lheight);
364 			point[1] -= shadevector[1]*(point[2]+lheight);
365 			point[2] = height;
366 //			height -= 0.001;
367 			qglVertex3fv (point);
368 
369 			order += 3;
370 
371 //			verts++;
372 
373 		} while (--count);
374 
375 		qglEnd ();
376 	}
377 
378 	/* stencilbuffer shadows */
379 	if (have_stencil && gl_stencilshadow->value)
380 		qglDisable(GL_STENCIL_TEST);
381 }
382 
383 #endif
384 
385 /*
386 ** R_CullAliasModel
387 */
R_CullAliasModel(vec3_t bbox[8],entity_t * e)388 static qboolean R_CullAliasModel( vec3_t bbox[8], entity_t *e )
389 {
390 	int i;
391 	vec3_t		mins, maxs;
392 	dmdl_t		*paliashdr;
393 	vec3_t		vectors[3];
394 	vec3_t		thismins, oldmins, thismaxs, oldmaxs;
395 	daliasframe_t *pframe, *poldframe;
396 	vec3_t angles;
397 
398 	paliashdr = (dmdl_t *)currentmodel->extradata;
399 
400 	if ( ( e->frame >= paliashdr->num_frames ) || ( e->frame < 0 ) )
401 	{
402 		ri.Con_Printf (PRINT_ALL, "R_CullAliasModel %s: no such frame %d\n",
403 			currentmodel->name, e->frame);
404 		e->frame = 0;
405 	}
406 	if ( ( e->oldframe >= paliashdr->num_frames ) || ( e->oldframe < 0 ) )
407 	{
408 		ri.Con_Printf (PRINT_ALL, "R_CullAliasModel %s: no such oldframe %d\n",
409 			currentmodel->name, e->oldframe);
410 		e->oldframe = 0;
411 	}
412 
413 	pframe = ( daliasframe_t * ) ( ( byte * ) paliashdr +
414 		                              paliashdr->ofs_frames +
415 									  e->frame * paliashdr->framesize);
416 
417 	poldframe = ( daliasframe_t * ) ( ( byte * ) paliashdr +
418 		                              paliashdr->ofs_frames +
419 									  e->oldframe * paliashdr->framesize);
420 
421 	/*
422 	** compute axially aligned mins and maxs
423 	*/
424 	if ( pframe == poldframe )
425 	{
426 		for ( i = 0; i < 3; i++ )
427 		{
428 			mins[i] = pframe->translate[i];
429 			maxs[i] = mins[i] + pframe->scale[i]*255;
430 		}
431 	}
432 	else
433 	{
434 		for ( i = 0; i < 3; i++ )
435 		{
436 			thismins[i] = pframe->translate[i];
437 			thismaxs[i] = thismins[i] + pframe->scale[i]*255;
438 
439 			oldmins[i]  = poldframe->translate[i];
440 			oldmaxs[i]  = oldmins[i] + poldframe->scale[i]*255;
441 
442 			if ( thismins[i] < oldmins[i] )
443 				mins[i] = thismins[i];
444 			else
445 				mins[i] = oldmins[i];
446 
447 			if ( thismaxs[i] > oldmaxs[i] )
448 				maxs[i] = thismaxs[i];
449 			else
450 				maxs[i] = oldmaxs[i];
451 		}
452 	}
453 
454 	/*
455 	** compute a full bounding box
456 	*/
457 	for ( i = 0; i < 8; i++ )
458 	{
459 		vec3_t   tmp;
460 
461 		if ( i & 1 )
462 			tmp[0] = mins[0];
463 		else
464 			tmp[0] = maxs[0];
465 
466 		if ( i & 2 )
467 			tmp[1] = mins[1];
468 		else
469 			tmp[1] = maxs[1];
470 
471 		if ( i & 4 )
472 			tmp[2] = mins[2];
473 		else
474 			tmp[2] = maxs[2];
475 
476 		VectorCopy( tmp, bbox[i] );
477 	}
478 
479 	/*
480 	** rotate the bounding box
481 	*/
482 	VectorCopy( e->angles, angles );
483 	angles[YAW] = -angles[YAW];
484 	AngleVectors( angles, vectors[0], vectors[1], vectors[2] );
485 
486 	for ( i = 0; i < 8; i++ )
487 	{
488 		vec3_t tmp;
489 
490 		VectorCopy( bbox[i], tmp );
491 
492 		bbox[i][0] = DotProduct( vectors[0], tmp );
493 		bbox[i][1] = -DotProduct( vectors[1], tmp );
494 		bbox[i][2] = DotProduct( vectors[2], tmp );
495 
496 		VectorAdd( e->origin, bbox[i], bbox[i] );
497 	}
498 
499 	{
500 		int p, f, aggregatemask = ~0;
501 
502 		for ( p = 0; p < 8; p++ )
503 		{
504 			int mask = 0;
505 
506 			for ( f = 0; f < 4; f++ )
507 			{
508 				float dp = DotProduct( frustum[f].normal, bbox[p] );
509 
510 				if ( ( dp - frustum[f].dist ) < 0 )
511 				{
512 					mask |= ( 1 << f );
513 				}
514 			}
515 
516 			aggregatemask &= mask;
517 		}
518 
519 		if ( aggregatemask )
520 		{
521 			return true;
522 		}
523 
524 		return false;
525 	}
526 }
527 
528 /*
529 =================
530 R_DrawAliasModel
531 
532 =================
533 */
R_DrawAliasModel(entity_t * e)534 void R_DrawAliasModel (entity_t *e)
535 {
536 	int			i;
537 	dmdl_t		*paliashdr;
538 	float		an;
539 	vec3_t		bbox[8];
540 	image_t		*skin;
541 
542 	if ( !( e->flags & RF_WEAPONMODEL ) )
543 	{
544 		if ( R_CullAliasModel( bbox, e ) )
545 			return;
546 	}
547 
548 	if ( e->flags & RF_WEAPONMODEL )
549 	{
550 		if ( r_lefthand->value == 2 )
551 			return;
552 	}
553 
554 	paliashdr = (dmdl_t *)currentmodel->extradata;
555 
556 	//
557 	// get lighting information
558 	//
559 	// PMM - rewrote, reordered to handle new shells & mixing
560 	// PMM - 3.20 code .. replaced with original way of doing it to keep mod authors happy
561 	//
562 	if ( currententity->flags & ( RF_SHELL_HALF_DAM | RF_SHELL_GREEN | RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_DOUBLE ) )
563 	{
564 		VectorClear (shadelight);
565 		if (currententity->flags & RF_SHELL_HALF_DAM)
566 		{
567 				shadelight[0] = 0.56;
568 				shadelight[1] = 0.59;
569 				shadelight[2] = 0.45;
570 		}
571 		if ( currententity->flags & RF_SHELL_DOUBLE )
572 		{
573 			shadelight[0] = 0.9;
574 			shadelight[1] = 0.7;
575 		}
576 		if ( currententity->flags & RF_SHELL_RED )
577 			shadelight[0] = 1.0;
578 		if ( currententity->flags & RF_SHELL_GREEN )
579 			shadelight[1] = 1.0;
580 		if ( currententity->flags & RF_SHELL_BLUE )
581 			shadelight[2] = 1.0;
582 	}
583 /*
584 		// PMM -special case for godmode
585 		if ( (currententity->flags & RF_SHELL_RED) &&
586 			(currententity->flags & RF_SHELL_BLUE) &&
587 			(currententity->flags & RF_SHELL_GREEN) )
588 		{
589 			for (i=0 ; i<3 ; i++)
590 				shadelight[i] = 1.0;
591 		}
592 		else if ( currententity->flags & ( RF_SHELL_RED | RF_SHELL_BLUE | RF_SHELL_DOUBLE ) )
593 		{
594 			VectorClear (shadelight);
595 
596 			if ( currententity->flags & RF_SHELL_RED )
597 			{
598 				shadelight[0] = 1.0;
599 				if (currententity->flags & (RF_SHELL_BLUE|RF_SHELL_DOUBLE) )
600 					shadelight[2] = 1.0;
601 			}
602 			else if ( currententity->flags & RF_SHELL_BLUE )
603 			{
604 				if ( currententity->flags & RF_SHELL_DOUBLE )
605 				{
606 					shadelight[1] = 1.0;
607 					shadelight[2] = 1.0;
608 				}
609 				else
610 				{
611 					shadelight[2] = 1.0;
612 				}
613 			}
614 			else if ( currententity->flags & RF_SHELL_DOUBLE )
615 			{
616 				shadelight[0] = 0.9;
617 				shadelight[1] = 0.7;
618 			}
619 		}
620 		else if ( currententity->flags & ( RF_SHELL_HALF_DAM | RF_SHELL_GREEN ) )
621 		{
622 			VectorClear (shadelight);
623 			// PMM - new colors
624 			if ( currententity->flags & RF_SHELL_HALF_DAM )
625 			{
626 				shadelight[0] = 0.56;
627 				shadelight[1] = 0.59;
628 				shadelight[2] = 0.45;
629 			}
630 			if ( currententity->flags & RF_SHELL_GREEN )
631 			{
632 				shadelight[1] = 1.0;
633 			}
634 		}
635 	}
636 			//PMM - ok, now flatten these down to range from 0 to 1.0.
637 	//		max_shell_val = max(shadelight[0], max(shadelight[1], shadelight[2]));
638 	//		if (max_shell_val > 0)
639 	//		{
640 	//			for (i=0; i<3; i++)
641 	//			{
642 	//				shadelight[i] = shadelight[i] / max_shell_val;
643 	//			}
644 	//		}
645 	// pmm
646 */
647 	else if ( currententity->flags & RF_FULLBRIGHT )
648 	{
649 		for (i=0 ; i<3 ; i++)
650 			shadelight[i] = 1.0;
651 	}
652 	else
653 	{
654 		R_LightPoint (currententity->origin, shadelight);
655 
656 		// player lighting hack for communication back to server
657 		// big hack!
658 		if ( currententity->flags & RF_WEAPONMODEL )
659 		{
660 			// pick the greatest component, which should be the same
661 			// as the mono value returned by software
662 			if (shadelight[0] > shadelight[1])
663 			{
664 				if (shadelight[0] > shadelight[2])
665 					r_lightlevel->value = 150*shadelight[0];
666 				else
667 					r_lightlevel->value = 150*shadelight[2];
668 			}
669 			else
670 			{
671 				if (shadelight[1] > shadelight[2])
672 					r_lightlevel->value = 150*shadelight[1];
673 				else
674 					r_lightlevel->value = 150*shadelight[2];
675 			}
676 
677 		}
678 
679 		if ( gl_monolightmap->string[0] != '0' )
680 		{
681 			float s = shadelight[0];
682 
683 			if ( s < shadelight[1] )
684 				s = shadelight[1];
685 			if ( s < shadelight[2] )
686 				s = shadelight[2];
687 
688 			shadelight[0] = s;
689 			shadelight[1] = s;
690 			shadelight[2] = s;
691 		}
692 	}
693 
694 	if ( currententity->flags & RF_MINLIGHT )
695 	{
696 		for (i=0 ; i<3 ; i++)
697 			if (shadelight[i] > 0.1)
698 				break;
699 		if (i == 3)
700 		{
701 			shadelight[0] = 0.1;
702 			shadelight[1] = 0.1;
703 			shadelight[2] = 0.1;
704 		}
705 	}
706 
707 	if ( currententity->flags & RF_GLOW )
708 	{	// bonus items will pulse with time
709 		float	scale;
710 		float	min;
711 
712 		scale = 0.1 * sin(r_newrefdef.time*7);
713 		for (i=0 ; i<3 ; i++)
714 		{
715 			min = shadelight[i] * 0.8;
716 			shadelight[i] += scale;
717 			if (shadelight[i] < min)
718 				shadelight[i] = min;
719 		}
720 	}
721 
722 // =================
723 // PGM	ir goggles color override
724 	if ( r_newrefdef.rdflags & RDF_IRGOGGLES && currententity->flags & RF_IR_VISIBLE)
725 	{
726 		shadelight[0] = 1.0;
727 		shadelight[1] = 0.0;
728 		shadelight[2] = 0.0;
729 	}
730 // PGM
731 // =================
732 
733 	shadedots = r_avertexnormal_dots[((int)(currententity->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)];
734 
735 	an = currententity->angles[1]/180*M_PI;
736 	shadevector[0] = cos(-an);
737 	shadevector[1] = sin(-an);
738 	shadevector[2] = 1;
739 	VectorNormalize (shadevector);
740 
741 	//
742 	// locate the proper data
743 	//
744 
745 	c_alias_polys += paliashdr->num_tris;
746 
747 	//
748 	// draw all the triangles
749 	//
750 	if (currententity->flags & RF_DEPTHHACK) // hack the depth range to prevent view model from poking into walls
751 		qglDepthRange (gldepthmin, gldepthmin + 0.3*(gldepthmax-gldepthmin));
752 
753 	if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) )
754 	{
755 		extern void MYgluPerspective( GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar );
756 
757 		qglMatrixMode( GL_PROJECTION );
758 		qglPushMatrix();
759 		qglLoadIdentity();
760 		qglScalef( -1, 1, 1 );
761 	    MYgluPerspective( r_newrefdef.fov_y, ( float ) r_newrefdef.width / r_newrefdef.height,  4,  4096);
762 		qglMatrixMode( GL_MODELVIEW );
763 
764 		qglCullFace( GL_BACK );
765 	}
766 
767     qglPushMatrix ();
768 	e->angles[PITCH] = -e->angles[PITCH];	// sigh.
769 	R_RotateForEntity (e);
770 	e->angles[PITCH] = -e->angles[PITCH];	// sigh.
771 
772 	// select skin
773 	if (currententity->skin)
774 		skin = currententity->skin;	// custom player skin
775 	else
776 	{
777 		if (currententity->skinnum >= MAX_MD2SKINS)
778 			skin = currentmodel->skins[0];
779 		else
780 		{
781 			skin = currentmodel->skins[currententity->skinnum];
782 			if (!skin)
783 				skin = currentmodel->skins[0];
784 		}
785 	}
786 	if (!skin)
787 		skin = r_notexture;	// fallback...
788 	GL_Bind(skin->texnum);
789 
790 	// draw it
791 
792 	qglShadeModel (GL_SMOOTH);
793 
794 	GL_TexEnv( GL_MODULATE );
795 	if ( currententity->flags & RF_TRANSLUCENT )
796 	{
797 		qglEnable (GL_BLEND);
798 	}
799 
800 
801 	if ( (currententity->frame >= paliashdr->num_frames)
802 		|| (currententity->frame < 0) )
803 	{
804 		ri.Con_Printf (PRINT_ALL, "R_DrawAliasModel %s: no such frame %d\n",
805 			currentmodel->name, currententity->frame);
806 		currententity->frame = 0;
807 		currententity->oldframe = 0;
808 	}
809 
810 	if ( (currententity->oldframe >= paliashdr->num_frames)
811 		|| (currententity->oldframe < 0))
812 	{
813 		ri.Con_Printf (PRINT_ALL, "R_DrawAliasModel %s: no such oldframe %d\n",
814 			currentmodel->name, currententity->oldframe);
815 		currententity->frame = 0;
816 		currententity->oldframe = 0;
817 	}
818 
819 	if ( !r_lerpmodels->value )
820 		currententity->backlerp = 0;
821 	GL_DrawAliasFrameLerp (paliashdr, currententity->backlerp);
822 
823 	GL_TexEnv( GL_REPLACE );
824 	qglShadeModel (GL_FLAT);
825 
826 	qglPopMatrix ();
827 
828 #if 0
829 	qglDisable( GL_CULL_FACE );
830 	qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
831 	qglDisable( GL_TEXTURE_2D );
832 	qglBegin( GL_TRIANGLE_STRIP );
833 	for ( i = 0; i < 8; i++ )
834 	{
835 		qglVertex3fv( bbox[i] );
836 	}
837 	qglEnd();
838 	qglEnable( GL_TEXTURE_2D );
839 	qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
840 	qglEnable( GL_CULL_FACE );
841 #endif
842 
843 	if ( ( currententity->flags & RF_WEAPONMODEL ) && ( r_lefthand->value == 1.0F ) )
844 	{
845 		qglMatrixMode( GL_PROJECTION );
846 		qglPopMatrix();
847 		qglMatrixMode( GL_MODELVIEW );
848 		qglCullFace( GL_FRONT );
849 	}
850 
851 	if ( currententity->flags & RF_TRANSLUCENT )
852 	{
853 		qglDisable (GL_BLEND);
854 	}
855 
856 	if (currententity->flags & RF_DEPTHHACK)
857 		qglDepthRange (gldepthmin, gldepthmax);
858 
859 //#if 1
860 	if (gl_shadows->value &&
861 		!(currententity->flags & (RF_TRANSLUCENT|RF_WEAPONMODEL|RF_NOSHADOW))) {
862 		qglPushMatrix ();
863 
864 		/* don't rotate shadows on ungodly axes */
865 		qglTranslatef(e->origin[0], e->origin[1], e->origin[2]);
866 		qglRotatef(e->angles[1], 0, 0, 1);
867 
868 		qglDisable (GL_TEXTURE_2D);
869 		qglEnable (GL_BLEND);
870 		qglColor4f (0,0,0,0.5);
871 		GL_DrawAliasShadow (paliashdr, currententity->frame );
872 		qglEnable (GL_TEXTURE_2D);
873 		qglDisable (GL_BLEND);
874 		qglPopMatrix ();
875 	}
876 //#endif
877 	qglColor4f (1,1,1,1);
878 }
879 
880 
881