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 #include "tr_local.h"
30
31
32 /*
33
34 for a projection shadow:
35
36 point[x] += light vector * ( z - shadow plane )
37 point[y] +=
38 point[z] = shadow plane
39
40 1 0 light[x] / light[z]
41
42 */
43
44 typedef struct {
45 int i2;
46 int facing;
47 } edgeDef_t;
48
49 #define MAX_EDGE_DEFS 32
50
51 static edgeDef_t edgeDefs[SHADER_MAX_VERTEXES][MAX_EDGE_DEFS];
52 static int numEdgeDefs[SHADER_MAX_VERTEXES];
53 static int facing[SHADER_MAX_INDEXES / 3];
54 static vec3_t shadowXyz[SHADER_MAX_VERTEXES];
55
56 #ifdef USE_OPENGLES
57 static unsigned short indexes[6*MAX_EDGE_DEFS*SHADER_MAX_VERTEXES];
58 static int idx = 0;
59 #endif
60
R_AddEdgeDef(int i1,int i2,int facing)61 void R_AddEdgeDef( int i1, int i2, int facing ) {
62 int c;
63
64 c = numEdgeDefs[ i1 ];
65 if ( c == MAX_EDGE_DEFS ) {
66 return; // overflow
67 }
68 edgeDefs[ i1 ][ c ].i2 = i2;
69 edgeDefs[ i1 ][ c ].facing = facing;
70
71 numEdgeDefs[ i1 ]++;
72 }
73
R_RenderShadowEdges(void)74 void R_RenderShadowEdges( void ) {
75 int i;
76
77 #if 0
78 int numTris;
79
80 // dumb way -- render every triangle's edges
81 numTris = tess.numIndexes / 3;
82
83 for ( i = 0 ; i < numTris ; i++ ) {
84 int i1, i2, i3;
85
86 if ( !facing[i] ) {
87 continue;
88 }
89
90 i1 = tess.indexes[ i * 3 + 0 ];
91 i2 = tess.indexes[ i * 3 + 1 ];
92 i3 = tess.indexes[ i * 3 + 2 ];
93
94 qglBegin( GL_TRIANGLE_STRIP );
95 qglVertex3fv( tess.xyz[ i1 ] );
96 qglVertex3fv( shadowXyz[ i1 ] );
97 qglVertex3fv( tess.xyz[ i2 ] );
98 qglVertex3fv( shadowXyz[ i2 ] );
99 qglVertex3fv( tess.xyz[ i3 ] );
100 qglVertex3fv( shadowXyz[ i3 ] );
101 qglVertex3fv( tess.xyz[ i1 ] );
102 qglVertex3fv( shadowXyz[ i1 ] );
103 qglEnd();
104 }
105 #else
106 int c, c2;
107 int j, k;
108 int i2;
109 int c_edges, c_rejected;
110 int hit[2];
111 #ifdef USE_OPENGLES
112 idx = 0;
113 #endif
114
115 // an edge is NOT a silhouette edge if its face doesn't face the light,
116 // or if it has a reverse paired edge that also faces the light.
117 // A well behaved polyhedron would have exactly two faces for each edge,
118 // but lots of models have dangling edges or overfanned edges
119 c_edges = 0;
120 c_rejected = 0;
121
122 for ( i = 0 ; i < tess.numVertexes ; i++ ) {
123 c = numEdgeDefs[ i ];
124 for ( j = 0 ; j < c ; j++ ) {
125 if ( !edgeDefs[ i ][ j ].facing ) {
126 continue;
127 }
128
129 hit[0] = 0;
130 hit[1] = 0;
131
132 i2 = edgeDefs[ i ][ j ].i2;
133 c2 = numEdgeDefs[ i2 ];
134 for ( k = 0 ; k < c2 ; k++ ) {
135 if ( edgeDefs[ i2 ][ k ].i2 == i ) {
136 hit[ edgeDefs[ i2 ][ k ].facing ]++;
137 }
138 }
139
140 // if it doesn't share the edge with another front facing
141 // triangle, it is a sil edge
142 if ( hit[ 1 ] == 0 ) {
143 #ifdef USE_OPENGLES
144 // A single drawing call is better than many. So I prefer a singe TRIANGLES call than many TRAINGLE_STRIP call
145 // even if it seems less efficiant, it's faster on the PANDORA
146 indexes[idx++] = i;
147 indexes[idx++] = i + tess.numVertexes;
148 indexes[idx++] = i2;
149 indexes[idx++] = i2;
150 indexes[idx++] = i + tess.numVertexes;
151 indexes[idx++] = i2 + tess.numVertexes;
152 #else
153 qglBegin( GL_TRIANGLE_STRIP );
154 qglVertex3fv( tess.xyz[ i ] );
155 qglVertex3fv( shadowXyz[ i ] );
156 qglVertex3fv( tess.xyz[ i2 ] );
157 qglVertex3fv( shadowXyz[ i2 ] );
158 qglEnd();
159 #endif
160 c_edges++;
161 } else {
162 c_rejected++;
163 }
164 }
165 }
166
167 #ifdef USE_OPENGLES
168 qglDrawElements(GL_TRIANGLES, idx, GL_UNSIGNED_SHORT, indexes);
169 #endif
170
171 #endif
172 }
173
174 /*
175 =================
176 RB_ShadowTessEnd
177
178 triangleFromEdge[ v1 ][ v2 ]
179
180
181 set triangle from edge( v1, v2, tri )
182 if ( facing[ triangleFromEdge[ v1 ][ v2 ] ] && !facing[ triangleFromEdge[ v2 ][ v1 ] ) {
183 }
184 =================
185 */
RB_ShadowTessEnd(void)186 void RB_ShadowTessEnd( void ) {
187 int i;
188 int numTris;
189 vec3_t lightDir;
190 GLboolean rgba[4];
191
192 if ( glConfig.stencilBits < 4 ) {
193 return;
194 }
195
196 VectorCopy( backEnd.currentEntity->lightDir, lightDir );
197
198 // project vertexes away from light direction
199 for ( i = 0 ; i < tess.numVertexes ; i++ ) {
200 VectorMA( tess.xyz[i], -512, lightDir, shadowXyz[i] );
201 }
202
203 // decide which triangles face the light
204 memset( numEdgeDefs, 0, 4 * tess.numVertexes );
205
206 numTris = tess.numIndexes / 3;
207 for ( i = 0 ; i < numTris ; i++ ) {
208 int i1, i2, i3;
209 vec3_t d1, d2, normal;
210 float *v1, *v2, *v3;
211 float d;
212
213 i1 = tess.indexes[ i * 3 + 0 ];
214 i2 = tess.indexes[ i * 3 + 1 ];
215 i3 = tess.indexes[ i * 3 + 2 ];
216
217 v1 = tess.xyz[ i1 ];
218 v2 = tess.xyz[ i2 ];
219 v3 = tess.xyz[ i3 ];
220
221 VectorSubtract( v2, v1, d1 );
222 VectorSubtract( v3, v1, d2 );
223 CrossProduct( d1, d2, normal );
224
225 d = DotProduct( normal, lightDir );
226 if ( d > 0 ) {
227 facing[ i ] = 1;
228 } else {
229 facing[ i ] = 0;
230 }
231
232 // create the edges
233 R_AddEdgeDef( i1, i2, facing[ i ] );
234 R_AddEdgeDef( i2, i3, facing[ i ] );
235 R_AddEdgeDef( i3, i1, facing[ i ] );
236 }
237
238 // draw the silhouette edges
239
240 GL_Bind( tr.whiteImage );
241 GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
242 qglColor3f( 0.2f, 0.2f, 0.2f );
243
244 // don't write to the color buffer
245 qglGetBooleanv(GL_COLOR_WRITEMASK, rgba);
246 qglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
247
248 qglEnable( GL_STENCIL_TEST );
249 qglStencilFunc( GL_ALWAYS, 1, 255 );
250
251 #ifdef USE_OPENGLES
252 qglVertexPointer (3, GL_FLOAT, 16, tess.xyz);
253 GLboolean text = qglIsEnabled(GL_TEXTURE_COORD_ARRAY);
254 GLboolean glcol = qglIsEnabled(GL_COLOR_ARRAY);
255 if (text)
256 qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
257 if (glcol)
258 qglDisableClientState( GL_COLOR_ARRAY );
259 #endif
260
261 GL_Cull( CT_BACK_SIDED );
262 qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR );
263
264 R_RenderShadowEdges();
265
266 GL_Cull( CT_FRONT_SIDED );
267 qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR );
268
269 #ifdef USE_OPENGLES
270 qglDrawElements(GL_TRIANGLES, idx, GL_UNSIGNED_SHORT, indexes);
271 #else
272 R_RenderShadowEdges();
273 #endif
274
275 #ifdef USE_OPENGLES
276 if (text)
277 qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
278 if (glcol)
279 qglEnableClientState( GL_COLOR_ARRAY );
280 #endif
281
282 // reenable writing to the color buffer
283 qglColorMask(rgba[0], rgba[1], rgba[2], rgba[3]);
284 }
285
286
287 /*
288 =================
289 RB_ShadowFinish
290
291 Darken everything that is is a shadow volume.
292 We have to delay this until everything has been shadowed,
293 because otherwise shadows from different body parts would
294 overlap and double darken.
295 =================
296 */
RB_ShadowFinish(void)297 void RB_ShadowFinish( void ) {
298 if ( r_shadows->integer != 2 ) {
299 return;
300 }
301 if ( glConfig.stencilBits < 4 ) {
302 return;
303 }
304 qglEnable( GL_STENCIL_TEST );
305 qglStencilFunc( GL_NOTEQUAL, 0, 255 );
306
307 qglDisable( GL_CLIP_PLANE0 );
308 GL_Cull( CT_TWO_SIDED );
309
310 GL_Bind( tr.whiteImage );
311
312 qglLoadIdentity();
313
314 qglColor3f( 0.6f, 0.6f, 0.6f );
315 GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO );
316
317 // qglColor3f( 1, 0, 0 );
318 // GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
319
320 #ifdef USE_OPENGLES
321 GLboolean text = qglIsEnabled(GL_TEXTURE_COORD_ARRAY);
322 GLboolean glcol = qglIsEnabled(GL_COLOR_ARRAY);
323 if (text)
324 qglDisableClientState( GL_TEXTURE_COORD_ARRAY );
325 if (glcol)
326 qglDisableClientState( GL_COLOR_ARRAY );
327 GLfloat vtx[] = {
328 -100, 100, -10,
329 100, 100, -10,
330 100, -100, -10,
331 -100, -100, -10
332 };
333 qglVertexPointer ( 3, GL_FLOAT, 0, vtx );
334 qglDrawArrays( GL_TRIANGLE_FAN, 0, 4 );
335 if (text)
336 qglEnableClientState( GL_TEXTURE_COORD_ARRAY );
337 if (glcol)
338 qglEnableClientState( GL_COLOR_ARRAY );
339 #else
340 qglBegin( GL_QUADS );
341 qglVertex3f( -100, 100, -10 );
342 qglVertex3f( 100, 100, -10 );
343 qglVertex3f( 100, -100, -10 );
344 qglVertex3f( -100, -100, -10 );
345 qglEnd();
346 #endif
347
348 qglColor4f( 1,1,1,1 );
349 qglDisable( GL_STENCIL_TEST );
350 }
351
352
353 /*
354 =================
355 RB_ProjectionShadowDeform
356
357 =================
358 */
RB_ProjectionShadowDeform(void)359 void RB_ProjectionShadowDeform( void ) {
360 float *xyz;
361 int i;
362 float h;
363 vec3_t ground;
364 vec3_t light;
365 float groundDist;
366 float d;
367 vec3_t lightDir;
368
369 xyz = ( float * ) tess.xyz;
370
371 ground[0] = backEnd.or.axis[0][2];
372 ground[1] = backEnd.or.axis[1][2];
373 ground[2] = backEnd.or.axis[2][2];
374
375 groundDist = backEnd.or.origin[2] - backEnd.currentEntity->e.shadowPlane;
376
377 VectorCopy( backEnd.currentEntity->lightDir, lightDir );
378 d = DotProduct( lightDir, ground );
379 // don't let the shadows get too long or go negative
380 if ( d < 0.5 ) {
381 VectorMA( lightDir, ( 0.5 - d ), ground, lightDir );
382 d = DotProduct( lightDir, ground );
383 }
384 d = 1.0 / d;
385
386 light[0] = lightDir[0] * d;
387 light[1] = lightDir[1] * d;
388 light[2] = lightDir[2] * d;
389
390 for ( i = 0; i < tess.numVertexes; i++, xyz += 4 ) {
391 h = DotProduct( xyz, ground ) + groundDist;
392
393 xyz[0] -= light[0] * h;
394 xyz[1] -= light[1] * h;
395 xyz[2] -= light[2] * h;
396 }
397 }
398