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