1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4 
5 This file is part of Quake III Arena source code.
6 
7 Quake III Arena source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
11 
12 Quake III Arena source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Quake III Arena source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 ===========================================================================
21 */
22 // tr_shade.c
23 
24 #include "tr_local.h"
25 #if idppc_altivec && !defined(MACOS_X)
26 #include <altivec.h>
27 #endif
28 
29 /*
30 
31   THIS ENTIRE FILE IS BACK END
32 
33   This file deals with applying shaders to surface data in the tess struct.
34 */
35 
36 /*
37 ================
38 R_ArrayElementDiscrete
39 
40 This is just for OpenGL conformance testing, it should never be the fastest
41 ================
42 */
R_ArrayElementDiscrete(GLint index)43 static void APIENTRY R_ArrayElementDiscrete( GLint index ) {
44 	qglColor4ubv( tess.svars.colors[ index ] );
45 	if ( glState.currenttmu ) {
46 		qglMultiTexCoord2fARB( 0, tess.svars.texcoords[ 0 ][ index ][0], tess.svars.texcoords[ 0 ][ index ][1] );
47 		qglMultiTexCoord2fARB( 1, tess.svars.texcoords[ 1 ][ index ][0], tess.svars.texcoords[ 1 ][ index ][1] );
48 	} else {
49 		qglTexCoord2fv( tess.svars.texcoords[ 0 ][ index ] );
50 	}
51 	qglVertex3fv( tess.xyz[ index ] );
52 }
53 
54 /*
55 ===================
56 R_DrawStripElements
57 
58 ===================
59 */
60 static int		c_vertexes;		// for seeing how long our average strips are
61 static int		c_begins;
R_DrawStripElements(int numIndexes,const glIndex_t * indexes,void (APIENTRY * element)(GLint))62 static void R_DrawStripElements( int numIndexes, const glIndex_t *indexes, void ( APIENTRY *element )(GLint) ) {
63 	int i;
64 	int last[3] = { -1, -1, -1 };
65 	qboolean even;
66 
67 	c_begins++;
68 
69 	if ( numIndexes <= 0 ) {
70 		return;
71 	}
72 
73 	qglBegin( GL_TRIANGLE_STRIP );
74 
75 	// prime the strip
76 	element( indexes[0] );
77 	element( indexes[1] );
78 	element( indexes[2] );
79 	c_vertexes += 3;
80 
81 	last[0] = indexes[0];
82 	last[1] = indexes[1];
83 	last[2] = indexes[2];
84 
85 	even = qfalse;
86 
87 	for ( i = 3; i < numIndexes; i += 3 )
88 	{
89 		// odd numbered triangle in potential strip
90 		if ( !even )
91 		{
92 			// check previous triangle to see if we're continuing a strip
93 			if ( ( indexes[i+0] == last[2] ) && ( indexes[i+1] == last[1] ) )
94 			{
95 				element( indexes[i+2] );
96 				c_vertexes++;
97 				assert( indexes[i+2] < tess.numVertexes );
98 				even = qtrue;
99 			}
100 			// otherwise we're done with this strip so finish it and start
101 			// a new one
102 			else
103 			{
104 				qglEnd();
105 
106 				qglBegin( GL_TRIANGLE_STRIP );
107 				c_begins++;
108 
109 				element( indexes[i+0] );
110 				element( indexes[i+1] );
111 				element( indexes[i+2] );
112 
113 				c_vertexes += 3;
114 
115 				even = qfalse;
116 			}
117 		}
118 		else
119 		{
120 			// check previous triangle to see if we're continuing a strip
121 			if ( ( last[2] == indexes[i+1] ) && ( last[0] == indexes[i+0] ) )
122 			{
123 				element( indexes[i+2] );
124 				c_vertexes++;
125 
126 				even = qfalse;
127 			}
128 			// otherwise we're done with this strip so finish it and start
129 			// a new one
130 			else
131 			{
132 				qglEnd();
133 
134 				qglBegin( GL_TRIANGLE_STRIP );
135 				c_begins++;
136 
137 				element( indexes[i+0] );
138 				element( indexes[i+1] );
139 				element( indexes[i+2] );
140 				c_vertexes += 3;
141 
142 				even = qfalse;
143 			}
144 		}
145 
146 		// cache the last three vertices
147 		last[0] = indexes[i+0];
148 		last[1] = indexes[i+1];
149 		last[2] = indexes[i+2];
150 	}
151 
152 	qglEnd();
153 }
154 
155 
156 
157 /*
158 ==================
159 R_DrawElements
160 
161 Optionally performs our own glDrawElements that looks for strip conditions
162 instead of using the single glDrawElements call that may be inefficient
163 without compiled vertex arrays.
164 ==================
165 */
R_DrawElements(int numIndexes,const glIndex_t * indexes)166 static void R_DrawElements( int numIndexes, const glIndex_t *indexes ) {
167 	int		primitives;
168 
169 	primitives = r_primitives->integer;
170 
171 	// default is to use triangles if compiled vertex arrays are present
172 	if ( primitives == 0 ) {
173 		if ( qglLockArraysEXT ) {
174 			primitives = 2;
175 		} else {
176 			primitives = 1;
177 		}
178 	}
179 
180 
181 	if ( primitives == 2 ) {
182 		qglDrawElements( GL_TRIANGLES,
183 						numIndexes,
184 						GL_INDEX_TYPE,
185 						indexes );
186 		return;
187 	}
188 
189 	if ( primitives == 1 ) {
190 		R_DrawStripElements( numIndexes,  indexes, qglArrayElement );
191 		return;
192 	}
193 
194 	if ( primitives == 3 ) {
195 		R_DrawStripElements( numIndexes,  indexes, R_ArrayElementDiscrete );
196 		return;
197 	}
198 
199 	// anything else will cause no drawing
200 }
201 
202 
203 /*
204 =============================================================
205 
206 SURFACE SHADERS
207 
208 =============================================================
209 */
210 
211 shaderCommands_t	tess;
212 static qboolean	setArraysOnce;
213 
214 /*
215 =================
216 R_BindAnimatedImage
217 
218 =================
219 */
R_BindAnimatedImage(textureBundle_t * bundle)220 static void R_BindAnimatedImage( textureBundle_t *bundle ) {
221 	int		index;
222 
223 	if ( bundle->isVideoMap ) {
224 		ri.CIN_RunCinematic(bundle->videoMapHandle);
225 		ri.CIN_UploadCinematic(bundle->videoMapHandle);
226 		return;
227 	}
228 
229 	if ( bundle->numImageAnimations <= 1 ) {
230 		GL_Bind( bundle->image[0] );
231 		return;
232 	}
233 
234 	// it is necessary to do this messy calc to make sure animations line up
235 	// exactly with waveforms of the same frequency
236 	index = myftol( tess.shaderTime * bundle->imageAnimationSpeed * FUNCTABLE_SIZE );
237 	index >>= FUNCTABLE_SIZE2;
238 
239 	if ( index < 0 ) {
240 		index = 0;	// may happen with shader time offsets
241 	}
242 	index %= bundle->numImageAnimations;
243 
244 	GL_Bind( bundle->image[ index ] );
245 }
246 
247 /*
248 ================
249 DrawTris
250 
251 Draws triangle outlines for debugging
252 ================
253 */
DrawTris(shaderCommands_t * input)254 static void DrawTris (shaderCommands_t *input) {
255 	GL_Bind( tr.whiteImage );
256 	qglColor3f (1,1,1);
257 
258 	GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE );
259 	qglDepthRange( 0, 0 );
260 
261 	qglDisableClientState (GL_COLOR_ARRAY);
262 	qglDisableClientState (GL_TEXTURE_COORD_ARRAY);
263 
264 	qglVertexPointer (3, GL_FLOAT, 16, input->xyz);	// padded for SIMD
265 
266 	if (qglLockArraysEXT) {
267 		qglLockArraysEXT(0, input->numVertexes);
268 		GLimp_LogComment( "glLockArraysEXT\n" );
269 	}
270 
271 	R_DrawElements( input->numIndexes, input->indexes );
272 
273 	if (qglUnlockArraysEXT) {
274 		qglUnlockArraysEXT();
275 		GLimp_LogComment( "glUnlockArraysEXT\n" );
276 	}
277 	qglDepthRange( 0, 1 );
278 }
279 
280 
281 /*
282 ================
283 DrawNormals
284 
285 Draws vertex normals for debugging
286 ================
287 */
DrawNormals(shaderCommands_t * input)288 static void DrawNormals (shaderCommands_t *input) {
289 	int		i;
290 	vec3_t	temp;
291 
292 	GL_Bind( tr.whiteImage );
293 	qglColor3f (1,1,1);
294 	qglDepthRange( 0, 0 );	// never occluded
295 	GL_State( GLS_POLYMODE_LINE | GLS_DEPTHMASK_TRUE );
296 
297 	qglBegin (GL_LINES);
298 	for (i = 0 ; i < input->numVertexes ; i++) {
299 		qglVertex3fv (input->xyz[i]);
300 		VectorMA (input->xyz[i], 2, input->normal[i], temp);
301 		qglVertex3fv (temp);
302 	}
303 	qglEnd ();
304 
305 	qglDepthRange( 0, 1 );
306 }
307 
308 /*
309 ==============
310 RB_BeginSurface
311 
312 We must set some things up before beginning any tesselation,
313 because a surface may be forced to perform a RB_End due
314 to overflow.
315 ==============
316 */
RB_BeginSurface(shader_t * shader,int fogNum)317 void RB_BeginSurface( shader_t *shader, int fogNum ) {
318 
319 	shader_t *state = (shader->remappedShader) ? shader->remappedShader : shader;
320 
321 	tess.numIndexes = 0;
322 	tess.numVertexes = 0;
323 	tess.shader = state;
324 	tess.fogNum = fogNum;
325 	tess.dlightBits = 0;		// will be OR'd in by surface functions
326 	tess.xstages = state->stages;
327 	tess.numPasses = state->numUnfoggedPasses;
328 	tess.currentStageIteratorFunc = state->optimalStageIteratorFunc;
329 
330 	tess.shaderTime = backEnd.refdef.floatTime - tess.shader->timeOffset;
331 	if (tess.shader->clampTime && tess.shaderTime >= tess.shader->clampTime) {
332 		tess.shaderTime = tess.shader->clampTime;
333 	}
334 
335 
336 }
337 
338 /*
339 ===================
340 DrawMultitextured
341 
342 output = t0 * t1 or t0 + t1
343 
344 t0 = most upstream according to spec
345 t1 = most downstream according to spec
346 ===================
347 */
DrawMultitextured(shaderCommands_t * input,int stage)348 static void DrawMultitextured( shaderCommands_t *input, int stage ) {
349 	shaderStage_t	*pStage;
350 
351 	pStage = tess.xstages[stage];
352 
353 	GL_State( pStage->stateBits );
354 
355 	// this is an ugly hack to work around a GeForce driver
356 	// bug with multitexture and clip planes
357 	if ( backEnd.viewParms.isPortal ) {
358 		qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
359 	}
360 
361 	//
362 	// base
363 	//
364 	GL_SelectTexture( 0 );
365 	qglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[0] );
366 	R_BindAnimatedImage( &pStage->bundle[0] );
367 
368 	//
369 	// lightmap/secondary pass
370 	//
371 	GL_SelectTexture( 1 );
372 	qglEnable( GL_TEXTURE_2D );
373 	qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
374 
375 	if ( r_lightmap->integer ) {
376 		GL_TexEnv( GL_REPLACE );
377 	} else {
378 		GL_TexEnv( tess.shader->multitextureEnv );
379 	}
380 
381 	qglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[1] );
382 
383 	R_BindAnimatedImage( &pStage->bundle[1] );
384 
385 	R_DrawElements( input->numIndexes, input->indexes );
386 
387 	//
388 	// disable texturing on TEXTURE1, then select TEXTURE0
389 	//
390 	//qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
391 	qglDisable( GL_TEXTURE_2D );
392 
393 	GL_SelectTexture( 0 );
394 }
395 
396 
397 
398 /*
399 ===================
400 ProjectDlightTexture
401 
402 Perform dynamic lighting with another rendering pass
403 ===================
404 */
405 #if idppc_altivec
ProjectDlightTexture_altivec(void)406 static void ProjectDlightTexture_altivec( void ) {
407 	int		i, l;
408 	vec_t	origin0, origin1, origin2;
409 	float   texCoords0, texCoords1;
410 	vector float floatColorVec0, floatColorVec1;
411 	vector float modulateVec, colorVec, zero;
412 	vector short colorShort;
413 	vector signed int colorInt;
414 	vector unsigned char floatColorVecPerm, modulatePerm, colorChar;
415 	vector unsigned char vSel = VECCONST_UINT8(0x00, 0x00, 0x00, 0xff,
416                                                0x00, 0x00, 0x00, 0xff,
417                                                0x00, 0x00, 0x00, 0xff,
418                                                0x00, 0x00, 0x00, 0xff);
419 	float	*texCoords;
420 	byte	*colors;
421 	byte	clipBits[SHADER_MAX_VERTEXES];
422 	float	texCoordsArray[SHADER_MAX_VERTEXES][2];
423 	byte	colorArray[SHADER_MAX_VERTEXES][4];
424 	unsigned	hitIndexes[SHADER_MAX_INDEXES];
425 	int		numIndexes;
426 	float	scale;
427 	float	radius;
428 	vec3_t	floatColor;
429 	float	modulate = 0.0f;
430 
431 	if ( !backEnd.refdef.num_dlights ) {
432 		return;
433 	}
434 
435 	// There has to be a better way to do this so that floatColor
436 	// and/or modulate are already 16-byte aligned.
437 	floatColorVecPerm = vec_lvsl(0,(float *)floatColor);
438 	modulatePerm = vec_lvsl(0,(float *)&modulate);
439 	modulatePerm = (vector unsigned char)vec_splat((vector unsigned int)modulatePerm,0);
440 	zero = (vector float)vec_splat_s8(0);
441 
442 	for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) {
443 		dlight_t	*dl;
444 
445 		if ( !( tess.dlightBits & ( 1 << l ) ) ) {
446 			continue;	// this surface definately doesn't have any of this light
447 		}
448 		texCoords = texCoordsArray[0];
449 		colors = colorArray[0];
450 
451 		dl = &backEnd.refdef.dlights[l];
452 		origin0 = dl->transformed[0];
453 		origin1 = dl->transformed[1];
454 		origin2 = dl->transformed[2];
455 		radius = dl->radius;
456 		scale = 1.0f / radius;
457 
458 		if(r_greyscale->integer)
459 		{
460 			float luminance;
461 
462 			luminance = (dl->color[0] * 255.0f + dl->color[1] * 255.0f + dl->color[2] * 255.0f) / 3;
463 			floatColor[0] = floatColor[1] = floatColor[2] = luminance;
464 		}
465 		else
466 		{
467 			floatColor[0] = dl->color[0] * 255.0f;
468 			floatColor[1] = dl->color[1] * 255.0f;
469 			floatColor[2] = dl->color[2] * 255.0f;
470 		}
471 		floatColorVec0 = vec_ld(0, floatColor);
472 		floatColorVec1 = vec_ld(11, floatColor);
473 		floatColorVec0 = vec_perm(floatColorVec0,floatColorVec0,floatColorVecPerm);
474 		for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) {
475 			int		clip = 0;
476 			vec_t dist0, dist1, dist2;
477 
478 			dist0 = origin0 - tess.xyz[i][0];
479 			dist1 = origin1 - tess.xyz[i][1];
480 			dist2 = origin2 - tess.xyz[i][2];
481 
482 			backEnd.pc.c_dlightVertexes++;
483 
484 			texCoords0 = 0.5f + dist0 * scale;
485 			texCoords1 = 0.5f + dist1 * scale;
486 
487 			if( !r_dlightBacks->integer &&
488 					// dist . tess.normal[i]
489 					( dist0 * tess.normal[i][0] +
490 					dist1 * tess.normal[i][1] +
491 					dist2 * tess.normal[i][2] ) < 0.0f ) {
492 				clip = 63;
493 			} else {
494 				if ( texCoords0 < 0.0f ) {
495 					clip |= 1;
496 				} else if ( texCoords0 > 1.0f ) {
497 					clip |= 2;
498 				}
499 				if ( texCoords1 < 0.0f ) {
500 					clip |= 4;
501 				} else if ( texCoords1 > 1.0f ) {
502 					clip |= 8;
503 				}
504 				texCoords[0] = texCoords0;
505 				texCoords[1] = texCoords1;
506 
507 				// modulate the strength based on the height and color
508 				if ( dist2 > radius ) {
509 					clip |= 16;
510 					modulate = 0.0f;
511 				} else if ( dist2 < -radius ) {
512 					clip |= 32;
513 					modulate = 0.0f;
514 				} else {
515 					dist2 = Q_fabs(dist2);
516 					if ( dist2 < radius * 0.5f ) {
517 						modulate = 1.0f;
518 					} else {
519 						modulate = 2.0f * (radius - dist2) * scale;
520 					}
521 				}
522 			}
523 			clipBits[i] = clip;
524 
525 			modulateVec = vec_ld(0,(float *)&modulate);
526 			modulateVec = vec_perm(modulateVec,modulateVec,modulatePerm);
527 			colorVec = vec_madd(floatColorVec0,modulateVec,zero);
528 			colorInt = vec_cts(colorVec,0);	// RGBx
529 			colorShort = vec_pack(colorInt,colorInt);		// RGBxRGBx
530 			colorChar = vec_packsu(colorShort,colorShort);	// RGBxRGBxRGBxRGBx
531 			colorChar = vec_sel(colorChar,vSel,vSel);		// RGBARGBARGBARGBA replace alpha with 255
532 			vec_ste((vector unsigned int)colorChar,0,(unsigned int *)colors);	// store color
533 		}
534 
535 		// build a list of triangles that need light
536 		numIndexes = 0;
537 		for ( i = 0 ; i < tess.numIndexes ; i += 3 ) {
538 			int		a, b, c;
539 
540 			a = tess.indexes[i];
541 			b = tess.indexes[i+1];
542 			c = tess.indexes[i+2];
543 			if ( clipBits[a] & clipBits[b] & clipBits[c] ) {
544 				continue;	// not lighted
545 			}
546 			hitIndexes[numIndexes] = a;
547 			hitIndexes[numIndexes+1] = b;
548 			hitIndexes[numIndexes+2] = c;
549 			numIndexes += 3;
550 		}
551 
552 		if ( !numIndexes ) {
553 			continue;
554 		}
555 
556 		qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
557 		qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] );
558 
559 		qglEnableClientState( GL_COLOR_ARRAY );
560 		qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray );
561 
562 		GL_Bind( tr.dlightImage );
563 		// include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light
564 		// where they aren't rendered
565 		if ( dl->additive ) {
566 			GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
567 		}
568 		else {
569 			GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
570 		}
571 		R_DrawElements( numIndexes, hitIndexes );
572 		backEnd.pc.c_totalIndexes += numIndexes;
573 		backEnd.pc.c_dlightIndexes += numIndexes;
574 	}
575 }
576 #endif
577 
578 
ProjectDlightTexture_scalar(void)579 static void ProjectDlightTexture_scalar( void ) {
580 	int		i, l;
581 	vec3_t	origin;
582 	float	*texCoords;
583 	byte	*colors;
584 	byte	clipBits[SHADER_MAX_VERTEXES];
585 	float	texCoordsArray[SHADER_MAX_VERTEXES][2];
586 	byte	colorArray[SHADER_MAX_VERTEXES][4];
587 	unsigned	hitIndexes[SHADER_MAX_INDEXES];
588 	int		numIndexes;
589 	float	scale;
590 	float	radius;
591 	vec3_t	floatColor;
592 	float	modulate = 0.0f;
593 
594 	if ( !backEnd.refdef.num_dlights ) {
595 		return;
596 	}
597 
598 	for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) {
599 		dlight_t	*dl;
600 
601 		if ( !( tess.dlightBits & ( 1 << l ) ) ) {
602 			continue;	// this surface definately doesn't have any of this light
603 		}
604 		texCoords = texCoordsArray[0];
605 		colors = colorArray[0];
606 
607 		dl = &backEnd.refdef.dlights[l];
608 		VectorCopy( dl->transformed, origin );
609 		radius = dl->radius;
610 		scale = 1.0f / radius;
611 
612 		if(r_greyscale->integer)
613 		{
614 			float luminance;
615 
616 			luminance = (dl->color[0] * 255.0f + dl->color[1] * 255.0f + dl->color[2] * 255.0f) / 3;
617 			floatColor[0] = floatColor[1] = floatColor[2] = luminance;
618 		}
619 		else
620 		{
621 			floatColor[0] = dl->color[0] * 255.0f;
622 			floatColor[1] = dl->color[1] * 255.0f;
623 			floatColor[2] = dl->color[2] * 255.0f;
624 		}
625 
626 		for ( i = 0 ; i < tess.numVertexes ; i++, texCoords += 2, colors += 4 ) {
627 			int		clip = 0;
628 			vec3_t	dist;
629 
630 			VectorSubtract( origin, tess.xyz[i], dist );
631 
632 			backEnd.pc.c_dlightVertexes++;
633 
634 			texCoords[0] = 0.5f + dist[0] * scale;
635 			texCoords[1] = 0.5f + dist[1] * scale;
636 
637 			if( !r_dlightBacks->integer &&
638 					// dist . tess.normal[i]
639 					( dist[0] * tess.normal[i][0] +
640 					dist[1] * tess.normal[i][1] +
641 					dist[2] * tess.normal[i][2] ) < 0.0f ) {
642 				clip = 63;
643 			} else {
644 				if ( texCoords[0] < 0.0f ) {
645 					clip |= 1;
646 				} else if ( texCoords[0] > 1.0f ) {
647 					clip |= 2;
648 				}
649 				if ( texCoords[1] < 0.0f ) {
650 					clip |= 4;
651 				} else if ( texCoords[1] > 1.0f ) {
652 					clip |= 8;
653 				}
654 				texCoords[0] = texCoords[0];
655 				texCoords[1] = texCoords[1];
656 
657 				// modulate the strength based on the height and color
658 				if ( dist[2] > radius ) {
659 					clip |= 16;
660 					modulate = 0.0f;
661 				} else if ( dist[2] < -radius ) {
662 					clip |= 32;
663 					modulate = 0.0f;
664 				} else {
665 					dist[2] = Q_fabs(dist[2]);
666 					if ( dist[2] < radius * 0.5f ) {
667 						modulate = 1.0f;
668 					} else {
669 						modulate = 2.0f * (radius - dist[2]) * scale;
670 					}
671 				}
672 			}
673 			clipBits[i] = clip;
674 			colors[0] = myftol(floatColor[0] * modulate);
675 			colors[1] = myftol(floatColor[1] * modulate);
676 			colors[2] = myftol(floatColor[2] * modulate);
677 			colors[3] = 255;
678 		}
679 
680 		// build a list of triangles that need light
681 		numIndexes = 0;
682 		for ( i = 0 ; i < tess.numIndexes ; i += 3 ) {
683 			int		a, b, c;
684 
685 			a = tess.indexes[i];
686 			b = tess.indexes[i+1];
687 			c = tess.indexes[i+2];
688 			if ( clipBits[a] & clipBits[b] & clipBits[c] ) {
689 				continue;	// not lighted
690 			}
691 			hitIndexes[numIndexes] = a;
692 			hitIndexes[numIndexes+1] = b;
693 			hitIndexes[numIndexes+2] = c;
694 			numIndexes += 3;
695 		}
696 
697 		if ( !numIndexes ) {
698 			continue;
699 		}
700 
701 		qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
702 		qglTexCoordPointer( 2, GL_FLOAT, 0, texCoordsArray[0] );
703 
704 		qglEnableClientState( GL_COLOR_ARRAY );
705 		qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, colorArray );
706 
707 		GL_Bind( tr.dlightImage );
708 		// include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light
709 		// where they aren't rendered
710 		if ( dl->additive ) {
711 			GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
712 		}
713 		else {
714 			GL_State( GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL );
715 		}
716 		R_DrawElements( numIndexes, hitIndexes );
717 		backEnd.pc.c_totalIndexes += numIndexes;
718 		backEnd.pc.c_dlightIndexes += numIndexes;
719 	}
720 }
721 
ProjectDlightTexture(void)722 static void ProjectDlightTexture( void ) {
723 #if idppc_altivec
724 	if (com_altivec->integer) {
725 		// must be in a seperate function or G3 systems will crash.
726 		ProjectDlightTexture_altivec();
727 		return;
728 	}
729 #endif
730 	ProjectDlightTexture_scalar();
731 }
732 
733 
734 /*
735 ===================
736 RB_FogPass
737 
738 Blends a fog texture on top of everything else
739 ===================
740 */
RB_FogPass(void)741 static void RB_FogPass( void ) {
742 	fog_t		*fog;
743 	int			i;
744 
745 	qglEnableClientState( GL_COLOR_ARRAY );
746 	qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors );
747 
748 	qglEnableClientState( GL_TEXTURE_COORD_ARRAY);
749 	qglTexCoordPointer( 2, GL_FLOAT, 0, tess.svars.texcoords[0] );
750 
751 	fog = tr.world->fogs + tess.fogNum;
752 
753 	for ( i = 0; i < tess.numVertexes; i++ ) {
754 		* ( int * )&tess.svars.colors[i] = fog->colorInt;
755 	}
756 
757 	RB_CalcFogTexCoords( ( float * ) tess.svars.texcoords[0] );
758 
759 	GL_Bind( tr.fogImage );
760 
761 	if ( tess.shader->fogPass == FP_EQUAL ) {
762 		GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA | GLS_DEPTHFUNC_EQUAL );
763 	} else {
764 		GL_State( GLS_SRCBLEND_SRC_ALPHA | GLS_DSTBLEND_ONE_MINUS_SRC_ALPHA );
765 	}
766 
767 	R_DrawElements( tess.numIndexes, tess.indexes );
768 }
769 
770 /*
771 ===============
772 ComputeColors
773 ===============
774 */
ComputeColors(shaderStage_t * pStage)775 static void ComputeColors( shaderStage_t *pStage )
776 {
777 	int		i;
778 
779 	//
780 	// rgbGen
781 	//
782 	switch ( pStage->rgbGen )
783 	{
784 		case CGEN_IDENTITY:
785 			Com_Memset( tess.svars.colors, 0xff, tess.numVertexes * 4 );
786 			break;
787 		default:
788 		case CGEN_IDENTITY_LIGHTING:
789 			Com_Memset( tess.svars.colors, tr.identityLightByte, tess.numVertexes * 4 );
790 			break;
791 		case CGEN_LIGHTING_DIFFUSE:
792 			RB_CalcDiffuseColor( ( unsigned char * ) tess.svars.colors );
793 			break;
794 		case CGEN_EXACT_VERTEX:
795 			Com_Memcpy( tess.svars.colors, tess.vertexColors, tess.numVertexes * sizeof( tess.vertexColors[0] ) );
796 			break;
797 		case CGEN_CONST:
798 			for ( i = 0; i < tess.numVertexes; i++ ) {
799 				*(int *)tess.svars.colors[i] = *(int *)pStage->constantColor;
800 			}
801 			break;
802 		case CGEN_VERTEX:
803 			if ( tr.identityLight == 1 )
804 			{
805 				Com_Memcpy( tess.svars.colors, tess.vertexColors, tess.numVertexes * sizeof( tess.vertexColors[0] ) );
806 			}
807 			else
808 			{
809 				for ( i = 0; i < tess.numVertexes; i++ )
810 				{
811 					tess.svars.colors[i][0] = tess.vertexColors[i][0] * tr.identityLight;
812 					tess.svars.colors[i][1] = tess.vertexColors[i][1] * tr.identityLight;
813 					tess.svars.colors[i][2] = tess.vertexColors[i][2] * tr.identityLight;
814 					tess.svars.colors[i][3] = tess.vertexColors[i][3];
815 				}
816 			}
817 			break;
818 		case CGEN_ONE_MINUS_VERTEX:
819 			if ( tr.identityLight == 1 )
820 			{
821 				for ( i = 0; i < tess.numVertexes; i++ )
822 				{
823 					tess.svars.colors[i][0] = 255 - tess.vertexColors[i][0];
824 					tess.svars.colors[i][1] = 255 - tess.vertexColors[i][1];
825 					tess.svars.colors[i][2] = 255 - tess.vertexColors[i][2];
826 				}
827 			}
828 			else
829 			{
830 				for ( i = 0; i < tess.numVertexes; i++ )
831 				{
832 					tess.svars.colors[i][0] = ( 255 - tess.vertexColors[i][0] ) * tr.identityLight;
833 					tess.svars.colors[i][1] = ( 255 - tess.vertexColors[i][1] ) * tr.identityLight;
834 					tess.svars.colors[i][2] = ( 255 - tess.vertexColors[i][2] ) * tr.identityLight;
835 				}
836 			}
837 			break;
838 		case CGEN_FOG:
839 			{
840 				fog_t		*fog;
841 
842 				fog = tr.world->fogs + tess.fogNum;
843 
844 				for ( i = 0; i < tess.numVertexes; i++ ) {
845 					* ( int * )&tess.svars.colors[i] = fog->colorInt;
846 				}
847 			}
848 			break;
849 		case CGEN_WAVEFORM:
850 			RB_CalcWaveColor( &pStage->rgbWave, ( unsigned char * ) tess.svars.colors );
851 			break;
852 		case CGEN_ENTITY:
853 			RB_CalcColorFromEntity( ( unsigned char * ) tess.svars.colors );
854 			break;
855 		case CGEN_ONE_MINUS_ENTITY:
856 			RB_CalcColorFromOneMinusEntity( ( unsigned char * ) tess.svars.colors );
857 			break;
858 	}
859 
860 	//
861 	// alphaGen
862 	//
863 	switch ( pStage->alphaGen )
864 	{
865 	case AGEN_SKIP:
866 		break;
867 	case AGEN_IDENTITY:
868 		if ( pStage->rgbGen != CGEN_IDENTITY ) {
869 			if ( ( pStage->rgbGen == CGEN_VERTEX && tr.identityLight != 1 ) ||
870 				 pStage->rgbGen != CGEN_VERTEX ) {
871 				for ( i = 0; i < tess.numVertexes; i++ ) {
872 					tess.svars.colors[i][3] = 0xff;
873 				}
874 			}
875 		}
876 		break;
877 	case AGEN_CONST:
878 		if ( pStage->rgbGen != CGEN_CONST ) {
879 			for ( i = 0; i < tess.numVertexes; i++ ) {
880 				tess.svars.colors[i][3] = pStage->constantColor[3];
881 			}
882 		}
883 		break;
884 	case AGEN_WAVEFORM:
885 		RB_CalcWaveAlpha( &pStage->alphaWave, ( unsigned char * ) tess.svars.colors );
886 		break;
887 	case AGEN_LIGHTING_SPECULAR:
888 		RB_CalcSpecularAlpha( ( unsigned char * ) tess.svars.colors );
889 		break;
890 	case AGEN_ENTITY:
891 		RB_CalcAlphaFromEntity( ( unsigned char * ) tess.svars.colors );
892 		break;
893 	case AGEN_ONE_MINUS_ENTITY:
894 		RB_CalcAlphaFromOneMinusEntity( ( unsigned char * ) tess.svars.colors );
895 		break;
896     case AGEN_VERTEX:
897 		if ( pStage->rgbGen != CGEN_VERTEX ) {
898 			for ( i = 0; i < tess.numVertexes; i++ ) {
899 				tess.svars.colors[i][3] = tess.vertexColors[i][3];
900 			}
901 		}
902         break;
903     case AGEN_ONE_MINUS_VERTEX:
904         for ( i = 0; i < tess.numVertexes; i++ )
905         {
906 			tess.svars.colors[i][3] = 255 - tess.vertexColors[i][3];
907         }
908         break;
909 	case AGEN_PORTAL:
910 		{
911 			unsigned char alpha;
912 
913 			for ( i = 0; i < tess.numVertexes; i++ )
914 			{
915 				float len;
916 				vec3_t v;
917 
918 				VectorSubtract( tess.xyz[i], backEnd.viewParms.or.origin, v );
919 				len = VectorLength( v );
920 
921 				len /= tess.shader->portalRange;
922 
923 				if ( len < 0 )
924 				{
925 					alpha = 0;
926 				}
927 				else if ( len > 1 )
928 				{
929 					alpha = 0xff;
930 				}
931 				else
932 				{
933 					alpha = len * 0xff;
934 				}
935 
936 				tess.svars.colors[i][3] = alpha;
937 			}
938 		}
939 		break;
940 	}
941 
942 	//
943 	// fog adjustment for colors to fade out as fog increases
944 	//
945 	if ( tess.fogNum )
946 	{
947 		switch ( pStage->adjustColorsForFog )
948 		{
949 		case ACFF_MODULATE_RGB:
950 			RB_CalcModulateColorsByFog( ( unsigned char * ) tess.svars.colors );
951 			break;
952 		case ACFF_MODULATE_ALPHA:
953 			RB_CalcModulateAlphasByFog( ( unsigned char * ) tess.svars.colors );
954 			break;
955 		case ACFF_MODULATE_RGBA:
956 			RB_CalcModulateRGBAsByFog( ( unsigned char * ) tess.svars.colors );
957 			break;
958 		case ACFF_NONE:
959 			break;
960 		}
961 	}
962 
963 	// if in greyscale rendering mode turn all color values into greyscale.
964 	if(r_greyscale->integer)
965 	{
966 		int scale;
967 
968 		for(i = 0; i < tess.numVertexes; i++)
969 		{
970 			scale = (tess.svars.colors[i][0] + tess.svars.colors[i][1] + tess.svars.colors[i][2]) / 3;
971 			tess.svars.colors[i][0] = tess.svars.colors[i][1] = tess.svars.colors[i][2] = scale;
972 		}
973 	}
974 }
975 
976 /*
977 ===============
978 ComputeTexCoords
979 ===============
980 */
ComputeTexCoords(shaderStage_t * pStage)981 static void ComputeTexCoords( shaderStage_t *pStage ) {
982 	int		i;
983 	int		b;
984 
985 	for ( b = 0; b < NUM_TEXTURE_BUNDLES; b++ ) {
986 		int tm;
987 
988 		//
989 		// generate the texture coordinates
990 		//
991 		switch ( pStage->bundle[b].tcGen )
992 		{
993 		case TCGEN_IDENTITY:
994 			Com_Memset( tess.svars.texcoords[b], 0, sizeof( float ) * 2 * tess.numVertexes );
995 			break;
996 		case TCGEN_TEXTURE:
997 			for ( i = 0 ; i < tess.numVertexes ; i++ ) {
998 				tess.svars.texcoords[b][i][0] = tess.texCoords[i][0][0];
999 				tess.svars.texcoords[b][i][1] = tess.texCoords[i][0][1];
1000 			}
1001 			break;
1002 		case TCGEN_LIGHTMAP:
1003 			for ( i = 0 ; i < tess.numVertexes ; i++ ) {
1004 				tess.svars.texcoords[b][i][0] = tess.texCoords[i][1][0];
1005 				tess.svars.texcoords[b][i][1] = tess.texCoords[i][1][1];
1006 			}
1007 			break;
1008 		case TCGEN_VECTOR:
1009 			for ( i = 0 ; i < tess.numVertexes ; i++ ) {
1010 				tess.svars.texcoords[b][i][0] = DotProduct( tess.xyz[i], pStage->bundle[b].tcGenVectors[0] );
1011 				tess.svars.texcoords[b][i][1] = DotProduct( tess.xyz[i], pStage->bundle[b].tcGenVectors[1] );
1012 			}
1013 			break;
1014 		case TCGEN_FOG:
1015 			RB_CalcFogTexCoords( ( float * ) tess.svars.texcoords[b] );
1016 			break;
1017 		case TCGEN_ENVIRONMENT_MAPPED:
1018 			RB_CalcEnvironmentTexCoords( ( float * ) tess.svars.texcoords[b] );
1019 			break;
1020 		case TCGEN_BAD:
1021 			return;
1022 		}
1023 
1024 		//
1025 		// alter texture coordinates
1026 		//
1027 		for ( tm = 0; tm < pStage->bundle[b].numTexMods ; tm++ ) {
1028 			switch ( pStage->bundle[b].texMods[tm].type )
1029 			{
1030 			case TMOD_NONE:
1031 				tm = TR_MAX_TEXMODS;		// break out of for loop
1032 				break;
1033 
1034 			case TMOD_TURBULENT:
1035 				RB_CalcTurbulentTexCoords( &pStage->bundle[b].texMods[tm].wave,
1036 						                 ( float * ) tess.svars.texcoords[b] );
1037 				break;
1038 
1039 			case TMOD_ENTITY_TRANSLATE:
1040 				RB_CalcScrollTexCoords( backEnd.currentEntity->e.shaderTexCoord,
1041 									 ( float * ) tess.svars.texcoords[b] );
1042 				break;
1043 
1044 			case TMOD_SCROLL:
1045 				RB_CalcScrollTexCoords( pStage->bundle[b].texMods[tm].scroll,
1046 										 ( float * ) tess.svars.texcoords[b] );
1047 				break;
1048 
1049 			case TMOD_SCALE:
1050 				RB_CalcScaleTexCoords( pStage->bundle[b].texMods[tm].scale,
1051 									 ( float * ) tess.svars.texcoords[b] );
1052 				break;
1053 
1054 			case TMOD_STRETCH:
1055 				RB_CalcStretchTexCoords( &pStage->bundle[b].texMods[tm].wave,
1056 						               ( float * ) tess.svars.texcoords[b] );
1057 				break;
1058 
1059 			case TMOD_TRANSFORM:
1060 				RB_CalcTransformTexCoords( &pStage->bundle[b].texMods[tm],
1061 						                 ( float * ) tess.svars.texcoords[b] );
1062 				break;
1063 
1064 			case TMOD_ROTATE:
1065 				RB_CalcRotateTexCoords( pStage->bundle[b].texMods[tm].rotateSpeed,
1066 										( float * ) tess.svars.texcoords[b] );
1067 				break;
1068 
1069 			default:
1070 				ri.Error( ERR_DROP, "ERROR: unknown texmod '%d' in shader '%s'\n", pStage->bundle[b].texMods[tm].type, tess.shader->name );
1071 				break;
1072 			}
1073 		}
1074 	}
1075 }
1076 
1077 /*
1078 ** RB_IterateStagesGeneric
1079 */
RB_IterateStagesGeneric(shaderCommands_t * input)1080 static void RB_IterateStagesGeneric( shaderCommands_t *input )
1081 {
1082 	int stage;
1083 
1084 	for ( stage = 0; stage < MAX_SHADER_STAGES; stage++ )
1085 	{
1086 		shaderStage_t *pStage = tess.xstages[stage];
1087 
1088 		if ( !pStage )
1089 		{
1090 			break;
1091 		}
1092 
1093 		ComputeColors( pStage );
1094 		ComputeTexCoords( pStage );
1095 
1096 		if ( !setArraysOnce )
1097 		{
1098 			qglEnableClientState( GL_COLOR_ARRAY );
1099 			qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, input->svars.colors );
1100 		}
1101 
1102 		//
1103 		// do multitexture
1104 		//
1105 		if ( pStage->bundle[1].image[0] != 0 )
1106 		{
1107 			DrawMultitextured( input, stage );
1108 		}
1109 		else
1110 		{
1111 			if ( !setArraysOnce )
1112 			{
1113 				qglTexCoordPointer( 2, GL_FLOAT, 0, input->svars.texcoords[0] );
1114 			}
1115 
1116 			//
1117 			// set state
1118 			//
1119 			if ( pStage->bundle[0].vertexLightmap && ( (r_vertexLight->integer && !r_uiFullScreen->integer) || glConfig.hardwareType == GLHW_PERMEDIA2 ) && r_lightmap->integer )
1120 			{
1121 				GL_Bind( tr.whiteImage );
1122 			}
1123 			else
1124 				R_BindAnimatedImage( &pStage->bundle[0] );
1125 
1126 			GL_State( pStage->stateBits );
1127 
1128 			//
1129 			// draw
1130 			//
1131 			R_DrawElements( input->numIndexes, input->indexes );
1132 		}
1133 		// allow skipping out to show just lightmaps during development
1134 		if ( r_lightmap->integer && ( pStage->bundle[0].isLightmap || pStage->bundle[1].isLightmap || pStage->bundle[0].vertexLightmap ) )
1135 		{
1136 			break;
1137 		}
1138 	}
1139 }
1140 
1141 
1142 /*
1143 ** RB_StageIteratorGeneric
1144 */
RB_StageIteratorGeneric(void)1145 void RB_StageIteratorGeneric( void )
1146 {
1147 	shaderCommands_t *input;
1148 
1149 	input = &tess;
1150 
1151 	RB_DeformTessGeometry();
1152 
1153 	//
1154 	// log this call
1155 	//
1156 	if ( r_logFile->integer )
1157 	{
1158 		// don't just call LogComment, or we will get
1159 		// a call to va() every frame!
1160 		GLimp_LogComment( va("--- RB_StageIteratorGeneric( %s ) ---\n", tess.shader->name) );
1161 	}
1162 
1163 	//
1164 	// set face culling appropriately
1165 	//
1166 	GL_Cull( input->shader->cullType );
1167 
1168 	// set polygon offset if necessary
1169 	if ( input->shader->polygonOffset )
1170 	{
1171 		qglEnable( GL_POLYGON_OFFSET_FILL );
1172 		qglPolygonOffset( r_offsetFactor->value, r_offsetUnits->value );
1173 	}
1174 
1175 	//
1176 	// if there is only a single pass then we can enable color
1177 	// and texture arrays before we compile, otherwise we need
1178 	// to avoid compiling those arrays since they will change
1179 	// during multipass rendering
1180 	//
1181 	if ( tess.numPasses > 1 || input->shader->multitextureEnv )
1182 	{
1183 		setArraysOnce = qfalse;
1184 		qglDisableClientState (GL_COLOR_ARRAY);
1185 		qglDisableClientState (GL_TEXTURE_COORD_ARRAY);
1186 	}
1187 	else
1188 	{
1189 		setArraysOnce = qtrue;
1190 
1191 		qglEnableClientState( GL_COLOR_ARRAY);
1192 		qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors );
1193 
1194 		qglEnableClientState( GL_TEXTURE_COORD_ARRAY);
1195 		qglTexCoordPointer( 2, GL_FLOAT, 0, tess.svars.texcoords[0] );
1196 	}
1197 
1198 	//
1199 	// lock XYZ
1200 	//
1201 	qglVertexPointer (3, GL_FLOAT, 16, input->xyz);	// padded for SIMD
1202 	if (qglLockArraysEXT)
1203 	{
1204 		qglLockArraysEXT(0, input->numVertexes);
1205 		GLimp_LogComment( "glLockArraysEXT\n" );
1206 	}
1207 
1208 	//
1209 	// enable color and texcoord arrays after the lock if necessary
1210 	//
1211 	if ( !setArraysOnce )
1212 	{
1213 		qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
1214 		qglEnableClientState( GL_COLOR_ARRAY );
1215 	}
1216 
1217 	//
1218 	// call shader function
1219 	//
1220 	RB_IterateStagesGeneric( input );
1221 
1222 	//
1223 	// now do any dynamic lighting needed
1224 	//
1225 	if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE
1226 		&& !(tess.shader->surfaceFlags & (SURF_NODLIGHT | SURF_SKY) ) ) {
1227 		ProjectDlightTexture();
1228 	}
1229 
1230 	//
1231 	// now do fog
1232 	//
1233 	if ( tess.fogNum && tess.shader->fogPass ) {
1234 		RB_FogPass();
1235 	}
1236 
1237 	//
1238 	// unlock arrays
1239 	//
1240 	if (qglUnlockArraysEXT)
1241 	{
1242 		qglUnlockArraysEXT();
1243 		GLimp_LogComment( "glUnlockArraysEXT\n" );
1244 	}
1245 
1246 	//
1247 	// reset polygon offset
1248 	//
1249 	if ( input->shader->polygonOffset )
1250 	{
1251 		qglDisable( GL_POLYGON_OFFSET_FILL );
1252 	}
1253 }
1254 
1255 
1256 /*
1257 ** RB_StageIteratorVertexLitTexture
1258 */
RB_StageIteratorVertexLitTexture(void)1259 void RB_StageIteratorVertexLitTexture( void )
1260 {
1261 	shaderCommands_t *input;
1262 	shader_t		*shader;
1263 
1264 	input = &tess;
1265 
1266 	shader = input->shader;
1267 
1268 	//
1269 	// compute colors
1270 	//
1271 	RB_CalcDiffuseColor( ( unsigned char * ) tess.svars.colors );
1272 
1273 	//
1274 	// log this call
1275 	//
1276 	if ( r_logFile->integer )
1277 	{
1278 		// don't just call LogComment, or we will get
1279 		// a call to va() every frame!
1280 		GLimp_LogComment( va("--- RB_StageIteratorVertexLitTexturedUnfogged( %s ) ---\n", tess.shader->name) );
1281 	}
1282 
1283 	//
1284 	// set face culling appropriately
1285 	//
1286 	GL_Cull( input->shader->cullType );
1287 
1288 	//
1289 	// set arrays and lock
1290 	//
1291 	qglEnableClientState( GL_COLOR_ARRAY);
1292 	qglEnableClientState( GL_TEXTURE_COORD_ARRAY);
1293 
1294 	qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.svars.colors );
1295 	qglTexCoordPointer( 2, GL_FLOAT, 16, tess.texCoords[0][0] );
1296 	qglVertexPointer (3, GL_FLOAT, 16, input->xyz);
1297 
1298 	if ( qglLockArraysEXT )
1299 	{
1300 		qglLockArraysEXT(0, input->numVertexes);
1301 		GLimp_LogComment( "glLockArraysEXT\n" );
1302 	}
1303 
1304 	//
1305 	// call special shade routine
1306 	//
1307 	R_BindAnimatedImage( &tess.xstages[0]->bundle[0] );
1308 	GL_State( tess.xstages[0]->stateBits );
1309 	R_DrawElements( input->numIndexes, input->indexes );
1310 
1311 	//
1312 	// now do any dynamic lighting needed
1313 	//
1314 	if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE ) {
1315 		ProjectDlightTexture();
1316 	}
1317 
1318 	//
1319 	// now do fog
1320 	//
1321 	if ( tess.fogNum && tess.shader->fogPass ) {
1322 		RB_FogPass();
1323 	}
1324 
1325 	//
1326 	// unlock arrays
1327 	//
1328 	if (qglUnlockArraysEXT)
1329 	{
1330 		qglUnlockArraysEXT();
1331 		GLimp_LogComment( "glUnlockArraysEXT\n" );
1332 	}
1333 }
1334 
1335 //define	REPLACE_MODE
1336 
RB_StageIteratorLightmappedMultitexture(void)1337 void RB_StageIteratorLightmappedMultitexture( void ) {
1338 	shaderCommands_t *input;
1339 
1340 	input = &tess;
1341 
1342 	//
1343 	// log this call
1344 	//
1345 	if ( r_logFile->integer ) {
1346 		// don't just call LogComment, or we will get
1347 		// a call to va() every frame!
1348 		GLimp_LogComment( va("--- RB_StageIteratorLightmappedMultitexture( %s ) ---\n", tess.shader->name) );
1349 	}
1350 
1351 	//
1352 	// set face culling appropriately
1353 	//
1354 	GL_Cull( input->shader->cullType );
1355 
1356 	//
1357 	// set color, pointers, and lock
1358 	//
1359 	GL_State( GLS_DEFAULT );
1360 	qglVertexPointer( 3, GL_FLOAT, 16, input->xyz );
1361 
1362 #ifdef REPLACE_MODE
1363 	qglDisableClientState( GL_COLOR_ARRAY );
1364 	qglColor3f( 1, 1, 1 );
1365 	qglShadeModel( GL_FLAT );
1366 #else
1367 	qglEnableClientState( GL_COLOR_ARRAY );
1368 	qglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tess.constantColor255 );
1369 #endif
1370 
1371 	//
1372 	// select base stage
1373 	//
1374 	GL_SelectTexture( 0 );
1375 
1376 	qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
1377 	R_BindAnimatedImage( &tess.xstages[0]->bundle[0] );
1378 	qglTexCoordPointer( 2, GL_FLOAT, 16, tess.texCoords[0][0] );
1379 
1380 	//
1381 	// configure second stage
1382 	//
1383 	GL_SelectTexture( 1 );
1384 	qglEnable( GL_TEXTURE_2D );
1385 	if ( r_lightmap->integer ) {
1386 		GL_TexEnv( GL_REPLACE );
1387 	} else {
1388 		GL_TexEnv( GL_MODULATE );
1389 	}
1390 	R_BindAnimatedImage( &tess.xstages[0]->bundle[1] );
1391 	qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
1392 	qglTexCoordPointer( 2, GL_FLOAT, 16, tess.texCoords[0][1] );
1393 
1394 	//
1395 	// lock arrays
1396 	//
1397 	if ( qglLockArraysEXT ) {
1398 		qglLockArraysEXT(0, input->numVertexes);
1399 		GLimp_LogComment( "glLockArraysEXT\n" );
1400 	}
1401 
1402 	R_DrawElements( input->numIndexes, input->indexes );
1403 
1404 	//
1405 	// disable texturing on TEXTURE1, then select TEXTURE0
1406 	//
1407 	qglDisable( GL_TEXTURE_2D );
1408 	qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
1409 
1410 	GL_SelectTexture( 0 );
1411 #ifdef REPLACE_MODE
1412 	GL_TexEnv( GL_MODULATE );
1413 	qglShadeModel( GL_SMOOTH );
1414 #endif
1415 
1416 	//
1417 	// now do any dynamic lighting needed
1418 	//
1419 	if ( tess.dlightBits && tess.shader->sort <= SS_OPAQUE ) {
1420 		ProjectDlightTexture();
1421 	}
1422 
1423 	//
1424 	// now do fog
1425 	//
1426 	if ( tess.fogNum && tess.shader->fogPass ) {
1427 		RB_FogPass();
1428 	}
1429 
1430 	//
1431 	// unlock arrays
1432 	//
1433 	if ( qglUnlockArraysEXT ) {
1434 		qglUnlockArraysEXT();
1435 		GLimp_LogComment( "glUnlockArraysEXT\n" );
1436 	}
1437 }
1438 
1439 /*
1440 ** RB_EndSurface
1441 */
RB_EndSurface(void)1442 void RB_EndSurface( void ) {
1443 	shaderCommands_t *input;
1444 
1445 	input = &tess;
1446 
1447 	if (input->numIndexes == 0) {
1448 		return;
1449 	}
1450 
1451 	if (input->indexes[SHADER_MAX_INDEXES-1] != 0) {
1452 		ri.Error (ERR_DROP, "RB_EndSurface() - SHADER_MAX_INDEXES hit");
1453 	}
1454 	if (input->xyz[SHADER_MAX_VERTEXES-1][0] != 0) {
1455 		ri.Error (ERR_DROP, "RB_EndSurface() - SHADER_MAX_VERTEXES hit");
1456 	}
1457 
1458 	if ( tess.shader == tr.shadowShader ) {
1459 		RB_ShadowTessEnd();
1460 		return;
1461 	}
1462 
1463 	// for debugging of sort order issues, stop rendering after a given sort value
1464 	if ( r_debugSort->integer && r_debugSort->integer < tess.shader->sort ) {
1465 		return;
1466 	}
1467 
1468 	//
1469 	// update performance counters
1470 	//
1471 	backEnd.pc.c_shaders++;
1472 	backEnd.pc.c_vertexes += tess.numVertexes;
1473 	backEnd.pc.c_indexes += tess.numIndexes;
1474 	backEnd.pc.c_totalIndexes += tess.numIndexes * tess.numPasses;
1475 
1476 	//
1477 	// call off to shader specific tess end function
1478 	//
1479 	tess.currentStageIteratorFunc();
1480 
1481 	//
1482 	// draw debugging stuff
1483 	//
1484 	if ( r_showtris->integer ) {
1485 		DrawTris (input);
1486 	}
1487 	if ( r_shownormals->integer ) {
1488 		DrawNormals (input);
1489 	}
1490 	// clear shader so we can tell we don't have any unclosed surfaces
1491 	tess.numIndexes = 0;
1492 
1493 	GLimp_LogComment( "----------\n" );
1494 }
1495 
1496