1 /*
2 ===========================================================================
3 
4 Return to Castle Wolfenstein multiplayer GPL Source Code
5 Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
8 
9 RTCW MP Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 RTCW MP Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with RTCW MP Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code.  If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 // tr_shade_calc.c
30 
31 #include "tr_local.h"
32 
33 #define	WAVEVALUE( table, base, amplitude, phase, freq )  ( ( base ) + table[ ( ( int64_t ) ( ( ( phase ) + tess.shaderTime * ( freq ) ) * FUNCTABLE_SIZE ) ) & FUNCTABLE_MASK ] * ( amplitude ) )
34 
TableForFunc(genFunc_t func)35 static float *TableForFunc( genFunc_t func ) {
36 	switch ( func )
37 	{
38 	case GF_SIN:
39 		return tr.sinTable;
40 	case GF_TRIANGLE:
41 		return tr.triangleTable;
42 	case GF_SQUARE:
43 		return tr.squareTable;
44 	case GF_SAWTOOTH:
45 		return tr.sawToothTable;
46 	case GF_INVERSE_SAWTOOTH:
47 		return tr.inverseSawToothTable;
48 	case GF_NONE:
49 	default:
50 		break;
51 	}
52 
53 	ri.Error( ERR_DROP, "TableForFunc called with invalid function '%d' in shader '%s'", func, tess.shader->name );
54 	return NULL;
55 }
56 
57 /*
58 ** EvalWaveForm
59 **
60 ** Evaluates a given waveForm_t, referencing backEnd.refdef.time directly
61 */
EvalWaveForm(const waveForm_t * wf)62 static float EvalWaveForm( const waveForm_t *wf )
63 {
64 	float	*table;
65 
66 	table = TableForFunc( wf->func );
67 
68 	return WAVEVALUE( table, wf->base, wf->amplitude, wf->phase, wf->frequency );
69 }
70 
EvalWaveFormClamped(const waveForm_t * wf)71 static float EvalWaveFormClamped( const waveForm_t *wf )
72 {
73 	float glow  = EvalWaveForm( wf );
74 
75 	if ( glow < 0 )
76 	{
77 		return 0;
78 	}
79 
80 	if ( glow > 1 )
81 	{
82 		return 1;
83 	}
84 
85 	return glow;
86 }
87 
88 /*
89 ** RB_CalcStretchTexMatrix
90 */
RB_CalcStretchTexMatrix(const waveForm_t * wf,float * matrix)91 void RB_CalcStretchTexMatrix( const waveForm_t *wf, float *matrix )
92 {
93 	float p;
94 
95 	p = 1.0f / EvalWaveForm( wf );
96 
97 	matrix[0] = p; matrix[2] = 0; matrix[4] = 0.5f - 0.5f * p;
98 	matrix[1] = 0; matrix[3] = p; matrix[5] = 0.5f - 0.5f * p;
99 }
100 
101 /*
102 ====================================================================
103 
104 DEFORMATIONS
105 
106 ====================================================================
107 */
108 
109 /*
110 ========================
111 RB_CalcDeformVertexes
112 
113 ========================
114 */
RB_CalcDeformVertexes(deformStage_t * ds)115 void RB_CalcDeformVertexes( deformStage_t *ds ) {
116 	int i;
117 	vec3_t offset;
118 	float scale;
119 	float   *xyz = ( float * ) tess.xyz;
120 	int16_t	*normal = tess.normal[0];
121 	float   *table;
122 
123 	// Ridah
124 	if ( ds->deformationWave.frequency < 0 ) {
125 		qboolean inverse = qfalse;
126 		vec3_t worldUp;
127 		//static vec3_t up = {0,0,1};
128 
129 		if ( VectorCompare( backEnd.currentEntity->e.fireRiseDir, vec3_origin ) ) {
130 			VectorSet( backEnd.currentEntity->e.fireRiseDir, 0, 0, 1 );
131 		}
132 
133 		// get the world up vector in local coordinates
134 		if ( backEnd.currentEntity->e.hModel ) {  // world surfaces dont have an axis
135 			VectorRotate( backEnd.currentEntity->e.fireRiseDir, backEnd.currentEntity->e.axis, worldUp );
136 		} else {
137 			VectorCopy( backEnd.currentEntity->e.fireRiseDir, worldUp );
138 		}
139 		// don't go so far if sideways, since they must be moving
140 		VectorScale( worldUp, 0.4 + 0.6 * fabs( backEnd.currentEntity->e.fireRiseDir[2] ), worldUp );
141 
142 		ds->deformationWave.frequency *= -1;
143 		if ( ds->deformationWave.frequency > 999 ) {  // hack for negative Z deformation (ack)
144 			inverse = qtrue;
145 			ds->deformationWave.frequency -= 999;
146 		}
147 
148 		table = TableForFunc( ds->deformationWave.func );
149 
150 		for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 )
151 		{
152 			float off = ( xyz[0] + xyz[1] + xyz[2] ) * ds->deformationSpread;
153 			float dot;
154 			vec3_t fNormal;
155 
156 			R_VaoUnpackNormal(fNormal, normal);
157 
158 			scale = WAVEVALUE( table, ds->deformationWave.base,
159 							   ds->deformationWave.amplitude,
160 							   ds->deformationWave.phase + off,
161 							   ds->deformationWave.frequency );
162 
163 			dot = DotProduct( worldUp, fNormal );
164 
165 			if ( dot * scale > 0 ) {
166 				if ( inverse ) {
167 					scale *= -1;
168 				}
169 				VectorMA( xyz, dot * scale, worldUp, xyz );
170 			}
171 		}
172 
173 		if ( inverse ) {
174 			ds->deformationWave.frequency += 999;
175 		}
176 		ds->deformationWave.frequency *= -1;
177 	}
178 	// done.
179 	else if ( ds->deformationWave.frequency == 0 ) {
180 		scale = EvalWaveForm( &ds->deformationWave );
181 
182 		for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 )
183 		{
184 			R_VaoUnpackNormal(offset, normal);
185 
186 			xyz[0] += offset[0] * scale;
187 			xyz[1] += offset[1] * scale;
188 			xyz[2] += offset[2] * scale;
189 		}
190 	}
191 	else {
192 		table = TableForFunc( ds->deformationWave.func );
193 
194 		for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 )
195 		{
196 			float off = ( xyz[0] + xyz[1] + xyz[2] ) * ds->deformationSpread;
197 
198 			scale = WAVEVALUE( table, ds->deformationWave.base,
199 							   ds->deformationWave.amplitude,
200 							   ds->deformationWave.phase + off,
201 							   ds->deformationWave.frequency );
202 
203 			R_VaoUnpackNormal(offset, normal);
204 
205 			xyz[0] += offset[0] * scale;
206 			xyz[1] += offset[1] * scale;
207 			xyz[2] += offset[2] * scale;
208 		}
209 	}
210 }
211 
212 /*
213 =========================
214 RB_CalcDeformNormals
215 
216 Wiggle the normals for wavy environment mapping
217 =========================
218 */
RB_CalcDeformNormals(deformStage_t * ds)219 void RB_CalcDeformNormals( deformStage_t *ds ) {
220 	int i;
221 	float scale;
222 	float   *xyz = ( float * ) tess.xyz;
223 	int16_t *normal = tess.normal[0];
224 
225 	for ( i = 0; i < tess.numVertexes; i++, xyz += 4, normal += 4 ) {
226 		vec3_t fNormal;
227 
228 		R_VaoUnpackNormal(fNormal, normal);
229 
230 		scale = 0.98f;
231 		scale = R_NoiseGet4f( xyz[0] * scale, xyz[1] * scale, xyz[2] * scale,
232 							  tess.shaderTime * ds->deformationWave.frequency );
233 		fNormal[ 0 ] += ds->deformationWave.amplitude * scale;
234 
235 		scale = 0.98f;
236 		scale = R_NoiseGet4f( 100 + xyz[0] * scale, xyz[1] * scale, xyz[2] * scale,
237 							  tess.shaderTime * ds->deformationWave.frequency );
238 		fNormal[ 1 ] += ds->deformationWave.amplitude * scale;
239 
240 		scale = 0.98f;
241 		scale = R_NoiseGet4f( 200 + xyz[0] * scale, xyz[1] * scale, xyz[2] * scale,
242 							  tess.shaderTime * ds->deformationWave.frequency );
243 		fNormal[ 2 ] += ds->deformationWave.amplitude * scale;
244 
245 		VectorNormalizeFast( fNormal );
246 
247 		R_VaoPackNormal(normal, fNormal);
248 	}
249 }
250 
251 /*
252 ========================
253 RB_CalcBulgeVertexes
254 
255 ========================
256 */
RB_CalcBulgeVertexes(deformStage_t * ds)257 void RB_CalcBulgeVertexes( deformStage_t *ds ) {
258 	int i;
259 	const float	*st = ( const float * ) tess.texCoords[0];
260 	float		*xyz = ( float * ) tess.xyz;
261 	int16_t	*normal = tess.normal[0];
262 	double now;
263 
264 	now = backEnd.refdef.time * 0.001 * ds->bulgeSpeed;
265 
266 	for ( i = 0; i < tess.numVertexes; i++, xyz += 4, st += 2, normal += 4 ) {
267 		int64_t off;
268 		float scale;
269 		vec3_t fNormal;
270 
271 		R_VaoUnpackNormal(fNormal, normal);
272 
273 		off = (float)( FUNCTABLE_SIZE / ( M_PI * 2 ) ) * ( st[0] * ds->bulgeWidth + now );
274 
275 		scale = tr.sinTable[ off & FUNCTABLE_MASK ] * ds->bulgeHeight;
276 
277 		xyz[0] += fNormal[0] * scale;
278 		xyz[1] += fNormal[1] * scale;
279 		xyz[2] += fNormal[2] * scale;
280 	}
281 }
282 
283 
284 /*
285 ======================
286 RB_CalcMoveVertexes
287 
288 A deformation that can move an entire surface along a wave path
289 ======================
290 */
RB_CalcMoveVertexes(deformStage_t * ds)291 void RB_CalcMoveVertexes( deformStage_t *ds ) {
292 	int i;
293 	float       *xyz;
294 	float       *table;
295 	float scale;
296 	vec3_t offset;
297 
298 	table = TableForFunc( ds->deformationWave.func );
299 
300 	scale = WAVEVALUE( table, ds->deformationWave.base,
301 					   ds->deformationWave.amplitude,
302 					   ds->deformationWave.phase,
303 					   ds->deformationWave.frequency );
304 
305 	VectorScale( ds->moveVector, scale, offset );
306 
307 	xyz = ( float * ) tess.xyz;
308 	for ( i = 0; i < tess.numVertexes; i++, xyz += 4 ) {
309 		VectorAdd( xyz, offset, xyz );
310 	}
311 }
312 
313 
314 /*
315 =============
316 DeformText
317 
318 Change a polygon into a bunch of text polygons
319 =============
320 */
DeformText(const char * text)321 void DeformText( const char *text ) {
322 	int i;
323 	vec3_t origin, width, height;
324 	int len;
325 	int ch;
326 	float color[4];
327 	float bottom, top;
328 	vec3_t mid;
329 	vec3_t fNormal;
330 
331 	height[0] = 0;
332 	height[1] = 0;
333 	height[2] = -1;
334 
335 	R_VaoUnpackNormal(fNormal, tess.normal[0]);
336 	CrossProduct( fNormal, height, width );
337 
338 	// find the midpoint of the box
339 	VectorClear( mid );
340 	bottom = 999999;
341 	top = -999999;
342 	for ( i = 0 ; i < 4 ; i++ ) {
343 		VectorAdd( tess.xyz[i], mid, mid );
344 		if ( tess.xyz[i][2] < bottom ) {
345 			bottom = tess.xyz[i][2];
346 		}
347 		if ( tess.xyz[i][2] > top ) {
348 			top = tess.xyz[i][2];
349 		}
350 	}
351 	VectorScale( mid, 0.25f, origin );
352 
353 	// determine the individual character size
354 	height[0] = 0;
355 	height[1] = 0;
356 	height[2] = ( top - bottom ) * 0.5f;
357 
358 	VectorScale( width, height[2] * -0.75f, width );
359 
360 	// determine the starting position
361 	len = strlen( text );
362 	VectorMA( origin, ( len - 1 ), width, origin );
363 
364 	// clear the shader indexes
365 	tess.numIndexes = 0;
366 	tess.numVertexes = 0;
367 	tess.firstIndex = 0;
368 
369 	color[0] = color[1] = color[2] = color[3] = 1.0f;
370 
371 	// draw each character
372 	for ( i = 0 ; i < len ; i++ ) {
373 		ch = text[i];
374 		ch &= 255;
375 
376 		if ( ch != ' ' ) {
377 			int row, col;
378 			float frow, fcol, size;
379 
380 			row = ch >> 4;
381 			col = ch & 15;
382 
383 			frow = row * 0.0625f;
384 			fcol = col * 0.0625f;
385 			size = 0.0625f;
386 
387 			RB_AddQuadStampExt( origin, width, height, color, fcol, frow, fcol + size, frow + size );
388 		}
389 		VectorMA( origin, -2, width, origin );
390 	}
391 }
392 
393 /*
394 ==================
395 GlobalVectorToLocal
396 ==================
397 */
GlobalVectorToLocal(const vec3_t in,vec3_t out)398 void GlobalVectorToLocal( const vec3_t in, vec3_t out ) {
399 	out[0] = DotProduct( in, backEnd.or.axis[0] );
400 	out[1] = DotProduct( in, backEnd.or.axis[1] );
401 	out[2] = DotProduct( in, backEnd.or.axis[2] );
402 }
403 
404 /*
405 =====================
406 AutospriteDeform
407 
408 Assuming all the triangles for this shader are independant
409 quads, rebuild them as forward facing sprites
410 =====================
411 */
AutospriteDeform(void)412 static void AutospriteDeform( void ) {
413 	int i;
414 	int oldVerts;
415 	float   *xyz;
416 	vec3_t mid, delta;
417 	float radius;
418 	vec3_t left, up;
419 	vec3_t leftDir, upDir;
420 
421 	if ( tess.numVertexes & 3 ) {
422 		ri.Printf( PRINT_WARNING, "Autosprite shader %s had odd vertex count\n", tess.shader->name );
423 	}
424 	if ( tess.numIndexes != ( tess.numVertexes >> 2 ) * 6 ) {
425 		ri.Printf( PRINT_WARNING, "Autosprite shader %s had odd index count\n", tess.shader->name );
426 	}
427 
428 	oldVerts = tess.numVertexes;
429 	tess.numVertexes = 0;
430 	tess.numIndexes = 0;
431 	tess.firstIndex = 0;
432 
433 	if ( backEnd.currentEntity != &tr.worldEntity ) {
434 		GlobalVectorToLocal( backEnd.viewParms.or.axis[1], leftDir );
435 		GlobalVectorToLocal( backEnd.viewParms.or.axis[2], upDir );
436 	} else {
437 		VectorCopy( backEnd.viewParms.or.axis[1], leftDir );
438 		VectorCopy( backEnd.viewParms.or.axis[2], upDir );
439 	}
440 
441 	for ( i = 0 ; i < oldVerts ; i += 4 ) {
442 		vec4_t color;
443 		// find the midpoint
444 		xyz = tess.xyz[i];
445 
446 		mid[0] = 0.25f * ( xyz[0] + xyz[4] + xyz[8] + xyz[12] );
447 		mid[1] = 0.25f * ( xyz[1] + xyz[5] + xyz[9] + xyz[13] );
448 		mid[2] = 0.25f * ( xyz[2] + xyz[6] + xyz[10] + xyz[14] );
449 
450 		VectorSubtract( xyz, mid, delta );
451 		radius = VectorLength( delta ) * 0.707f;        // / sqrt(2)
452 
453 		VectorScale( leftDir, radius, left );
454 		VectorScale( upDir, radius, up );
455 
456 		if ( backEnd.viewParms.isMirror ) {
457 			VectorSubtract( vec3_origin, left, left );
458 		}
459 
460 		// compensate for scale in the axes if necessary
461 		if ( backEnd.currentEntity->e.nonNormalizedAxes ) {
462 			float axisLength;
463 			axisLength = VectorLength( backEnd.currentEntity->e.axis[0] );
464 			if ( !axisLength ) {
465 				axisLength = 0;
466 			} else {
467 				axisLength = 1.0f / axisLength;
468 			}
469 			VectorScale( left, axisLength, left );
470 			VectorScale( up, axisLength, up );
471 		}
472 
473 		VectorScale4(tess.color[i], 1.0f / 65535.0f, color);
474 		RB_AddQuadStamp( mid, left, up, color );
475 	}
476 }
477 
478 
479 /*
480 =====================
481 Autosprite2Deform
482 
483 Autosprite2 will pivot a rectangular quad along the center of its long axis
484 =====================
485 */
486 int edgeVerts[6][2] = {
487 	{ 0, 1 },
488 	{ 0, 2 },
489 	{ 0, 3 },
490 	{ 1, 2 },
491 	{ 1, 3 },
492 	{ 2, 3 }
493 };
494 
Autosprite2Deform(void)495 static void Autosprite2Deform( void ) {
496 	int i, j, k;
497 	int indexes;
498 	float   *xyz;
499 	vec3_t forward;
500 
501 	if ( tess.numVertexes & 3 ) {
502 		ri.Printf( PRINT_WARNING, "Autosprite2 shader %s had odd vertex count\n", tess.shader->name );
503 	}
504 	if ( tess.numIndexes != ( tess.numVertexes >> 2 ) * 6 ) {
505 		ri.Printf( PRINT_WARNING, "Autosprite2 shader %s had odd index count\n", tess.shader->name );
506 	}
507 
508 	if ( backEnd.currentEntity != &tr.worldEntity ) {
509 		GlobalVectorToLocal( backEnd.viewParms.or.axis[0], forward );
510 	} else {
511 		VectorCopy( backEnd.viewParms.or.axis[0], forward );
512 	}
513 
514 	// this is a lot of work for two triangles...
515 	// we could precalculate a lot of it is an issue, but it would mess up
516 	// the shader abstraction
517 	for ( i = 0, indexes = 0 ; i < tess.numVertexes ; i += 4, indexes += 6 ) {
518 		float lengths[2];
519 		int nums[2];
520 		vec3_t mid[2];
521 		vec3_t major, minor;
522 		float   *v1, *v2;
523 
524 		// find the midpoint
525 		xyz = tess.xyz[i];
526 
527 		// identify the two shortest edges
528 		nums[0] = nums[1] = 0;
529 		lengths[0] = lengths[1] = 999999;
530 
531 		for ( j = 0 ; j < 6 ; j++ ) {
532 			float l;
533 			vec3_t temp;
534 
535 			v1 = xyz + 4 * edgeVerts[j][0];
536 			v2 = xyz + 4 * edgeVerts[j][1];
537 
538 			VectorSubtract( v1, v2, temp );
539 
540 			l = DotProduct( temp, temp );
541 			if ( l < lengths[0] ) {
542 				nums[1] = nums[0];
543 				lengths[1] = lengths[0];
544 				nums[0] = j;
545 				lengths[0] = l;
546 			} else if ( l < lengths[1] ) {
547 				nums[1] = j;
548 				lengths[1] = l;
549 			}
550 		}
551 
552 		for ( j = 0 ; j < 2 ; j++ ) {
553 			v1 = xyz + 4 * edgeVerts[nums[j]][0];
554 			v2 = xyz + 4 * edgeVerts[nums[j]][1];
555 
556 			mid[j][0] = 0.5f * ( v1[0] + v2[0] );
557 			mid[j][1] = 0.5f * ( v1[1] + v2[1] );
558 			mid[j][2] = 0.5f * ( v1[2] + v2[2] );
559 		}
560 
561 		// find the vector of the major axis
562 		VectorSubtract( mid[1], mid[0], major );
563 
564 		// cross this with the view direction to get minor axis
565 		CrossProduct( major, forward, minor );
566 		VectorNormalize( minor );
567 
568 		// re-project the points
569 		for ( j = 0 ; j < 2 ; j++ ) {
570 			float l;
571 
572 			v1 = xyz + 4 * edgeVerts[nums[j]][0];
573 			v2 = xyz + 4 * edgeVerts[nums[j]][1];
574 
575 			l = 0.5f * sqrt( lengths[j] );
576 
577 			// we need to see which direction this edge
578 			// is used to determine direction of projection
579 			for ( k = 0 ; k < 5 ; k++ ) {
580 				if ( tess.indexes[ indexes + k ] == i + edgeVerts[nums[j]][0]
581 					 && tess.indexes[ indexes + k + 1 ] == i + edgeVerts[nums[j]][1] ) {
582 					break;
583 				}
584 			}
585 
586 			if ( k == 5 ) {
587 				VectorMA( mid[j], l, minor, v1 );
588 				VectorMA( mid[j], -l, minor, v2 );
589 			} else {
590 				VectorMA( mid[j], -l, minor, v1 );
591 				VectorMA( mid[j], l, minor, v2 );
592 			}
593 		}
594 	}
595 }
596 
597 
598 /*
599 =====================
600 RB_DeformTessGeometry
601 
602 =====================
603 */
RB_DeformTessGeometry(void)604 void RB_DeformTessGeometry( void ) {
605 	int i;
606 	deformStage_t   *ds;
607 
608 	if(!ShaderRequiresCPUDeforms(tess.shader))
609 	{
610 		// we don't need the following CPU deforms
611 		return;
612 	}
613 
614 	for ( i = 0 ; i < tess.shader->numDeforms ; i++ ) {
615 		ds = &tess.shader->deforms[ i ];
616 
617 		switch ( ds->deformation ) {
618 		case DEFORM_NONE:
619 			break;
620 		case DEFORM_NORMALS:
621 			RB_CalcDeformNormals( ds );
622 			break;
623 		case DEFORM_WAVE:
624 			RB_CalcDeformVertexes( ds );
625 			break;
626 		case DEFORM_BULGE:
627 			RB_CalcBulgeVertexes( ds );
628 			break;
629 		case DEFORM_MOVE:
630 			RB_CalcMoveVertexes( ds );
631 			break;
632 		case DEFORM_PROJECTION_SHADOW:
633 			RB_ProjectionShadowDeform();
634 			break;
635 		case DEFORM_AUTOSPRITE:
636 			AutospriteDeform();
637 			break;
638 		case DEFORM_AUTOSPRITE2:
639 			Autosprite2Deform();
640 			break;
641 		case DEFORM_TEXT0:
642 		case DEFORM_TEXT1:
643 		case DEFORM_TEXT2:
644 		case DEFORM_TEXT3:
645 		case DEFORM_TEXT4:
646 		case DEFORM_TEXT5:
647 		case DEFORM_TEXT6:
648 		case DEFORM_TEXT7:
649 			DeformText( backEnd.refdef.text[ds->deformation - DEFORM_TEXT0] );
650 			break;
651 		}
652 	}
653 }
654 
655 /*
656 ====================================================================
657 
658 COLORS
659 
660 ====================================================================
661 */
662 
663 /*
664 ** RB_CalcWaveColorSingle
665 */
RB_CalcWaveColorSingle(const waveForm_t * wf)666 float RB_CalcWaveColorSingle( const waveForm_t *wf )
667 {
668 	float glow;
669 
670 	if ( wf->func == GF_NOISE ) {
671 		glow = wf->base + R_NoiseGet4f( 0, 0, 0, ( tess.shaderTime + wf->phase ) * wf->frequency ) * wf->amplitude;
672 	} else {
673 		glow = EvalWaveForm( wf ) * tr.identityLight;
674 	}
675 
676 	if ( glow < 0 ) {
677 		glow = 0;
678 	}
679 	else if ( glow > 1 ) {
680 		glow = 1;
681 	}
682 
683 	return glow;
684 }
685 
686 /*
687 ** RB_CalcWaveAlphaSingle
688 */
RB_CalcWaveAlphaSingle(const waveForm_t * wf)689 float RB_CalcWaveAlphaSingle( const waveForm_t *wf )
690 {
691 	return EvalWaveFormClamped( wf );
692 }
693 
694 /*
695 ** RB_CalcModulateColorsByFog
696 */
RB_CalcModulateColorsByFog(unsigned char * colors)697 void RB_CalcModulateColorsByFog( unsigned char *colors ) {
698 	int i;
699 	float texCoords[SHADER_MAX_VERTEXES][2] = {{0.0f}};
700 
701 	// calculate texcoords so we can derive density
702 	// this is not wasted, because it would only have
703 	// been previously called if the surface was opaque
704 	RB_CalcFogTexCoords( texCoords[0] );
705 
706 	for ( i = 0; i < tess.numVertexes; i++, colors += 4 ) {
707 		float f = 1.0 - R_FogFactor( texCoords[i][0], texCoords[i][1] );
708 		colors[0] *= f;
709 		colors[1] *= f;
710 		colors[2] *= f;
711 	}
712 }
713 
714 /*
715 ====================================================================
716 
717 TEX COORDS
718 
719 ====================================================================
720 */
721 
722 /*
723 ========================
724 RB_CalcFogTexCoords
725 
726 To do the clipped fog plane really correctly, we should use
727 projected textures, but I don't trust the drivers and it
728 doesn't fit our shader data.
729 ========================
730 */
RB_CalcFogTexCoords(float * st)731 void RB_CalcFogTexCoords( float *st ) {
732 	int i;
733 	float       *v;
734 	float s, t;
735 	float eyeT;
736 	qboolean eyeOutside;
737 	fog_t       *fog;
738 	vec3_t local;
739 	vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0};
740 
741 	fog = tr.world->fogs + tess.fogNum;
742 
743 	// all fogging distance is based on world Z units
744 	VectorSubtract( backEnd.or.origin, backEnd.viewParms.or.origin, local );
745 	fogDistanceVector[0] = -backEnd.or.modelMatrix[2];
746 	fogDistanceVector[1] = -backEnd.or.modelMatrix[6];
747 	fogDistanceVector[2] = -backEnd.or.modelMatrix[10];
748 	fogDistanceVector[3] = DotProduct( local, backEnd.viewParms.or.axis[0] );
749 
750 	// scale the fog vectors based on the fog's thickness
751 	fogDistanceVector[0] *= fog->tcScale;
752 	fogDistanceVector[1] *= fog->tcScale;
753 	fogDistanceVector[2] *= fog->tcScale;
754 	fogDistanceVector[3] *= fog->tcScale;
755 
756 	// rotate the gradient vector for this orientation
757 	if ( fog->hasSurface ) {
758 		fogDepthVector[0] = fog->surface[0] * backEnd.or.axis[0][0] +
759 			fog->surface[1] * backEnd.or.axis[0][1] + fog->surface[2] * backEnd.or.axis[0][2];
760 		fogDepthVector[1] = fog->surface[0] * backEnd.or.axis[1][0] +
761 			fog->surface[1] * backEnd.or.axis[1][1] + fog->surface[2] * backEnd.or.axis[1][2];
762 		fogDepthVector[2] = fog->surface[0] * backEnd.or.axis[2][0] +
763 			fog->surface[1] * backEnd.or.axis[2][1] + fog->surface[2] * backEnd.or.axis[2][2];
764 		fogDepthVector[3] = -fog->surface[3] + DotProduct( backEnd.or.origin, fog->surface );
765 
766 		eyeT = DotProduct( backEnd.or.viewOrigin, fogDepthVector ) + fogDepthVector[3];
767 	} else {
768 		eyeT = 1;   // non-surface fog always has eye inside
769 	}
770 
771 	// see if the viewpoint is outside
772 	// this is needed for clipping distance even for constant fog
773 
774 	if ( eyeT < 0 ) {
775 		eyeOutside = qtrue;
776 	} else {
777 		eyeOutside = qfalse;
778 	}
779 
780 	fogDistanceVector[3] += 1.0 / 512;
781 
782 	// calculate density for each point
783 	for ( i = 0, v = tess.xyz[0] ; i < tess.numVertexes ; i++, v += 4 ) {
784 		// calculate the length in fog
785 		s = DotProduct( v, fogDistanceVector ) + fogDistanceVector[3];
786 		t = DotProduct( v, fogDepthVector ) + fogDepthVector[3];
787 
788 		// partially clipped fogs use the T axis
789 		if ( eyeOutside ) {
790 			if ( t < 1.0 ) {
791 				t = 1.0 / 32; // point is outside, so no fogging
792 			} else {
793 				t = 1.0 / 32 + 30.0 / 32 * t / ( t - eyeT );    // cut the distance at the fog plane
794 			}
795 		} else {
796 			if ( t < 0 ) {
797 				t = 1.0 / 32; // point is outside, so no fogging
798 			} else {
799 				t = 31.0 / 32;
800 			}
801 		}
802 
803 		st[0] = s;
804 		st[1] = t;
805 		st += 2;
806 	}
807 }
808 
809 /*
810 ** RB_CalcFireRiseEnvTexCoords
811 */
RB_CalcFireRiseEnvTexCoords(float * st)812 void RB_CalcFireRiseEnvTexCoords( float *st ) {
813 	int i;
814 	float       *v;
815 	int16_t *normal = tess.normal[0];
816 	vec3_t fNormal, viewer, reflected;
817 	float d;
818 
819 	v = tess.xyz[0];
820 	VectorNegate( backEnd.currentEntity->e.fireRiseDir, viewer );
821 
822 	for ( i = 0 ; i < tess.numVertexes ; i++, v += 4, normal += 4, st += 2 )
823 	{
824 		VectorNormalizeFast( viewer );
825 
826 		R_VaoUnpackNormal(fNormal, normal);
827 
828 		d = DotProduct( fNormal, viewer );
829 
830 		reflected[0] = fNormal[0] * 2 * d - viewer[0];
831 		reflected[1] = fNormal[1] * 2 * d - viewer[1];
832 		reflected[2] = fNormal[2] * 2 * d - viewer[2];
833 
834 		st[0] = 0.5 + reflected[1] * 0.5;
835 		st[1] = 0.5 - reflected[2] * 0.5;
836 	}
837 }
838 
839 
840 /*
841 ** RB_CalcSwapTexCoords
842 */
RB_CalcSwapTexCoords(float * st)843 void RB_CalcSwapTexCoords( float *st ) {
844 	int i;
845 
846 	for ( i = 0; i < tess.numVertexes; i++, st += 2 )
847 	{
848 		float s = st[0];
849 		float t = st[1];
850 
851 		st[0] = t;
852 		st[1] = 1.0 - s;    // err, flaming effect needs this
853 	}
854 }
855 
856 /*
857 ** RB_CalcTurbulentFactors
858 */
RB_CalcTurbulentFactors(const waveForm_t * wf,float * amplitude,float * now)859 void RB_CalcTurbulentFactors( const waveForm_t *wf, float *amplitude, float *now )
860 {
861 	*now = wf->phase + tess.shaderTime * wf->frequency;
862 	*amplitude = wf->amplitude;
863 }
864 
865 /*
866 ** RB_CalcScaleTexMatrix
867 */
RB_CalcScaleTexMatrix(const float scale[2],float * matrix)868 void RB_CalcScaleTexMatrix( const float scale[2], float *matrix )
869 {
870 	matrix[0] = scale[0]; matrix[2] = 0.0f;     matrix[4] = 0.0f;
871 	matrix[1] = 0.0f;     matrix[3] = scale[1]; matrix[5] = 0.0f;
872 }
873 
874 /*
875 ** RB_CalcScrollTexMatrix
876 */
RB_CalcScrollTexMatrix(const float scrollSpeed[2],float * matrix)877 void RB_CalcScrollTexMatrix( const float scrollSpeed[2], float *matrix )
878 {
879 	double timeScale = tess.shaderTime;
880 	double adjustedScrollS, adjustedScrollT;
881 
882 	adjustedScrollS = scrollSpeed[0] * timeScale;
883 	adjustedScrollT = scrollSpeed[1] * timeScale;
884 
885 	// clamp so coordinates don't continuously get larger, causing problems
886 	// with hardware limits
887 	adjustedScrollS = adjustedScrollS - floor( adjustedScrollS );
888 	adjustedScrollT = adjustedScrollT - floor( adjustedScrollT );
889 
890 	matrix[0] = 1.0f; matrix[2] = 0.0f; matrix[4] = adjustedScrollS;
891 	matrix[1] = 0.0f; matrix[3] = 1.0f; matrix[5] = adjustedScrollT;
892 }
893 
894 /*
895 ** RB_CalcTransformTexMatrix
896 */
RB_CalcTransformTexMatrix(const texModInfo_t * tmi,float * matrix)897 void RB_CalcTransformTexMatrix( const texModInfo_t *tmi, float *matrix  )
898 {
899 	matrix[0] = tmi->matrix[0][0]; matrix[2] = tmi->matrix[1][0]; matrix[4] = tmi->translate[0];
900 	matrix[1] = tmi->matrix[0][1]; matrix[3] = tmi->matrix[1][1]; matrix[5] = tmi->translate[1];
901 }
902 
903 /*
904 ** RB_CalcRotateTexMatrix
905 */
RB_CalcRotateTexMatrix(float degsPerSecond,float * matrix)906 void RB_CalcRotateTexMatrix( float degsPerSecond, float *matrix )
907 {
908 	double timeScale = tess.shaderTime;
909 	double degs;
910 	int64_t index;
911 	float sinValue, cosValue;
912 
913 	degs = -degsPerSecond * timeScale;
914 	index = degs * ( FUNCTABLE_SIZE / 360.0f );
915 
916 	sinValue = tr.sinTable[ index & FUNCTABLE_MASK ];
917 	cosValue = tr.sinTable[ ( index + FUNCTABLE_SIZE / 4 ) & FUNCTABLE_MASK ];
918 
919 	matrix[0] = cosValue; matrix[2] = -sinValue; matrix[4] = 0.5 - 0.5 * cosValue + 0.5 * sinValue;
920 	matrix[1] = sinValue; matrix[3] = cosValue;  matrix[5] = 0.5 - 0.5 * sinValue - 0.5 * cosValue;
921 }
922