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