Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

tr_shadows.c (7900B)


      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 Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 #include "tr_local.h"
     23 
     24 
     25 /*
     26 
     27   for a projection shadow:
     28 
     29   point[x] += light vector * ( z - shadow plane )
     30   point[y] +=
     31   point[z] = shadow plane
     32 
     33   1 0 light[x] / light[z]
     34 
     35 */
     36 
     37 typedef struct {
     38 	int		i2;
     39 	int		facing;
     40 } edgeDef_t;
     41 
     42 #define	MAX_EDGE_DEFS	32
     43 
     44 static	edgeDef_t	edgeDefs[SHADER_MAX_VERTEXES][MAX_EDGE_DEFS];
     45 static	int			numEdgeDefs[SHADER_MAX_VERTEXES];
     46 static	int			facing[SHADER_MAX_INDEXES/3];
     47 
     48 void R_AddEdgeDef( int i1, int i2, int facing ) {
     49 	int		c;
     50 
     51 	c = numEdgeDefs[ i1 ];
     52 	if ( c == MAX_EDGE_DEFS ) {
     53 		return;		// overflow
     54 	}
     55 	edgeDefs[ i1 ][ c ].i2 = i2;
     56 	edgeDefs[ i1 ][ c ].facing = facing;
     57 
     58 	numEdgeDefs[ i1 ]++;
     59 }
     60 
     61 void R_RenderShadowEdges( void ) {
     62 	int		i;
     63 
     64 #if 0
     65 	int		numTris;
     66 
     67 	// dumb way -- render every triangle's edges
     68 	numTris = tess.numIndexes / 3;
     69 
     70 	for ( i = 0 ; i < numTris ; i++ ) {
     71 		int		i1, i2, i3;
     72 
     73 		if ( !facing[i] ) {
     74 			continue;
     75 		}
     76 
     77 		i1 = tess.indexes[ i*3 + 0 ];
     78 		i2 = tess.indexes[ i*3 + 1 ];
     79 		i3 = tess.indexes[ i*3 + 2 ];
     80 
     81 		qglBegin( GL_TRIANGLE_STRIP );
     82 		qglVertex3fv( tess.xyz[ i1 ] );
     83 		qglVertex3fv( tess.xyz[ i1 + tess.numVertexes ] );
     84 		qglVertex3fv( tess.xyz[ i2 ] );
     85 		qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] );
     86 		qglVertex3fv( tess.xyz[ i3 ] );
     87 		qglVertex3fv( tess.xyz[ i3 + tess.numVertexes ] );
     88 		qglVertex3fv( tess.xyz[ i1 ] );
     89 		qglVertex3fv( tess.xyz[ i1 + tess.numVertexes ] );
     90 		qglEnd();
     91 	}
     92 #else
     93 	int		c, c2;
     94 	int		j, k;
     95 	int		i2;
     96 	int		c_edges, c_rejected;
     97 	int		hit[2];
     98 
     99 	// an edge is NOT a silhouette edge if its face doesn't face the light,
    100 	// or if it has a reverse paired edge that also faces the light.
    101 	// A well behaved polyhedron would have exactly two faces for each edge,
    102 	// but lots of models have dangling edges or overfanned edges
    103 	c_edges = 0;
    104 	c_rejected = 0;
    105 
    106 	for ( i = 0 ; i < tess.numVertexes ; i++ ) {
    107 		c = numEdgeDefs[ i ];
    108 		for ( j = 0 ; j < c ; j++ ) {
    109 			if ( !edgeDefs[ i ][ j ].facing ) {
    110 				continue;
    111 			}
    112 
    113 			hit[0] = 0;
    114 			hit[1] = 0;
    115 
    116 			i2 = edgeDefs[ i ][ j ].i2;
    117 			c2 = numEdgeDefs[ i2 ];
    118 			for ( k = 0 ; k < c2 ; k++ ) {
    119 				if ( edgeDefs[ i2 ][ k ].i2 == i ) {
    120 					hit[ edgeDefs[ i2 ][ k ].facing ]++;
    121 				}
    122 			}
    123 
    124 			// if it doesn't share the edge with another front facing
    125 			// triangle, it is a sil edge
    126 			if ( hit[ 1 ] == 0 ) {
    127 				qglBegin( GL_TRIANGLE_STRIP );
    128 				qglVertex3fv( tess.xyz[ i ] );
    129 				qglVertex3fv( tess.xyz[ i + tess.numVertexes ] );
    130 				qglVertex3fv( tess.xyz[ i2 ] );
    131 				qglVertex3fv( tess.xyz[ i2 + tess.numVertexes ] );
    132 				qglEnd();
    133 				c_edges++;
    134 			} else {
    135 				c_rejected++;
    136 			}
    137 		}
    138 	}
    139 #endif
    140 }
    141 
    142 /*
    143 =================
    144 RB_ShadowTessEnd
    145 
    146 triangleFromEdge[ v1 ][ v2 ]
    147 
    148 
    149   set triangle from edge( v1, v2, tri )
    150   if ( facing[ triangleFromEdge[ v1 ][ v2 ] ] && !facing[ triangleFromEdge[ v2 ][ v1 ] ) {
    151   }
    152 =================
    153 */
    154 void RB_ShadowTessEnd( void ) {
    155 	int		i;
    156 	int		numTris;
    157 	vec3_t	lightDir;
    158 
    159 	// we can only do this if we have enough space in the vertex buffers
    160 	if ( tess.numVertexes >= SHADER_MAX_VERTEXES / 2 ) {
    161 		return;
    162 	}
    163 
    164 	if ( glConfig.stencilBits < 4 ) {
    165 		return;
    166 	}
    167 
    168 	VectorCopy( backEnd.currentEntity->lightDir, lightDir );
    169 
    170 	// project vertexes away from light direction
    171 	for ( i = 0 ; i < tess.numVertexes ; i++ ) {
    172 		VectorMA( tess.xyz[i], -512, lightDir, tess.xyz[i+tess.numVertexes] );
    173 	}
    174 
    175 	// decide which triangles face the light
    176 	Com_Memset( numEdgeDefs, 0, 4 * tess.numVertexes );
    177 
    178 	numTris = tess.numIndexes / 3;
    179 	for ( i = 0 ; i < numTris ; i++ ) {
    180 		int		i1, i2, i3;
    181 		vec3_t	d1, d2, normal;
    182 		float	*v1, *v2, *v3;
    183 		float	d;
    184 
    185 		i1 = tess.indexes[ i*3 + 0 ];
    186 		i2 = tess.indexes[ i*3 + 1 ];
    187 		i3 = tess.indexes[ i*3 + 2 ];
    188 
    189 		v1 = tess.xyz[ i1 ];
    190 		v2 = tess.xyz[ i2 ];
    191 		v3 = tess.xyz[ i3 ];
    192 
    193 		VectorSubtract( v2, v1, d1 );
    194 		VectorSubtract( v3, v1, d2 );
    195 		CrossProduct( d1, d2, normal );
    196 
    197 		d = DotProduct( normal, lightDir );
    198 		if ( d > 0 ) {
    199 			facing[ i ] = 1;
    200 		} else {
    201 			facing[ i ] = 0;
    202 		}
    203 
    204 		// create the edges
    205 		R_AddEdgeDef( i1, i2, facing[ i ] );
    206 		R_AddEdgeDef( i2, i3, facing[ i ] );
    207 		R_AddEdgeDef( i3, i1, facing[ i ] );
    208 	}
    209 
    210 	// draw the silhouette edges
    211 
    212 	GL_Bind( tr.whiteImage );
    213 	qglEnable( GL_CULL_FACE );
    214 	GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
    215 	qglColor3f( 0.2f, 0.2f, 0.2f );
    216 
    217 	// don't write to the color buffer
    218 	qglColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
    219 
    220 	qglEnable( GL_STENCIL_TEST );
    221 	qglStencilFunc( GL_ALWAYS, 1, 255 );
    222 
    223 	// mirrors have the culling order reversed
    224 	if ( backEnd.viewParms.isMirror ) {
    225 		qglCullFace( GL_FRONT );
    226 		qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR );
    227 
    228 		R_RenderShadowEdges();
    229 
    230 		qglCullFace( GL_BACK );
    231 		qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR );
    232 
    233 		R_RenderShadowEdges();
    234 	} else {
    235 		qglCullFace( GL_BACK );
    236 		qglStencilOp( GL_KEEP, GL_KEEP, GL_INCR );
    237 
    238 		R_RenderShadowEdges();
    239 
    240 		qglCullFace( GL_FRONT );
    241 		qglStencilOp( GL_KEEP, GL_KEEP, GL_DECR );
    242 
    243 		R_RenderShadowEdges();
    244 	}
    245 
    246 
    247 	// reenable writing to the color buffer
    248 	qglColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
    249 }
    250 
    251 
    252 /*
    253 =================
    254 RB_ShadowFinish
    255 
    256 Darken everything that is is a shadow volume.
    257 We have to delay this until everything has been shadowed,
    258 because otherwise shadows from different body parts would
    259 overlap and double darken.
    260 =================
    261 */
    262 void RB_ShadowFinish( void ) {
    263 	if ( r_shadows->integer != 2 ) {
    264 		return;
    265 	}
    266 	if ( glConfig.stencilBits < 4 ) {
    267 		return;
    268 	}
    269 	qglEnable( GL_STENCIL_TEST );
    270 	qglStencilFunc( GL_NOTEQUAL, 0, 255 );
    271 
    272 	qglDisable (GL_CLIP_PLANE0);
    273 	qglDisable (GL_CULL_FACE);
    274 
    275 	GL_Bind( tr.whiteImage );
    276 
    277     qglLoadIdentity ();
    278 
    279 	qglColor3f( 0.6f, 0.6f, 0.6f );
    280 	GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_DST_COLOR | GLS_DSTBLEND_ZERO );
    281 
    282 //	qglColor3f( 1, 0, 0 );
    283 //	GL_State( GLS_DEPTHMASK_TRUE | GLS_SRCBLEND_ONE | GLS_DSTBLEND_ZERO );
    284 
    285 	qglBegin( GL_QUADS );
    286 	qglVertex3f( -100, 100, -10 );
    287 	qglVertex3f( 100, 100, -10 );
    288 	qglVertex3f( 100, -100, -10 );
    289 	qglVertex3f( -100, -100, -10 );
    290 	qglEnd ();
    291 
    292 	qglColor4f(1,1,1,1);
    293 	qglDisable( GL_STENCIL_TEST );
    294 }
    295 
    296 
    297 /*
    298 =================
    299 RB_ProjectionShadowDeform
    300 
    301 =================
    302 */
    303 void RB_ProjectionShadowDeform( void ) {
    304 	float	*xyz;
    305 	int		i;
    306 	float	h;
    307 	vec3_t	ground;
    308 	vec3_t	light;
    309 	float	groundDist;
    310 	float	d;
    311 	vec3_t	lightDir;
    312 
    313 	xyz = ( float * ) tess.xyz;
    314 
    315 	ground[0] = backEnd.or.axis[0][2];
    316 	ground[1] = backEnd.or.axis[1][2];
    317 	ground[2] = backEnd.or.axis[2][2];
    318 
    319 	groundDist = backEnd.or.origin[2] - backEnd.currentEntity->e.shadowPlane;
    320 
    321 	VectorCopy( backEnd.currentEntity->lightDir, lightDir );
    322 	d = DotProduct( lightDir, ground );
    323 	// don't let the shadows get too long or go negative
    324 	if ( d < 0.5 ) {
    325 		VectorMA( lightDir, (0.5 - d), ground, lightDir );
    326 		d = DotProduct( lightDir, ground );
    327 	}
    328 	d = 1.0 / d;
    329 
    330 	light[0] = lightDir[0] * d;
    331 	light[1] = lightDir[1] * d;
    332 	light[2] = lightDir[2] * d;
    333 
    334 	for ( i = 0; i < tess.numVertexes; i++, xyz += 4 ) {
    335 		h = DotProduct( xyz, ground ) + groundDist;
    336 
    337 		xyz[0] -= light[0] * h;
    338 		xyz[1] -= light[1] * h;
    339 		xyz[2] -= light[2] * h;
    340 	}
    341 }