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_calc.c
23
24 #include "tr_local.h"
25 #if idppc_altivec && !defined(MACOS_X)
26 #include <altivec.h>
27 #endif
28
29
30 #define WAVEVALUE( table, base, amplitude, phase, freq ) ((base) + table[ myftol( ( ( (phase) + tess.shaderTime * (freq) ) * FUNCTABLE_SIZE ) ) & FUNCTABLE_MASK ] * (amplitude))
31
TableForFunc(genFunc_t func)32 static float *TableForFunc( genFunc_t func )
33 {
34 switch ( func )
35 {
36 case GF_SIN:
37 return tr.sinTable;
38 case GF_TRIANGLE:
39 return tr.triangleTable;
40 case GF_SQUARE:
41 return tr.squareTable;
42 case GF_SAWTOOTH:
43 return tr.sawToothTable;
44 case GF_INVERSE_SAWTOOTH:
45 return tr.inverseSawToothTable;
46 case GF_NONE:
47 default:
48 break;
49 }
50
51 ri.Error( ERR_DROP, "TableForFunc called with invalid function '%d' in shader '%s'\n", func, tess.shader->name );
52 return NULL;
53 }
54
55 /*
56 ** EvalWaveForm
57 **
58 ** Evaluates a given waveForm_t, referencing backEnd.refdef.time directly
59 */
EvalWaveForm(const waveForm_t * wf)60 static float EvalWaveForm( const waveForm_t *wf )
61 {
62 float *table;
63
64 table = TableForFunc( wf->func );
65
66 return WAVEVALUE( table, wf->base, wf->amplitude, wf->phase, wf->frequency );
67 }
68
EvalWaveFormClamped(const waveForm_t * wf)69 static float EvalWaveFormClamped( const waveForm_t *wf )
70 {
71 float glow = EvalWaveForm( wf );
72
73 if ( glow < 0 )
74 {
75 return 0;
76 }
77
78 if ( glow > 1 )
79 {
80 return 1;
81 }
82
83 return glow;
84 }
85
86 /*
87 ** RB_CalcStretchTexCoords
88 */
RB_CalcStretchTexCoords(const waveForm_t * wf,float * st)89 void RB_CalcStretchTexCoords( const waveForm_t *wf, float *st )
90 {
91 float p;
92 texModInfo_t tmi;
93
94 p = 1.0f / EvalWaveForm( wf );
95
96 tmi.matrix[0][0] = p;
97 tmi.matrix[1][0] = 0;
98 tmi.translate[0] = 0.5f - 0.5f * p;
99
100 tmi.matrix[0][1] = 0;
101 tmi.matrix[1][1] = p;
102 tmi.translate[1] = 0.5f - 0.5f * p;
103
104 RB_CalcTransformTexCoords( &tmi, st );
105 }
106
107 /*
108 ====================================================================
109
110 DEFORMATIONS
111
112 ====================================================================
113 */
114
115 /*
116 ========================
117 RB_CalcDeformVertexes
118
119 ========================
120 */
RB_CalcDeformVertexes(deformStage_t * ds)121 void RB_CalcDeformVertexes( deformStage_t *ds )
122 {
123 int i;
124 vec3_t offset;
125 float scale;
126 float *xyz = ( float * ) tess.xyz;
127 float *normal = ( float * ) tess.normal;
128 float *table;
129
130 if ( ds->deformationWave.frequency == 0 )
131 {
132 scale = EvalWaveForm( &ds->deformationWave );
133
134 for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 )
135 {
136 VectorScale( normal, scale, offset );
137
138 xyz[0] += offset[0];
139 xyz[1] += offset[1];
140 xyz[2] += offset[2];
141 }
142 }
143 else
144 {
145 table = TableForFunc( ds->deformationWave.func );
146
147 for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 )
148 {
149 float off = ( xyz[0] + xyz[1] + xyz[2] ) * ds->deformationSpread;
150
151 scale = WAVEVALUE( table, ds->deformationWave.base,
152 ds->deformationWave.amplitude,
153 ds->deformationWave.phase + off,
154 ds->deformationWave.frequency );
155
156 VectorScale( normal, scale, offset );
157
158 xyz[0] += offset[0];
159 xyz[1] += offset[1];
160 xyz[2] += offset[2];
161 }
162 }
163 }
164
165 /*
166 =========================
167 RB_CalcDeformNormals
168
169 Wiggle the normals for wavy environment mapping
170 =========================
171 */
RB_CalcDeformNormals(deformStage_t * ds)172 void RB_CalcDeformNormals( deformStage_t *ds ) {
173 int i;
174 float scale;
175 float *xyz = ( float * ) tess.xyz;
176 float *normal = ( float * ) tess.normal;
177
178 for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 ) {
179 scale = 0.98f;
180 scale = R_NoiseGet4f( xyz[0] * scale, xyz[1] * scale, xyz[2] * scale,
181 tess.shaderTime * ds->deformationWave.frequency );
182 normal[ 0 ] += ds->deformationWave.amplitude * scale;
183
184 scale = 0.98f;
185 scale = R_NoiseGet4f( 100 + xyz[0] * scale, xyz[1] * scale, xyz[2] * scale,
186 tess.shaderTime * ds->deformationWave.frequency );
187 normal[ 1 ] += ds->deformationWave.amplitude * scale;
188
189 scale = 0.98f;
190 scale = R_NoiseGet4f( 200 + xyz[0] * scale, xyz[1] * scale, xyz[2] * scale,
191 tess.shaderTime * ds->deformationWave.frequency );
192 normal[ 2 ] += ds->deformationWave.amplitude * scale;
193
194 VectorNormalizeFast( normal );
195 }
196 }
197
198 /*
199 ========================
200 RB_CalcBulgeVertexes
201
202 ========================
203 */
RB_CalcBulgeVertexes(deformStage_t * ds)204 void RB_CalcBulgeVertexes( deformStage_t *ds ) {
205 int i;
206 const float *st = ( const float * ) tess.texCoords[0];
207 float *xyz = ( float * ) tess.xyz;
208 float *normal = ( float * ) tess.normal;
209 float now;
210
211 now = backEnd.refdef.time * ds->bulgeSpeed * 0.001f;
212
213 for ( i = 0; i < tess.numVertexes; i++, xyz += 4, st += 4, normal += 4 ) {
214 int off;
215 float scale;
216
217 off = (float)( FUNCTABLE_SIZE / (M_PI*2) ) * ( st[0] * ds->bulgeWidth + now );
218
219 scale = tr.sinTable[ off & FUNCTABLE_MASK ] * ds->bulgeHeight;
220
221 xyz[0] += normal[0] * scale;
222 xyz[1] += normal[1] * scale;
223 xyz[2] += normal[2] * scale;
224 }
225 }
226
227
228 /*
229 ======================
230 RB_CalcMoveVertexes
231
232 A deformation that can move an entire surface along a wave path
233 ======================
234 */
RB_CalcMoveVertexes(deformStage_t * ds)235 void RB_CalcMoveVertexes( deformStage_t *ds ) {
236 int i;
237 float *xyz;
238 float *table;
239 float scale;
240 vec3_t offset;
241
242 table = TableForFunc( ds->deformationWave.func );
243
244 scale = WAVEVALUE( table, ds->deformationWave.base,
245 ds->deformationWave.amplitude,
246 ds->deformationWave.phase,
247 ds->deformationWave.frequency );
248
249 VectorScale( ds->moveVector, scale, offset );
250
251 xyz = ( float * ) tess.xyz;
252 for ( i = 0; i < tess.numVertexes; i++, xyz += 4 ) {
253 VectorAdd( xyz, offset, xyz );
254 }
255 }
256
257
258 /*
259 =============
260 DeformText
261
262 Change a polygon into a bunch of text polygons
263 =============
264 */
DeformText(const char * text)265 void DeformText( const char *text ) {
266 int i;
267 vec3_t origin, width, height;
268 int len;
269 int ch;
270 byte color[4];
271 float bottom, top;
272 vec3_t mid;
273
274 height[0] = 0;
275 height[1] = 0;
276 height[2] = -1;
277 CrossProduct( tess.normal[0], height, width );
278
279 // find the midpoint of the box
280 VectorClear( mid );
281 bottom = 999999;
282 top = -999999;
283 for ( i = 0 ; i < 4 ; i++ ) {
284 VectorAdd( tess.xyz[i], mid, mid );
285 if ( tess.xyz[i][2] < bottom ) {
286 bottom = tess.xyz[i][2];
287 }
288 if ( tess.xyz[i][2] > top ) {
289 top = tess.xyz[i][2];
290 }
291 }
292 VectorScale( mid, 0.25f, origin );
293
294 // determine the individual character size
295 height[0] = 0;
296 height[1] = 0;
297 height[2] = ( top - bottom ) * 0.5f;
298
299 VectorScale( width, height[2] * -0.75f, width );
300
301 // determine the starting position
302 len = strlen( text );
303 VectorMA( origin, (len-1), width, origin );
304
305 // clear the shader indexes
306 tess.numIndexes = 0;
307 tess.numVertexes = 0;
308
309 color[0] = color[1] = color[2] = color[3] = 255;
310
311 // draw each character
312 for ( i = 0 ; i < len ; i++ ) {
313 ch = text[i];
314 ch &= 255;
315
316 if ( ch != ' ' ) {
317 int row, col;
318 float frow, fcol, size;
319
320 row = ch>>4;
321 col = ch&15;
322
323 frow = row*0.0625f;
324 fcol = col*0.0625f;
325 size = 0.0625f;
326
327 RB_AddQuadStampExt( origin, width, height, color, fcol, frow, fcol + size, frow + size );
328 }
329 VectorMA( origin, -2, width, origin );
330 }
331 }
332
333 /*
334 ==================
335 GlobalVectorToLocal
336 ==================
337 */
GlobalVectorToLocal(const vec3_t in,vec3_t out)338 static void GlobalVectorToLocal( const vec3_t in, vec3_t out ) {
339 out[0] = DotProduct( in, backEnd.or.axis[0] );
340 out[1] = DotProduct( in, backEnd.or.axis[1] );
341 out[2] = DotProduct( in, backEnd.or.axis[2] );
342 }
343
344 /*
345 =====================
346 AutospriteDeform
347
348 Assuming all the triangles for this shader are independant
349 quads, rebuild them as forward facing sprites
350 =====================
351 */
AutospriteDeform(void)352 static void AutospriteDeform( void ) {
353 int i;
354 int oldVerts;
355 float *xyz;
356 vec3_t mid, delta;
357 float radius;
358 vec3_t left, up;
359 vec3_t leftDir, upDir;
360
361 if ( tess.numVertexes & 3 ) {
362 ri.Printf( PRINT_WARNING, "Autosprite shader %s had odd vertex count\n", tess.shader->name );
363 }
364 if ( tess.numIndexes != ( tess.numVertexes >> 2 ) * 6 ) {
365 ri.Printf( PRINT_WARNING, "Autosprite shader %s had odd index count\n", tess.shader->name );
366 }
367
368 oldVerts = tess.numVertexes;
369 tess.numVertexes = 0;
370 tess.numIndexes = 0;
371
372 if ( backEnd.currentEntity != &tr.worldEntity ) {
373 GlobalVectorToLocal( backEnd.viewParms.or.axis[1], leftDir );
374 GlobalVectorToLocal( backEnd.viewParms.or.axis[2], upDir );
375 } else {
376 VectorCopy( backEnd.viewParms.or.axis[1], leftDir );
377 VectorCopy( backEnd.viewParms.or.axis[2], upDir );
378 }
379
380 for ( i = 0 ; i < oldVerts ; i+=4 ) {
381 // find the midpoint
382 xyz = tess.xyz[i];
383
384 mid[0] = 0.25f * (xyz[0] + xyz[4] + xyz[8] + xyz[12]);
385 mid[1] = 0.25f * (xyz[1] + xyz[5] + xyz[9] + xyz[13]);
386 mid[2] = 0.25f * (xyz[2] + xyz[6] + xyz[10] + xyz[14]);
387
388 VectorSubtract( xyz, mid, delta );
389 radius = VectorLength( delta ) * 0.707f; // / sqrt(2)
390
391 VectorScale( leftDir, radius, left );
392 VectorScale( upDir, radius, up );
393
394 if ( backEnd.viewParms.isMirror ) {
395 VectorSubtract( vec3_origin, left, left );
396 }
397
398 // compensate for scale in the axes if necessary
399 if ( backEnd.currentEntity->e.nonNormalizedAxes ) {
400 float axisLength;
401 axisLength = VectorLength( backEnd.currentEntity->e.axis[0] );
402 if ( !axisLength ) {
403 axisLength = 0;
404 } else {
405 axisLength = 1.0f / axisLength;
406 }
407 VectorScale(left, axisLength, left);
408 VectorScale(up, axisLength, up);
409 }
410
411 RB_AddQuadStamp( mid, left, up, tess.vertexColors[i] );
412 }
413 }
414
415
416 /*
417 =====================
418 Autosprite2Deform
419
420 Autosprite2 will pivot a rectangular quad along the center of its long axis
421 =====================
422 */
423 int edgeVerts[6][2] = {
424 { 0, 1 },
425 { 0, 2 },
426 { 0, 3 },
427 { 1, 2 },
428 { 1, 3 },
429 { 2, 3 }
430 };
431
Autosprite2Deform(void)432 static void Autosprite2Deform( void ) {
433 int i, j, k;
434 int indexes;
435 float *xyz;
436 vec3_t forward;
437
438 if ( tess.numVertexes & 3 ) {
439 ri.Printf( PRINT_WARNING, "Autosprite2 shader %s had odd vertex count", tess.shader->name );
440 }
441 if ( tess.numIndexes != ( tess.numVertexes >> 2 ) * 6 ) {
442 ri.Printf( PRINT_WARNING, "Autosprite2 shader %s had odd index count", tess.shader->name );
443 }
444
445 if ( backEnd.currentEntity != &tr.worldEntity ) {
446 GlobalVectorToLocal( backEnd.viewParms.or.axis[0], forward );
447 } else {
448 VectorCopy( backEnd.viewParms.or.axis[0], forward );
449 }
450
451 // this is a lot of work for two triangles...
452 // we could precalculate a lot of it is an issue, but it would mess up
453 // the shader abstraction
454 for ( i = 0, indexes = 0 ; i < tess.numVertexes ; i+=4, indexes+=6 ) {
455 float lengths[2];
456 int nums[2];
457 vec3_t mid[2];
458 vec3_t major, minor;
459 float *v1, *v2;
460
461 // find the midpoint
462 xyz = tess.xyz[i];
463
464 // identify the two shortest edges
465 nums[0] = nums[1] = 0;
466 lengths[0] = lengths[1] = 999999;
467
468 for ( j = 0 ; j < 6 ; j++ ) {
469 float l;
470 vec3_t temp;
471
472 v1 = xyz + 4 * edgeVerts[j][0];
473 v2 = xyz + 4 * edgeVerts[j][1];
474
475 VectorSubtract( v1, v2, temp );
476
477 l = DotProduct( temp, temp );
478 if ( l < lengths[0] ) {
479 nums[1] = nums[0];
480 lengths[1] = lengths[0];
481 nums[0] = j;
482 lengths[0] = l;
483 } else if ( l < lengths[1] ) {
484 nums[1] = j;
485 lengths[1] = l;
486 }
487 }
488
489 for ( j = 0 ; j < 2 ; j++ ) {
490 v1 = xyz + 4 * edgeVerts[nums[j]][0];
491 v2 = xyz + 4 * edgeVerts[nums[j]][1];
492
493 mid[j][0] = 0.5f * (v1[0] + v2[0]);
494 mid[j][1] = 0.5f * (v1[1] + v2[1]);
495 mid[j][2] = 0.5f * (v1[2] + v2[2]);
496 }
497
498 // find the vector of the major axis
499 VectorSubtract( mid[1], mid[0], major );
500
501 // cross this with the view direction to get minor axis
502 CrossProduct( major, forward, minor );
503 VectorNormalize( minor );
504
505 // re-project the points
506 for ( j = 0 ; j < 2 ; j++ ) {
507 float l;
508
509 v1 = xyz + 4 * edgeVerts[nums[j]][0];
510 v2 = xyz + 4 * edgeVerts[nums[j]][1];
511
512 l = 0.5 * sqrt( lengths[j] );
513
514 // we need to see which direction this edge
515 // is used to determine direction of projection
516 for ( k = 0 ; k < 5 ; k++ ) {
517 if ( tess.indexes[ indexes + k ] == i + edgeVerts[nums[j]][0]
518 && tess.indexes[ indexes + k + 1 ] == i + edgeVerts[nums[j]][1] ) {
519 break;
520 }
521 }
522
523 if ( k == 5 ) {
524 VectorMA( mid[j], l, minor, v1 );
525 VectorMA( mid[j], -l, minor, v2 );
526 } else {
527 VectorMA( mid[j], -l, minor, v1 );
528 VectorMA( mid[j], l, minor, v2 );
529 }
530 }
531 }
532 }
533
534
535 /*
536 =====================
537 RB_DeformTessGeometry
538
539 =====================
540 */
RB_DeformTessGeometry(void)541 void RB_DeformTessGeometry( void ) {
542 int i;
543 deformStage_t *ds;
544
545 for ( i = 0 ; i < tess.shader->numDeforms ; i++ ) {
546 ds = &tess.shader->deforms[ i ];
547
548 switch ( ds->deformation ) {
549 case DEFORM_NONE:
550 break;
551 case DEFORM_NORMALS:
552 RB_CalcDeformNormals( ds );
553 break;
554 case DEFORM_WAVE:
555 RB_CalcDeformVertexes( ds );
556 break;
557 case DEFORM_BULGE:
558 RB_CalcBulgeVertexes( ds );
559 break;
560 case DEFORM_MOVE:
561 RB_CalcMoveVertexes( ds );
562 break;
563 case DEFORM_PROJECTION_SHADOW:
564 RB_ProjectionShadowDeform();
565 break;
566 case DEFORM_AUTOSPRITE:
567 AutospriteDeform();
568 break;
569 case DEFORM_AUTOSPRITE2:
570 Autosprite2Deform();
571 break;
572 case DEFORM_TEXT0:
573 case DEFORM_TEXT1:
574 case DEFORM_TEXT2:
575 case DEFORM_TEXT3:
576 case DEFORM_TEXT4:
577 case DEFORM_TEXT5:
578 case DEFORM_TEXT6:
579 case DEFORM_TEXT7:
580 DeformText( backEnd.refdef.text[ds->deformation - DEFORM_TEXT0] );
581 break;
582 }
583 }
584 }
585
586 /*
587 ====================================================================
588
589 COLORS
590
591 ====================================================================
592 */
593
594
595 /*
596 ** RB_CalcColorFromEntity
597 */
RB_CalcColorFromEntity(unsigned char * dstColors)598 void RB_CalcColorFromEntity( unsigned char *dstColors )
599 {
600 int i;
601 int *pColors = ( int * ) dstColors;
602 int c;
603
604 if ( !backEnd.currentEntity )
605 return;
606
607 c = * ( int * ) backEnd.currentEntity->e.shaderRGBA;
608
609 for ( i = 0; i < tess.numVertexes; i++, pColors++ )
610 {
611 *pColors = c;
612 }
613 }
614
615 /*
616 ** RB_CalcColorFromOneMinusEntity
617 */
RB_CalcColorFromOneMinusEntity(unsigned char * dstColors)618 void RB_CalcColorFromOneMinusEntity( unsigned char *dstColors )
619 {
620 int i;
621 int *pColors = ( int * ) dstColors;
622 unsigned char invModulate[4];
623 int c;
624
625 if ( !backEnd.currentEntity )
626 return;
627
628 invModulate[0] = 255 - backEnd.currentEntity->e.shaderRGBA[0];
629 invModulate[1] = 255 - backEnd.currentEntity->e.shaderRGBA[1];
630 invModulate[2] = 255 - backEnd.currentEntity->e.shaderRGBA[2];
631 invModulate[3] = 255 - backEnd.currentEntity->e.shaderRGBA[3]; // this trashes alpha, but the AGEN block fixes it
632
633 c = * ( int * ) invModulate;
634
635 for ( i = 0; i < tess.numVertexes; i++, pColors++ )
636 {
637 *pColors = * ( int * ) invModulate;
638 }
639 }
640
641 /*
642 ** RB_CalcAlphaFromEntity
643 */
RB_CalcAlphaFromEntity(unsigned char * dstColors)644 void RB_CalcAlphaFromEntity( unsigned char *dstColors )
645 {
646 int i;
647
648 if ( !backEnd.currentEntity )
649 return;
650
651 dstColors += 3;
652
653 for ( i = 0; i < tess.numVertexes; i++, dstColors += 4 )
654 {
655 *dstColors = backEnd.currentEntity->e.shaderRGBA[3];
656 }
657 }
658
659 /*
660 ** RB_CalcAlphaFromOneMinusEntity
661 */
RB_CalcAlphaFromOneMinusEntity(unsigned char * dstColors)662 void RB_CalcAlphaFromOneMinusEntity( unsigned char *dstColors )
663 {
664 int i;
665
666 if ( !backEnd.currentEntity )
667 return;
668
669 dstColors += 3;
670
671 for ( i = 0; i < tess.numVertexes; i++, dstColors += 4 )
672 {
673 *dstColors = 0xff - backEnd.currentEntity->e.shaderRGBA[3];
674 }
675 }
676
677 /*
678 ** RB_CalcWaveColor
679 */
RB_CalcWaveColor(const waveForm_t * wf,unsigned char * dstColors)680 void RB_CalcWaveColor( const waveForm_t *wf, unsigned char *dstColors )
681 {
682 int i;
683 int v;
684 float glow;
685 int *colors = ( int * ) dstColors;
686 byte color[4];
687
688
689 if ( wf->func == GF_NOISE ) {
690 glow = wf->base + R_NoiseGet4f( 0, 0, 0, ( tess.shaderTime + wf->phase ) * wf->frequency ) * wf->amplitude;
691 } else {
692 glow = EvalWaveForm( wf ) * tr.identityLight;
693 }
694
695 if ( glow < 0 ) {
696 glow = 0;
697 }
698 else if ( glow > 1 ) {
699 glow = 1;
700 }
701
702 v = myftol( 255 * glow );
703 color[0] = color[1] = color[2] = v;
704 color[3] = 255;
705 v = *(int *)color;
706
707 for ( i = 0; i < tess.numVertexes; i++, colors++ ) {
708 *colors = v;
709 }
710 }
711
712 /*
713 ** RB_CalcWaveAlpha
714 */
RB_CalcWaveAlpha(const waveForm_t * wf,unsigned char * dstColors)715 void RB_CalcWaveAlpha( const waveForm_t *wf, unsigned char *dstColors )
716 {
717 int i;
718 int v;
719 float glow;
720
721 glow = EvalWaveFormClamped( wf );
722
723 v = 255 * glow;
724
725 for ( i = 0; i < tess.numVertexes; i++, dstColors += 4 )
726 {
727 dstColors[3] = v;
728 }
729 }
730
731 /*
732 ** RB_CalcModulateColorsByFog
733 */
RB_CalcModulateColorsByFog(unsigned char * colors)734 void RB_CalcModulateColorsByFog( unsigned char *colors ) {
735 int i;
736 float texCoords[SHADER_MAX_VERTEXES][2];
737
738 // calculate texcoords so we can derive density
739 // this is not wasted, because it would only have
740 // been previously called if the surface was opaque
741 RB_CalcFogTexCoords( texCoords[0] );
742
743 for ( i = 0; i < tess.numVertexes; i++, colors += 4 ) {
744 float f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] );
745 colors[0] *= f;
746 colors[1] *= f;
747 colors[2] *= f;
748 }
749 }
750
751 /*
752 ** RB_CalcModulateAlphasByFog
753 */
RB_CalcModulateAlphasByFog(unsigned char * colors)754 void RB_CalcModulateAlphasByFog( unsigned char *colors ) {
755 int i;
756 float texCoords[SHADER_MAX_VERTEXES][2];
757
758 // calculate texcoords so we can derive density
759 // this is not wasted, because it would only have
760 // been previously called if the surface was opaque
761 RB_CalcFogTexCoords( texCoords[0] );
762
763 for ( i = 0; i < tess.numVertexes; i++, colors += 4 ) {
764 float f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] );
765 colors[3] *= f;
766 }
767 }
768
769 /*
770 ** RB_CalcModulateRGBAsByFog
771 */
RB_CalcModulateRGBAsByFog(unsigned char * colors)772 void RB_CalcModulateRGBAsByFog( unsigned char *colors ) {
773 int i;
774 float texCoords[SHADER_MAX_VERTEXES][2];
775
776 // calculate texcoords so we can derive density
777 // this is not wasted, because it would only have
778 // been previously called if the surface was opaque
779 RB_CalcFogTexCoords( texCoords[0] );
780
781 for ( i = 0; i < tess.numVertexes; i++, colors += 4 ) {
782 float f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] );
783 colors[0] *= f;
784 colors[1] *= f;
785 colors[2] *= f;
786 colors[3] *= f;
787 }
788 }
789
790
791 /*
792 ====================================================================
793
794 TEX COORDS
795
796 ====================================================================
797 */
798
799 /*
800 ========================
801 RB_CalcFogTexCoords
802
803 To do the clipped fog plane really correctly, we should use
804 projected textures, but I don't trust the drivers and it
805 doesn't fit our shader data.
806 ========================
807 */
RB_CalcFogTexCoords(float * st)808 void RB_CalcFogTexCoords( float *st ) {
809 int i;
810 float *v;
811 float s, t;
812 float eyeT;
813 qboolean eyeOutside;
814 fog_t *fog;
815 vec3_t local;
816 vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0};
817
818 fog = tr.world->fogs + tess.fogNum;
819
820 // all fogging distance is based on world Z units
821 VectorSubtract( backEnd.or.origin, backEnd.viewParms.or.origin, local );
822 fogDistanceVector[0] = -backEnd.or.modelMatrix[2];
823 fogDistanceVector[1] = -backEnd.or.modelMatrix[6];
824 fogDistanceVector[2] = -backEnd.or.modelMatrix[10];
825 fogDistanceVector[3] = DotProduct( local, backEnd.viewParms.or.axis[0] );
826
827 // scale the fog vectors based on the fog's thickness
828 fogDistanceVector[0] *= fog->tcScale;
829 fogDistanceVector[1] *= fog->tcScale;
830 fogDistanceVector[2] *= fog->tcScale;
831 fogDistanceVector[3] *= fog->tcScale;
832
833 // rotate the gradient vector for this orientation
834 if ( fog->hasSurface ) {
835 fogDepthVector[0] = fog->surface[0] * backEnd.or.axis[0][0] +
836 fog->surface[1] * backEnd.or.axis[0][1] + fog->surface[2] * backEnd.or.axis[0][2];
837 fogDepthVector[1] = fog->surface[0] * backEnd.or.axis[1][0] +
838 fog->surface[1] * backEnd.or.axis[1][1] + fog->surface[2] * backEnd.or.axis[1][2];
839 fogDepthVector[2] = fog->surface[0] * backEnd.or.axis[2][0] +
840 fog->surface[1] * backEnd.or.axis[2][1] + fog->surface[2] * backEnd.or.axis[2][2];
841 fogDepthVector[3] = -fog->surface[3] + DotProduct( backEnd.or.origin, fog->surface );
842
843 eyeT = DotProduct( backEnd.or.viewOrigin, fogDepthVector ) + fogDepthVector[3];
844 } else {
845 eyeT = 1; // non-surface fog always has eye inside
846 }
847
848 // see if the viewpoint is outside
849 // this is needed for clipping distance even for constant fog
850
851 if ( eyeT < 0 ) {
852 eyeOutside = qtrue;
853 } else {
854 eyeOutside = qfalse;
855 }
856
857 fogDistanceVector[3] += 1.0/512;
858
859 // calculate density for each point
860 for (i = 0, v = tess.xyz[0] ; i < tess.numVertexes ; i++, v += 4) {
861 // calculate the length in fog
862 s = DotProduct( v, fogDistanceVector ) + fogDistanceVector[3];
863 t = DotProduct( v, fogDepthVector ) + fogDepthVector[3];
864
865 // partially clipped fogs use the T axis
866 if ( eyeOutside ) {
867 if ( t < 1.0 ) {
868 t = 1.0/32; // point is outside, so no fogging
869 } else {
870 t = 1.0/32 + 30.0/32 * t / ( t - eyeT ); // cut the distance at the fog plane
871 }
872 } else {
873 if ( t < 0 ) {
874 t = 1.0/32; // point is outside, so no fogging
875 } else {
876 t = 31.0/32;
877 }
878 }
879
880 st[0] = s;
881 st[1] = t;
882 st += 2;
883 }
884 }
885
886
887
888 /*
889 ** RB_CalcEnvironmentTexCoords
890 */
RB_CalcEnvironmentTexCoords(float * st)891 void RB_CalcEnvironmentTexCoords( float *st )
892 {
893 int i;
894 float *v, *normal;
895 vec3_t viewer, reflected;
896 float d;
897
898 v = tess.xyz[0];
899 normal = tess.normal[0];
900
901 for (i = 0 ; i < tess.numVertexes ; i++, v += 4, normal += 4, st += 2 )
902 {
903 VectorSubtract (backEnd.or.viewOrigin, v, viewer);
904 VectorNormalizeFast (viewer);
905
906 d = DotProduct (normal, viewer);
907
908 reflected[0] = normal[0]*2*d - viewer[0];
909 reflected[1] = normal[1]*2*d - viewer[1];
910 reflected[2] = normal[2]*2*d - viewer[2];
911
912 st[0] = 0.5 + reflected[1] * 0.5;
913 st[1] = 0.5 - reflected[2] * 0.5;
914 }
915 }
916
917 /*
918 ** RB_CalcEnvironmentTexCoordsNew
919
920 This one also is offset by origin and axis which makes it look better on moving
921 objects and weapons. May be slow.
922
923 */
RB_CalcEnvironmentTexCoordsNew(float * st)924 void RB_CalcEnvironmentTexCoordsNew( float *st )
925 {
926
927 int i;
928 float *v, *normal;
929 vec3_t viewer, reflected, where, what, why, who;
930 float d, a;
931
932 v = tess.xyz[0];
933 normal = tess.normal[0];
934
935 for (i = 0 ; i < tess.numVertexes ; i++, v += 4, normal += 4, st += 2 )
936 {
937
938 VectorSubtract (backEnd.or.axis[0], v, what);
939 VectorSubtract (backEnd.or.axis[1], v, why);
940 VectorSubtract (backEnd.or.axis[2], v, who);
941
942 VectorSubtract (backEnd.or.origin, v, where);
943 VectorSubtract (backEnd.or.viewOrigin, v, viewer);
944
945 VectorNormalizeFast (viewer);
946 VectorNormalizeFast (where);
947 VectorNormalizeFast (what);
948 VectorNormalizeFast (why);
949 VectorNormalizeFast (who);
950
951 d = DotProduct (normal, viewer);
952 a = DotProduct (normal, where);
953
954 if ( backEnd.currentEntity == &tr.worldEntity ){
955
956 reflected[0] = normal[0]*2*d - viewer[0];
957 reflected[1] = normal[1]*2*d - viewer[1];
958 reflected[2] = normal[2]*2*d - viewer[2];
959
960 }
961 else
962 {
963 reflected[0] = normal[0]*2*d - viewer[0] - (where[0] * 5) + (what[0] * 4);
964 reflected[1] = normal[1]*2*d - viewer[1] - (where[1] * 5) + (why[1] * 4);
965 reflected[2] = normal[2]*2*d - viewer[2] - (where[2] * 5) + (who[2] * 4);
966
967
968 }
969 st[0] = 0.33 + reflected[1] * 0.33;
970 st[1] = 0.33 - reflected[2] * 0.33;
971 }
972 }
973
974
975 /*
976 ** RB_CalcEnvironmentTexCoordsHW
977
978 Hardware-native cubemapping (or sphere mapping if the former is unsupported)
979
980 adapted from this tremulous patch by Odin
981
982 NOTE: THIS BREAKS OTHER TCMODS IN A STAGE
983 */
RB_CalcEnvironmentTexCoordsHW()984 void RB_CalcEnvironmentTexCoordsHW()
985 {
986 qglTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
987 qglTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
988 qglTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
989 qglEnable(GL_TEXTURE_GEN_S);
990 qglEnable(GL_TEXTURE_GEN_T);
991 qglEnable(GL_TEXTURE_GEN_R);
992 }
993
994 /*
995 ** RB_CalcEnvironmentCelShadeTexCoords
996 **
997 ** RiO; celshade 1D environment map
998 */
999
RB_CalcEnvironmentCelShadeTexCoords(float * st)1000 void RB_CalcEnvironmentCelShadeTexCoords( float *st )
1001 {
1002 int i;
1003 float *v, *normal;
1004 vec3_t lightDir;
1005 float d;
1006
1007 normal = tess.normal[0];
1008 v = tess.xyz[0];
1009
1010 // Calculate only once
1011 // VectorCopy( backEnd.currentEntity->lightDir, lightDir );
1012 // if ( backEnd.currentEntity == &tr.worldEntity )
1013 // VectorSubtract( lightOrigin, v, lightDir );
1014 // else
1015 VectorCopy( backEnd.currentEntity->lightDir, lightDir );
1016 VectorNormalizeFast( lightDir );
1017
1018 for (i = 0 ; i < tess.numVertexes ; i++, v += 4, normal += 4, st += 2 ) {
1019 d= DotProduct( normal, lightDir );
1020
1021 st[0] = 0.5 + d * 0.5;
1022 st[1] = 0.5;
1023 }
1024 }
1025
1026 /*
1027 ** RB_CalcTurbulentTexCoords
1028 */
RB_CalcTurbulentTexCoords(const waveForm_t * wf,float * st)1029 void RB_CalcTurbulentTexCoords( const waveForm_t *wf, float *st )
1030 {
1031 int i;
1032 float now;
1033
1034 now = ( wf->phase + tess.shaderTime * wf->frequency );
1035
1036 for ( i = 0; i < tess.numVertexes; i++, st += 2 )
1037 {
1038 float s = st[0];
1039 float t = st[1];
1040
1041 st[0] = s + tr.sinTable[ ( ( int ) ( ( ( tess.xyz[i][0] + tess.xyz[i][2] )* 1.0/128 * 0.125 + now ) * FUNCTABLE_SIZE ) ) & ( FUNCTABLE_MASK ) ] * wf->amplitude;
1042 st[1] = t + tr.sinTable[ ( ( int ) ( ( tess.xyz[i][1] * 1.0/128 * 0.125 + now ) * FUNCTABLE_SIZE ) ) & ( FUNCTABLE_MASK ) ] * wf->amplitude;
1043 }
1044 }
1045
1046 /*
1047 ** RB_CalcScaleTexCoords
1048 */
RB_CalcScaleTexCoords(const float scale[2],float * st)1049 void RB_CalcScaleTexCoords( const float scale[2], float *st )
1050 {
1051 int i;
1052
1053 for ( i = 0; i < tess.numVertexes; i++, st += 2 )
1054 {
1055 st[0] *= scale[0];
1056 st[1] *= scale[1];
1057 }
1058 }
1059
1060 /*
1061 ** RB_CalcScrollTexCoords
1062 */
RB_CalcScrollTexCoords(const float scrollSpeed[2],float * st)1063 void RB_CalcScrollTexCoords( const float scrollSpeed[2], float *st )
1064 {
1065 int i;
1066 float timeScale = tess.shaderTime;
1067 float adjustedScrollS, adjustedScrollT;
1068
1069 adjustedScrollS = scrollSpeed[0] * timeScale;
1070 adjustedScrollT = scrollSpeed[1] * timeScale;
1071
1072 // clamp so coordinates don't continuously get larger, causing problems
1073 // with hardware limits
1074 adjustedScrollS = adjustedScrollS - floor( adjustedScrollS );
1075 adjustedScrollT = adjustedScrollT - floor( adjustedScrollT );
1076
1077 for ( i = 0; i < tess.numVertexes; i++, st += 2 )
1078 {
1079 st[0] += adjustedScrollS;
1080 st[1] += adjustedScrollT;
1081 }
1082 }
1083
1084 /*
1085 ** RB_CalcTransformTexCoords
1086 */
RB_CalcTransformTexCoords(const texModInfo_t * tmi,float * st)1087 void RB_CalcTransformTexCoords( const texModInfo_t *tmi, float *st )
1088 {
1089 int i;
1090
1091 for ( i = 0; i < tess.numVertexes; i++, st += 2 )
1092 {
1093 float s = st[0];
1094 float t = st[1];
1095
1096 st[0] = s * tmi->matrix[0][0] + t * tmi->matrix[1][0] + tmi->translate[0];
1097 st[1] = s * tmi->matrix[0][1] + t * tmi->matrix[1][1] + tmi->translate[1];
1098 }
1099 }
1100
1101 /*
1102 ** RB_CalcRotateTexCoords
1103 */
RB_CalcRotateTexCoords(float degsPerSecond,float * st)1104 void RB_CalcRotateTexCoords( float degsPerSecond, float *st )
1105 {
1106 float timeScale = tess.shaderTime;
1107 float degs;
1108 int index;
1109 float sinValue, cosValue;
1110 texModInfo_t tmi;
1111
1112 degs = -degsPerSecond * timeScale;
1113 index = degs * ( FUNCTABLE_SIZE / 360.0f );
1114
1115 sinValue = tr.sinTable[ index & FUNCTABLE_MASK ];
1116 cosValue = tr.sinTable[ ( index + FUNCTABLE_SIZE / 4 ) & FUNCTABLE_MASK ];
1117
1118 tmi.matrix[0][0] = cosValue;
1119 tmi.matrix[1][0] = -sinValue;
1120 tmi.translate[0] = 0.5 - 0.5 * cosValue + 0.5 * sinValue;
1121
1122 tmi.matrix[0][1] = sinValue;
1123 tmi.matrix[1][1] = cosValue;
1124 tmi.translate[1] = 0.5 - 0.5 * sinValue - 0.5 * cosValue;
1125
1126 RB_CalcTransformTexCoords( &tmi, st );
1127 }
1128
1129
1130
1131
1132
1133
1134 #if id386 && !defined(__GNUC__)
1135
myftol(float f)1136 long myftol( float f ) {
1137 static int tmp;
1138 __asm fld f
1139 __asm fistp tmp
1140 __asm mov eax, tmp
1141 }
1142
1143 #endif
1144
1145 /*
1146 ** RB_CalcSpecularAlpha
1147 **
1148 ** Calculates specular coefficient and places it in the alpha channel
1149 */
1150 vec3_t lightOrigin = { -960, 1980, 96 }; // FIXME: track dynamically
1151
RB_CalcSpecularAlpha(unsigned char * alphas)1152 void RB_CalcSpecularAlpha( unsigned char *alphas ) {
1153 int i;
1154 float *v, *normal;
1155 vec3_t viewer, reflected;
1156 float l, d;
1157 int b;
1158 vec3_t lightDir;
1159 int numVertexes;
1160
1161 v = tess.xyz[0];
1162 normal = tess.normal[0];
1163
1164 alphas += 3;
1165
1166 numVertexes = tess.numVertexes;
1167 for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4, alphas += 4) {
1168 float ilength;
1169
1170 VectorSubtract( lightOrigin, v, lightDir );
1171 // ilength = Q_rsqrt( DotProduct( lightDir, lightDir ) );
1172 VectorNormalizeFast( lightDir );
1173
1174 // calculate the specular color
1175 d = DotProduct (normal, lightDir);
1176 // d *= ilength;
1177
1178 // we don't optimize for the d < 0 case since this tends to
1179 // cause visual artifacts such as faceted "snapping"
1180 reflected[0] = normal[0]*2*d - lightDir[0];
1181 reflected[1] = normal[1]*2*d - lightDir[1];
1182 reflected[2] = normal[2]*2*d - lightDir[2];
1183
1184 VectorSubtract (backEnd.or.viewOrigin, v, viewer);
1185 ilength = Q_rsqrt( DotProduct( viewer, viewer ) );
1186 l = DotProduct (reflected, viewer);
1187 l *= ilength;
1188
1189 if (l < 0) {
1190 b = 0;
1191 } else {
1192 l = l*l;
1193 l = l*l;
1194 b = l * 255;
1195 if (b > 255) {
1196 b = 255;
1197 }
1198 }
1199
1200 *alphas = b;
1201 }
1202 }
1203
1204 // This fixed version comes from ZEQ2Lite
RB_CalcSpecularAlphaNew(unsigned char * alphas)1205 void RB_CalcSpecularAlphaNew( unsigned char *alphas ) {
1206 int i;
1207 float *v, *normal;
1208 vec3_t viewer, reflected;
1209 float l, d;
1210 int b;
1211 vec3_t lightDir;
1212 int numVertexes;
1213
1214 v = tess.xyz[0];
1215 normal = tess.normal[0];
1216
1217 alphas += 3;
1218
1219 numVertexes = tess.numVertexes;
1220 for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4, alphas += 4) {
1221 float ilength;
1222
1223 if ( backEnd.currentEntity == &tr.worldEntity )
1224 VectorSubtract( lightOrigin, v, lightDir ); // old compatibility with maps that use it on some models
1225 else
1226 VectorCopy( backEnd.currentEntity->lightDir, lightDir );
1227
1228 VectorNormalizeFast( lightDir );
1229
1230 // calculate the specular color
1231 d = DotProduct (normal, lightDir);
1232
1233 // we don't optimize for the d < 0 case since this tends to
1234 // cause visual artifacts such as faceted "snapping"
1235 reflected[0] = normal[0]*2*d - lightDir[0];
1236 reflected[1] = normal[1]*2*d - lightDir[1];
1237 reflected[2] = normal[2]*2*d - lightDir[2];
1238
1239 VectorSubtract (backEnd.or.viewOrigin, v, viewer);
1240 ilength = Q_rsqrt( DotProduct( viewer, viewer ) );
1241 l = DotProduct (reflected, viewer);
1242 l *= ilength;
1243
1244 if (l < 0) {
1245 b = 0;
1246 } else {
1247 l = l*l;
1248 l = l*l;
1249 b = l * 255;
1250 if (b > 255) {
1251 b = 255;
1252 }
1253 }
1254
1255 *alphas = b;
1256 }
1257
1258 }
1259
1260 /*
1261 ** RB_CalcDiffuseColor
1262 **
1263 ** The basic vertex lighting calc
1264 */
1265 #if idppc_altivec
RB_CalcDiffuseColor_altivec(unsigned char * colors)1266 static void RB_CalcDiffuseColor_altivec( unsigned char *colors )
1267 {
1268 int i;
1269 float *v, *normal;
1270 trRefEntity_t *ent;
1271 int ambientLightInt;
1272 vec3_t lightDir;
1273 int numVertexes;
1274 vector unsigned char vSel = VECCONST_UINT8(0x00, 0x00, 0x00, 0xff,
1275 0x00, 0x00, 0x00, 0xff,
1276 0x00, 0x00, 0x00, 0xff,
1277 0x00, 0x00, 0x00, 0xff);
1278 vector float ambientLightVec;
1279 vector float directedLightVec;
1280 vector float lightDirVec;
1281 vector float normalVec0, normalVec1;
1282 vector float incomingVec0, incomingVec1, incomingVec2;
1283 vector float zero, jVec;
1284 vector signed int jVecInt;
1285 vector signed short jVecShort;
1286 vector unsigned char jVecChar, normalPerm;
1287 ent = backEnd.currentEntity;
1288 ambientLightInt = ent->ambientLightInt;
1289 // A lot of this could be simplified if we made sure
1290 // entities light info was 16-byte aligned.
1291 jVecChar = vec_lvsl(0, ent->ambientLight);
1292 ambientLightVec = vec_ld(0, (vector float *)ent->ambientLight);
1293 jVec = vec_ld(11, (vector float *)ent->ambientLight);
1294 ambientLightVec = vec_perm(ambientLightVec,jVec,jVecChar);
1295
1296 jVecChar = vec_lvsl(0, ent->directedLight);
1297 directedLightVec = vec_ld(0,(vector float *)ent->directedLight);
1298 jVec = vec_ld(11,(vector float *)ent->directedLight);
1299 directedLightVec = vec_perm(directedLightVec,jVec,jVecChar);
1300
1301 jVecChar = vec_lvsl(0, ent->lightDir);
1302 lightDirVec = vec_ld(0,(vector float *)ent->lightDir);
1303 jVec = vec_ld(11,(vector float *)ent->lightDir);
1304 lightDirVec = vec_perm(lightDirVec,jVec,jVecChar);
1305
1306 zero = (vector float)vec_splat_s8(0);
1307 VectorCopy( ent->lightDir, lightDir );
1308
1309 v = tess.xyz[0];
1310 normal = tess.normal[0];
1311
1312 normalPerm = vec_lvsl(0,normal);
1313 numVertexes = tess.numVertexes;
1314 for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4) {
1315 normalVec0 = vec_ld(0,(vector float *)normal);
1316 normalVec1 = vec_ld(11,(vector float *)normal);
1317 normalVec0 = vec_perm(normalVec0,normalVec1,normalPerm);
1318 incomingVec0 = vec_madd(normalVec0, lightDirVec, zero);
1319 incomingVec1 = vec_sld(incomingVec0,incomingVec0,4);
1320 incomingVec2 = vec_add(incomingVec0,incomingVec1);
1321 incomingVec1 = vec_sld(incomingVec1,incomingVec1,4);
1322 incomingVec2 = vec_add(incomingVec2,incomingVec1);
1323 incomingVec0 = vec_splat(incomingVec2,0);
1324 incomingVec0 = vec_max(incomingVec0,zero);
1325 normalPerm = vec_lvsl(12,normal);
1326 jVec = vec_madd(incomingVec0, directedLightVec, ambientLightVec);
1327 jVecInt = vec_cts(jVec,0); // RGBx
1328 jVecShort = vec_pack(jVecInt,jVecInt); // RGBxRGBx
1329 jVecChar = vec_packsu(jVecShort,jVecShort); // RGBxRGBxRGBxRGBx
1330 jVecChar = vec_sel(jVecChar,vSel,vSel); // RGBARGBARGBARGBA replace alpha with 255
1331 vec_ste((vector unsigned int)jVecChar,0,(unsigned int *)&colors[i*4]); // store color
1332 }
1333 }
1334 #endif
1335
RB_CalcDiffuseColor_scalar(unsigned char * colors)1336 static void RB_CalcDiffuseColor_scalar( unsigned char *colors )
1337 {
1338 int i, j;
1339 float *v, *normal;
1340 float incoming;
1341 trRefEntity_t *ent;
1342 int ambientLightInt;
1343 vec3_t ambientLight;
1344 vec3_t lightDir;
1345 vec3_t directedLight;
1346 int numVertexes;
1347 ent = backEnd.currentEntity;
1348 ambientLightInt = ent->ambientLightInt;
1349 VectorCopy( ent->ambientLight, ambientLight );
1350 VectorCopy( ent->directedLight, directedLight );
1351 VectorCopy( ent->lightDir, lightDir );
1352
1353 v = tess.xyz[0];
1354 normal = tess.normal[0];
1355
1356 numVertexes = tess.numVertexes;
1357 for (i = 0 ; i < numVertexes ; i++, v += 4, normal += 4) {
1358 incoming = DotProduct (normal, lightDir);
1359 if ( incoming <= 0 ) {
1360 *(int *)&colors[i*4] = ambientLightInt;
1361 continue;
1362 }
1363 j = myftol( ambientLight[0] + incoming * directedLight[0] );
1364 if ( j > 255 ) {
1365 j = 255;
1366 }
1367 colors[i*4+0] = j;
1368
1369 j = myftol( ambientLight[1] + incoming * directedLight[1] );
1370 if ( j > 255 ) {
1371 j = 255;
1372 }
1373 colors[i*4+1] = j;
1374
1375 j = myftol( ambientLight[2] + incoming * directedLight[2] );
1376 if ( j > 255 ) {
1377 j = 255;
1378 }
1379 colors[i*4+2] = j;
1380
1381 colors[i*4+3] = 255;
1382 }
1383 }
1384
RB_CalcDiffuseColor(unsigned char * colors)1385 void RB_CalcDiffuseColor( unsigned char *colors )
1386 {
1387 #if idppc_altivec
1388 if (com_altivec->integer) {
1389 // must be in a seperate function or G3 systems will crash.
1390 RB_CalcDiffuseColor_altivec( colors );
1391 return;
1392 }
1393 #endif
1394 RB_CalcDiffuseColor_scalar( colors );
1395 }
1396
1397 /*
1398 ** RB_CalcUniformColor
1399 **
1400 ** RiO; Uniform vertex color lighting for cel shading
1401 */
RB_CalcUniformColor(unsigned char * colors)1402 void RB_CalcUniformColor( unsigned char *colors )
1403 {
1404
1405 int i;
1406 trRefEntity_t *ent;
1407 vec3_t ambientLight;
1408 vec3_t directedLight;
1409 vec4_t uniformLight;
1410 int numVertexes;
1411 float normalize;
1412
1413 ent = backEnd.currentEntity;
1414
1415 VectorCopy( ent->ambientLight, ambientLight );
1416 VectorCopy( ent->directedLight, directedLight );
1417
1418 VectorAdd( ambientLight, ambientLight/*directedLight*/, uniformLight );
1419
1420 normalize = NormalizeColor( uniformLight, uniformLight );
1421 if ( normalize > 255 ) normalize = 255;
1422 VectorScale( uniformLight, normalize, uniformLight );
1423 uniformLight[3] = 255;
1424
1425 numVertexes = tess.numVertexes;
1426 for (i = 0 ; i < numVertexes ; i++ ) {
1427 colors[i*4+0] = uniformLight[0];
1428 colors[i*4+1] = uniformLight[1];
1429 colors[i*4+2] = uniformLight[2];
1430 colors[i*4+3] = uniformLight[3];
1431 }
1432 }
1433
1434 /*
1435 ** RB_CalcDynamicColor
1436 **
1437 ** MDave; Vertex color dynamic lighting for cel shading
1438 */
RB_CalcDynamicColor(unsigned char * colors)1439 void RB_CalcDynamicColor( unsigned char *colors )
1440 {
1441 int i;
1442 trRefEntity_t *ent;
1443 vec4_t dynamic;
1444 int numVertexes;
1445 float normalize;
1446
1447 ent = backEnd.currentEntity;
1448
1449 VectorCopy( ent->dynamicLight, dynamic );
1450
1451 normalize = NormalizeColor( dynamic, dynamic );
1452 if ( normalize > 255 ) normalize = 255;
1453 VectorScale( dynamic, normalize, dynamic );
1454 dynamic[3] = 255;
1455
1456 numVertexes = tess.numVertexes;
1457 for (i = 0 ; i < numVertexes ; i++ ) {
1458 colors[i*4+0] = dynamic[0];
1459 colors[i*4+1] = dynamic[1];
1460 colors[i*4+2] = dynamic[2];
1461 colors[i*4+3] = dynamic[3];
1462 }
1463 }
1464