2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
\r
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
\r
5 This file is part of GtkRadiant.
\r
7 GtkRadiant is free software; you can redistribute it and/or modify
\r
8 it under the terms of the GNU General Public License as published by
\r
9 the Free Software Foundation; either version 2 of the License, or
\r
10 (at your option) any later version.
\r
12 GtkRadiant is distributed in the hope that it will be useful,
\r
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
15 GNU General Public License for more details.
\r
17 You should have received a copy of the GNU General Public License
\r
18 along with GtkRadiant; if not, write to the Free Software
\r
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
\r
21 ----------------------------------------------------------------------------------
\r
23 This code has been altered significantly from its original form, to support
\r
24 several games based on the Quake III Arena engine, in the form of "Q3Map2."
\r
26 ------------------------------------------------------------------------------- */
\r
40 #define MAX_PROJECTORS 1024
\r
42 typedef struct decalProjector_s
\r
47 float radius, radius2;
\r
48 int numPlanes; /* either 5 or 6, for quad or triangle projectors */
\r
54 static int numProjectors = 0;
\r
55 static decalProjector_t projectors[ MAX_PROJECTORS ];
\r
57 static int numDecalSurfaces = 0;
\r
59 static vec3_t entityOrigin;
\r
65 normalizes a vector, returns the length, operates using doubles
\r
68 typedef double dvec_t;
\r
69 typedef dvec_t dvec3_t[ 3 ];
\r
71 dvec_t DVectorNormalize( dvec3_t in, dvec3_t out )
\r
76 len = (dvec_t) sqrt( in[ 0 ] * in[ 0 ] + in[ 1 ] * in[ 1 ] + in[ 2 ] * in[ 2 ] );
\r
84 out[ 0 ] = in[ 0 ] * ilen;
\r
85 out[ 1 ] = in[ 1 ] * ilen;
\r
86 out[ 2 ] = in[ 2 ] * ilen;
\r
95 generates a texture projection matrix for a triangle
\r
96 returns qfalse if a texture matrix cannot be created
\r
99 #define Vector2Subtract(a,b,c) ((c)[ 0 ] = (a)[ 0 ] - (b)[ 0 ], (c)[ 1 ] = (a)[ 1 ] - (b)[ 1 ])
\r
101 static qboolean MakeTextureMatrix( decalProjector_t *dp, vec4_t projection, bspDrawVert_t *a, bspDrawVert_t *b, bspDrawVert_t *c )
\r
104 double bb, s, t, d;
\r
105 dvec3_t pa, pb, pc;
\r
107 dvec3_t vecs[ 3 ], axis[ 3 ], lengths;
\r
110 /* project triangle onto plane of projection */
\r
111 d = DotProduct( a->xyz, projection ) - projection[ 3 ];
\r
112 VectorMA( a->xyz, -d, projection, pa );
\r
113 d = DotProduct( b->xyz, projection ) - projection[ 3 ];
\r
114 VectorMA( b->xyz, -d, projection, pb );
\r
115 d = DotProduct( c->xyz, projection ) - projection[ 3 ];
\r
116 VectorMA( c->xyz, -d, projection, pc );
\r
123 /* calculate barycentric basis for the triangle */
\r
124 bb = (b->st[ 0 ] - a->st[ 0 ]) * (c->st[ 1 ] - a->st[ 1 ]) - (c->st[ 0 ] - a->st[ 0 ]) * (b->st[ 1 ] - a->st[ 1 ]);
\r
125 if( fabs( bb ) < 0.00000001 )
\r
128 /* calculate texture origin */
\r
132 bary[ 0 ] = ((b->st[ 0 ] - s) * (c->st[ 1 ] - t) - (c->st[ 0 ] - s) * (b->st[ 1 ] - t)) / bb;
\r
133 bary[ 1 ] = ((c->st[ 0 ] - s) * (a->st[ 1 ] - t) - (a->st[ 0 ] - s) * (c->st[ 1 ] - t)) / bb;
\r
134 bary[ 2 ] = ((a->st[ 0 ] - s) * (b->st[ 1 ] - t) - (b->st[ 0 ] - s) * (a->st[ 1 ] - t)) / bb;
\r
136 origin[ 0 ] = bary[ 0 ] * pa[ 0 ] + bary[ 1 ] * pb[ 0 ] + bary[ 2 ] * pc[ 0 ];
\r
137 origin[ 1 ] = bary[ 0 ] * pa[ 1 ] + bary[ 1 ] * pb[ 1 ] + bary[ 2 ] * pc[ 1 ];
\r
138 origin[ 2 ] = bary[ 0 ] * pa[ 2 ] + bary[ 1 ] * pb[ 2 ] + bary[ 2 ] * pc[ 2 ];
\r
141 /* calculate s vector */
\r
142 s = a->st[ 0 ] + 1.0;
\r
143 t = a->st[ 1 ] + 0.0;
\r
144 bary[ 0 ] = ((b->st[ 0 ] - s) * (c->st[ 1 ] - t) - (c->st[ 0 ] - s) * (b->st[ 1 ] - t)) / bb;
\r
145 bary[ 1 ] = ((c->st[ 0 ] - s) * (a->st[ 1 ] - t) - (a->st[ 0 ] - s) * (c->st[ 1 ] - t)) / bb;
\r
146 bary[ 2 ] = ((a->st[ 0 ] - s) * (b->st[ 1 ] - t) - (b->st[ 0 ] - s) * (a->st[ 1 ] - t)) / bb;
\r
148 xyz[ 0 ] = bary[ 0 ] * pa[ 0 ] + bary[ 1 ] * pb[ 0 ] + bary[ 2 ] * pc[ 0 ];
\r
149 xyz[ 1 ] = bary[ 0 ] * pa[ 1 ] + bary[ 1 ] * pb[ 1 ] + bary[ 2 ] * pc[ 1 ];
\r
150 xyz[ 2 ] = bary[ 0 ] * pa[ 2 ] + bary[ 1 ] * pb[ 2 ] + bary[ 2 ] * pc[ 2 ];
\r
152 //% VectorSubtract( xyz, origin, vecs[ 0 ] );
\r
153 VectorSubtract( xyz, pa, vecs[ 0 ] );
\r
155 /* calculate t vector */
\r
156 s = a->st[ 0 ] + 0.0;
\r
157 t = a->st[ 1 ] + 1.0;
\r
158 bary[ 0 ] = ((b->st[ 0 ] - s) * (c->st[ 1 ] - t) - (c->st[ 0 ] - s) * (b->st[ 1 ] - t)) / bb;
\r
159 bary[ 1 ] = ((c->st[ 0 ] - s) * (a->st[ 1 ] - t) - (a->st[ 0 ] - s) * (c->st[ 1 ] - t)) / bb;
\r
160 bary[ 2 ] = ((a->st[ 0 ] - s) * (b->st[ 1 ] - t) - (b->st[ 0 ] - s) * (a->st[ 1 ] - t)) / bb;
\r
162 xyz[ 0 ] = bary[ 0 ] * pa[ 0 ] + bary[ 1 ] * pb[ 0 ] + bary[ 2 ] * pc[ 0 ];
\r
163 xyz[ 1 ] = bary[ 0 ] * pa[ 1 ] + bary[ 1 ] * pb[ 1 ] + bary[ 2 ] * pc[ 1 ];
\r
164 xyz[ 2 ] = bary[ 0 ] * pa[ 2 ] + bary[ 1 ] * pb[ 2 ] + bary[ 2 ] * pc[ 2 ];
\r
166 //% VectorSubtract( xyz, origin, vecs[ 1 ] );
\r
167 VectorSubtract( xyz, pa, vecs[ 1 ] );
\r
169 /* calcuate r vector */
\r
170 VectorScale( projection, -1.0, vecs[ 2 ] );
\r
172 /* calculate transform axis */
\r
173 for( i = 0; i < 3; i++ )
\r
174 lengths[ i ] = DVectorNormalize( vecs[ i ], axis[ i ] );
\r
175 for( i = 0; i < 2; i++ )
\r
176 for( j = 0; j < 3; j++ )
\r
177 dp->texMat[ i ][ j ] = lengths[ i ] > 0.0 ? (axis[ i ][ j ] / lengths[ i ]) : 0.0;
\r
178 //% dp->texMat[ i ][ j ] = fabs( vecs[ i ][ j ] ) > 0.0 ? (1.0 / vecs[ i ][ j ]) : 0.0;
\r
179 //% dp->texMat[ i ][ j ] = axis[ i ][ j ] > 0.0 ? (1.0 / axis[ i ][ j ]) : 0.0;
\r
181 /* calculalate translation component */
\r
182 dp->texMat[ 0 ][ 3 ] = a->st[ 0 ] - DotProduct( a->xyz, dp->texMat[ 0 ] );
\r
183 dp->texMat[ 1 ][ 3 ] = a->st[ 1 ] - DotProduct( a->xyz, dp->texMat[ 1 ] );
\r
188 dvec3_t origin, deltas[ 3 ];
\r
189 double texDeltas[ 3 ][ 2 ];
\r
190 double delta, texDelta;
\r
195 /* calculate deltas */
\r
196 VectorSubtract( pa, pb, deltas[ 0 ] );
\r
197 VectorSubtract( pa, pc, deltas[ 1 ] );
\r
198 VectorSubtract( pb, pc, deltas[ 2 ] );
\r
199 Vector2Subtract( a->st, b->st, texDeltas[ 0 ] );
\r
200 Vector2Subtract( a->st, c->st, texDeltas[ 1 ] );
\r
201 Vector2Subtract( b->st, c->st, texDeltas[ 2 ] );
\r
204 for( i = 0; i < 2; i++ )
\r
207 for( j = 0; j < 3; j++ )
\r
214 for( k = 0; k < 3; k++ )
\r
216 if( fabs( deltas[ k ][ j ] ) > delta &&
\r
217 fabs( texDeltas[ k ][ i ] ) > texDelta )
\r
219 delta = deltas[ k ][ j ];
\r
220 texDelta = texDeltas[ k ][ i ];
\r
224 /* set texture matrix component */
\r
225 if( fabs( delta ) > 0.0 )
\r
226 dp->texMat[ i ][ j ] = texDelta / delta;
\r
228 dp->texMat[ i ][ j ] = 0.0;
\r
231 /* set translation component */
\r
232 dp->texMat[ i ][ 3 ] = a->st[ i ] - DotProduct( pa, dp->texMat[ i ] );
\r
239 Sys_Printf( "Mat: [ %f %f %f %f ] [ %f %f %f %f ] Theta: %f (%f)\n",
\r
240 dp->texMat[ 0 ][ 0 ], dp->texMat[ 0 ][ 1 ], dp->texMat[ 0 ][ 2 ], dp->texMat[ 0 ][ 3 ],
\r
241 dp->texMat[ 1 ][ 0 ], dp->texMat[ 1 ][ 1 ], dp->texMat[ 1 ][ 2 ], dp->texMat[ 1 ][ 3 ],
\r
242 RAD2DEG( acos( DotProduct( dp->texMat[ 0 ], dp->texMat[ 1 ] ) ) ),
\r
243 RAD2DEG( acos( DotProduct( axis[ 0 ], axis[ 1 ] ) ) ) );
\r
245 Sys_Printf( "XYZ: %f %f %f ST: %f %f ST(t): %f %f\n",
\r
246 a->xyz[ 0 ], a->xyz[ 1 ], a->xyz[ 2 ],
\r
247 a->st[ 0 ], a->st[ 1 ],
\r
248 DotProduct( a->xyz, dp->texMat[ 0 ] ) + dp->texMat[ 0 ][ 3 ], DotProduct( a->xyz, dp->texMat[ 1 ] ) + dp->texMat[ 1 ][ 3 ] );
\r
251 /* test texture matrix */
\r
252 s = DotProduct( a->xyz, dp->texMat[ 0 ] ) + dp->texMat[ 0 ][ 3 ];
\r
253 t = DotProduct( a->xyz, dp->texMat[ 1 ] ) + dp->texMat[ 1 ][ 3 ];
\r
254 if( fabs( s - a->st[ 0 ] ) > 0.01 || fabs( t - a->st[ 1 ] ) > 0.01 )
\r
256 Sys_Printf( "Bad texture matrix! (A) (%f, %f) != (%f, %f)\n",
\r
257 s, t, a->st[ 0 ], a->st[ 1 ] );
\r
260 s = DotProduct( b->xyz, dp->texMat[ 0 ] ) + dp->texMat[ 0 ][ 3 ];
\r
261 t = DotProduct( b->xyz, dp->texMat[ 1 ] ) + dp->texMat[ 1 ][ 3 ];
\r
262 if( fabs( s - b->st[ 0 ] ) > 0.01 || fabs( t - b->st[ 1 ] ) > 0.01 )
\r
264 Sys_Printf( "Bad texture matrix! (B) (%f, %f) != (%f, %f)\n",
\r
265 s, t, b->st[ 0 ], b->st[ 1 ] );
\r
268 s = DotProduct( c->xyz, dp->texMat[ 0 ] ) + dp->texMat[ 0 ][ 3 ];
\r
269 t = DotProduct( c->xyz, dp->texMat[ 1 ] ) + dp->texMat[ 1 ][ 3 ];
\r
270 if( fabs( s - c->st[ 0 ] ) > 0.01 || fabs( t - c->st[ 1 ] ) > 0.01 )
\r
272 Sys_Printf( "Bad texture matrix! (C) (%f, %f) != (%f, %f)\n",
\r
273 s, t, c->st[ 0 ], c->st[ 1 ] );
\r
284 TransformDecalProjector()
\r
285 transforms a decal projector
\r
286 note: non-normalized axes will screw up the plane transform
\r
289 static void TransformDecalProjector( decalProjector_t *in, vec3_t axis[ 3 ], vec3_t origin, decalProjector_t *out )
\r
294 /* copy misc stuff */
\r
296 out->numPlanes = in->numPlanes;
\r
298 /* translate bounding box and sphere (note: rotated projector bounding box will be invalid!) */
\r
299 VectorSubtract( in->mins, origin, out->mins );
\r
300 VectorSubtract( in->maxs, origin, out->maxs );
\r
301 VectorSubtract( in->center, origin, out->center );
\r
302 out->radius = in->radius;
\r
303 out->radius2 = in->radius2;
\r
305 /* translate planes */
\r
306 for( i = 0; i < in->numPlanes; i++ )
\r
308 out->planes[ i ][ 0 ] = DotProduct( in->planes[ i ], axis[ 0 ] );
\r
309 out->planes[ i ][ 1 ] = DotProduct( in->planes[ i ], axis[ 1 ] );
\r
310 out->planes[ i ][ 2 ] = DotProduct( in->planes[ i ], axis[ 2 ] );
\r
311 out->planes[ i ][ 3 ] = in->planes[ i ][ 3 ] - DotProduct( out->planes[ i ], origin );
\r
314 /* translate texture matrix */
\r
315 for( i = 0; i < 2; i++ )
\r
317 out->texMat[ i ][ 0 ] = DotProduct( in->texMat[ i ], axis[ 0 ] );
\r
318 out->texMat[ i ][ 1 ] = DotProduct( in->texMat[ i ], axis[ 1 ] );
\r
319 out->texMat[ i ][ 2 ] = DotProduct( in->texMat[ i ], axis[ 2 ] );
\r
320 out->texMat[ i ][ 3 ] = in->texMat[ i ][ 3 ] + DotProduct( out->texMat[ i ], origin );
\r
327 MakeDecalProjector()
\r
328 creates a new decal projector from a triangle
\r
331 static int MakeDecalProjector( shaderInfo_t *si, vec4_t projection, float distance, int numVerts, bspDrawVert_t **dv )
\r
334 decalProjector_t *dp;
\r
339 if( numVerts != 3 && numVerts != 4 )
\r
343 if( numProjectors >= MAX_PROJECTORS )
\r
345 Sys_Printf( "WARNING: MAX_PROJECTORS (%d) exceeded, no more decal projectors available.\n", MAX_PROJECTORS );
\r
349 /* create a new projector */
\r
350 dp = &projectors[ numProjectors ];
\r
351 memset( dp, 0, sizeof( *dp ) );
\r
355 dp->numPlanes = numVerts + 2;
\r
357 /* make texture matrix */
\r
358 if( !MakeTextureMatrix( dp, projection, dv[ 0 ], dv[ 1 ], dv[ 2 ] ) )
\r
361 /* bound the projector */
\r
362 ClearBounds( dp->mins, dp->maxs );
\r
363 for( i = 0; i < numVerts; i++ )
\r
365 AddPointToBounds( dv[ i ]->xyz, dp->mins, dp->maxs );
\r
366 VectorMA( dv[ i ]->xyz, distance, projection, xyz );
\r
367 AddPointToBounds( xyz, dp->mins, dp->maxs );
\r
370 /* make bouding sphere */
\r
371 VectorAdd( dp->mins, dp->maxs, dp->center );
\r
372 VectorScale( dp->center, 0.5f, dp->center );
\r
373 VectorSubtract( dp->maxs, dp->center, xyz );
\r
374 dp->radius = VectorLength( xyz );
\r
375 dp->radius2 = dp->radius * dp->radius;
\r
377 /* make the front plane */
\r
378 if( !PlaneFromPoints( dp->planes[ 0 ], dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) )
\r
381 /* make the back plane */
\r
382 VectorSubtract( vec3_origin, dp->planes[ 0 ], dp->planes[ 1 ] );
\r
383 VectorMA( dv[ 0 ]->xyz, distance, projection, xyz );
\r
384 dp->planes[ 1 ][ 3 ] = DotProduct( xyz, dp->planes[ 1 ] );
\r
386 /* make the side planes */
\r
387 for( i = 0; i < numVerts; i++ )
\r
389 j = (i + 1) % numVerts;
\r
390 VectorMA( dv[ i ]->xyz, distance, projection, xyz );
\r
391 if( !PlaneFromPoints( dp->planes[ i + 2 ], dv[ j ]->xyz, dv[ i ]->xyz, xyz ) )
\r
397 return numProjectors - 1;
\r
404 finds all decal entities and creates decal projectors
\r
407 #define PLANAR_EPSILON 0.5f
\r
409 void ProcessDecals( void )
\r
411 int i, j, x, y, pw[ 5 ], r, iterations;
\r
413 vec4_t projection, plane;
\r
414 vec3_t origin, target, delta;
\r
417 mesh_t *mesh, *subdivided;
\r
418 bspDrawVert_t *dv[ 4 ];
\r
423 Sys_FPrintf( SYS_VRB, "--- ProcessDecals ---\n" );
\r
425 /* walk entity list */
\r
426 for( i = 0; i < numEntities; i++ )
\r
429 e = &entities[ i ];
\r
430 value = ValueForKey( e, "classname" );
\r
431 if( Q_stricmp( value, "_decal" ) )
\r
435 if( e->patches == NULL )
\r
437 Sys_Printf( "WARNING: Decal entity without any patch meshes, ignoring.\n" );
\r
438 e->epairs = NULL; /* fixme: leak! */
\r
443 value = ValueForKey( e, "target" );
\r
444 e2 = FindTargetEntity( value );
\r
449 Sys_Printf( "WARNING: Decal entity without a valid target, ignoring.\n" );
\r
453 /* walk entity patches */
\r
454 for( p = e->patches; p != NULL; p = e->patches )
\r
456 /* setup projector */
\r
457 if( VectorCompare( e->origin, vec3_origin ) )
\r
459 VectorAdd( p->eMins, p->eMaxs, origin );
\r
460 VectorScale( origin, 0.5f, origin );
\r
463 VectorCopy( e->origin, origin );
\r
465 VectorCopy( e2->origin, target );
\r
466 VectorSubtract( target, origin, delta );
\r
468 /* setup projection plane */
\r
469 distance = VectorNormalize( delta, projection );
\r
470 projection[ 3 ] = DotProduct( origin, projection );
\r
472 /* create projectors */
\r
473 if( distance > 0.125f )
\r
475 /* tesselate the patch */
\r
476 iterations = IterationsForCurve( p->longestCurve, patchSubdivisions );
\r
477 subdivided = SubdivideMesh2( p->mesh, iterations );
\r
479 /* fit it to the curve and remove colinear verts on rows/columns */
\r
480 PutMeshOnCurve( *subdivided );
\r
481 mesh = RemoveLinearMeshColumnsRows( subdivided );
\r
482 FreeMesh( subdivided );
\r
484 /* offset by projector origin */
\r
485 for( j = 0; j < (mesh->width * mesh->height); j++ )
\r
486 VectorAdd( mesh->verts[ j ].xyz, e->origin, mesh->verts[ j ].xyz );
\r
488 /* iterate through the mesh quads */
\r
489 for( y = 0; y < (mesh->height - 1); y++ )
\r
491 for( x = 0; x < (mesh->width - 1); x++ )
\r
494 pw[ 0 ] = x + (y * mesh->width);
\r
495 pw[ 1 ] = x + ((y + 1) * mesh->width);
\r
496 pw[ 2 ] = x + 1 + ((y + 1) * mesh->width);
\r
497 pw[ 3 ] = x + 1 + (y * mesh->width);
\r
498 pw[ 4 ] = x + (y * mesh->width); /* same as pw[ 0 ] */
\r
503 /* get drawverts */
\r
504 dv[ 0 ] = &mesh->verts[ pw[ r + 0 ] ];
\r
505 dv[ 1 ] = &mesh->verts[ pw[ r + 1 ] ];
\r
506 dv[ 2 ] = &mesh->verts[ pw[ r + 2 ] ];
\r
507 dv[ 3 ] = &mesh->verts[ pw[ r + 3 ] ];
\r
509 /* planar? (nuking this optimization as it doesn't work on non-rectangular quads) */
\r
510 plane[ 0 ] = 0.0f; /* stupid msvc */
\r
511 if( 0 && PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) &&
\r
512 fabs( DotProduct( dv[ 1 ]->xyz, plane ) - plane[ 3 ] ) <= PLANAR_EPSILON )
\r
514 /* make a quad projector */
\r
515 MakeDecalProjector( p->shaderInfo, projection, distance, 4, dv );
\r
519 /* make first triangle */
\r
520 MakeDecalProjector( p->shaderInfo, projection, distance, 3, dv );
\r
522 /* make second triangle */
\r
525 MakeDecalProjector( p->shaderInfo, projection, distance, 3, dv );
\r
534 /* remove patch from entity (fixme: leak!) */
\r
535 e->patches = p->next;
\r
537 /* push patch to worldspawn (enable this to debug projectors) */
\r
539 p->next = entities[ 0 ].patches;
\r
540 entities[ 0 ].patches = p;
\r
545 /* emit some stats */
\r
546 Sys_FPrintf( SYS_VRB, "%9d decal projectors\n", numProjectors );
\r
552 ProjectDecalOntoWinding()
\r
553 projects a decal onto a winding
\r
556 static void ProjectDecalOntoWinding( decalProjector_t *dp, mapDrawSurface_t *ds, winding_t *w )
\r
559 float d, d2, alpha;
\r
560 winding_t *front, *back;
\r
561 mapDrawSurface_t *ds2;
\r
567 if( w->numpoints < 3 )
\r
573 /* offset by entity origin */
\r
574 for( i = 0; i < w->numpoints; i++ )
\r
575 VectorAdd( w->p[ i ], entityOrigin, w->p[ i ] );
\r
577 /* make a plane from the winding */
\r
578 if( !PlaneFromPoints( plane, w->p[ 0 ], w->p[ 1 ], w->p[ 2 ] ) )
\r
584 /* backface check */
\r
585 d = DotProduct( dp->planes[ 0 ], plane );
\r
592 /* walk list of planes */
\r
593 for( i = 0; i < dp->numPlanes; i++ )
\r
595 /* chop winding by the plane */
\r
596 ClipWindingEpsilon( w, dp->planes[ i ], dp->planes[ i ][ 3 ], 0.0625f, &front, &back );
\r
599 /* lose the front fragment */
\r
600 if( front != NULL )
\r
601 FreeWinding( front );
\r
603 /* if nothing left in back, then bail */
\r
607 /* reset winding */
\r
611 /* nothing left? */
\r
612 if( w == NULL || w->numpoints < 3 )
\r
615 /* add to counts */
\r
616 numDecalSurfaces++;
\r
618 /* make a new surface */
\r
619 ds2 = AllocDrawSurface( SURFACE_DECAL );
\r
622 ds2->entityNum = ds->entityNum;
\r
623 ds2->castShadows = ds->castShadows;
\r
624 ds2->recvShadows = ds->recvShadows;
\r
625 ds2->shaderInfo = dp->si;
\r
626 ds2->fogNum = ds->fogNum; /* why was this -1? */
\r
627 ds2->lightmapScale = ds->lightmapScale;
\r
628 ds2->numVerts = w->numpoints;
\r
629 ds2->verts = safe_malloc( ds2->numVerts * sizeof( *ds2->verts ) );
\r
630 memset( ds2->verts, 0, ds2->numVerts * sizeof( *ds2->verts ) );
\r
633 for( i = 0; i < ds2->numVerts; i++ )
\r
636 dv = &ds2->verts[ i ];
\r
639 d = DotProduct( w->p[ i ], dp->planes[ 0 ] ) - dp->planes[ 0 ][ 3 ];
\r
640 d2 = DotProduct( w->p[ i ], dp->planes[ 1 ] ) - dp->planes[ 1 ][ 3 ];
\r
641 alpha = 255.0f * d2 / (d + d2);
\r
644 else if( alpha < 0 )
\r
648 VectorSubtract( w->p[ i ], entityOrigin, dv->xyz );
\r
649 VectorCopy( plane, dv->normal );
\r
650 dv->st[ 0 ] = DotProduct( dv->xyz, dp->texMat[ 0 ] ) + dp->texMat[ 0 ][ 3 ];
\r
651 dv->st[ 1 ] = DotProduct( dv->xyz, dp->texMat[ 1 ] ) + dp->texMat[ 1 ][ 3 ];
\r
654 for( j = 0; j < MAX_LIGHTMAPS; j++ )
\r
656 dv->color[ j ][ 0 ] = 255;
\r
657 dv->color[ j ][ 1 ] = 255;
\r
658 dv->color[ j ][ 2 ] = 255;
\r
659 dv->color[ j ][ 3 ] = alpha;
\r
663 /* ydnar: finish the surface */
\r
664 FinishSurface( ds2 );
\r
670 ProjectDecalOntoFace()
\r
671 projects a decal onto a brushface surface
\r
674 static void ProjectDecalOntoFace( decalProjector_t *dp, mapDrawSurface_t *ds )
\r
682 if( ds->sideRef == NULL || ds->sideRef->side == NULL )
\r
685 /* backface check */
\r
688 VectorCopy( mapplanes[ ds->planeNum ].normal, plane );
\r
689 plane[ 3 ] = mapplanes[ ds->planeNum ].dist + DotProduct( plane, entityOrigin );
\r
690 d = DotProduct( dp->planes[ 0 ], plane );
\r
695 /* generate decal */
\r
696 w = WindingFromDrawSurf( ds );
\r
697 ProjectDecalOntoWinding( dp, ds, w );
\r
703 ProjectDecalOntoPatch()
\r
704 projects a decal onto a patch surface
\r
707 static void ProjectDecalOntoPatch( decalProjector_t *dp, mapDrawSurface_t *ds )
\r
709 int x, y, pw[ 5 ], r, iterations;
\r
712 mesh_t src, *mesh, *subdivided;
\r
716 /* backface check */
\r
719 VectorCopy( mapplanes[ ds->planeNum ].normal, plane );
\r
720 plane[ 3 ] = mapplanes[ ds->planeNum ].dist + DotProduct( plane, entityOrigin );
\r
721 d = DotProduct( dp->planes[ 0 ], plane );
\r
726 /* tesselate the patch */
\r
727 src.width = ds->patchWidth;
\r
728 src.height = ds->patchHeight;
\r
729 src.verts = ds->verts;
\r
730 iterations = IterationsForCurve( ds->longestCurve, patchSubdivisions );
\r
731 subdivided = SubdivideMesh2( src, iterations );
\r
733 /* fit it to the curve and remove colinear verts on rows/columns */
\r
734 PutMeshOnCurve( *subdivided );
\r
735 mesh = RemoveLinearMeshColumnsRows( subdivided );
\r
736 FreeMesh( subdivided );
\r
738 /* iterate through the mesh quads */
\r
739 for( y = 0; y < (mesh->height - 1); y++ )
\r
741 for( x = 0; x < (mesh->width - 1); x++ )
\r
744 pw[ 0 ] = x + (y * mesh->width);
\r
745 pw[ 1 ] = x + ((y + 1) * mesh->width);
\r
746 pw[ 2 ] = x + 1 + ((y + 1) * mesh->width);
\r
747 pw[ 3 ] = x + 1 + (y * mesh->width);
\r
748 pw[ 4 ] = x + (y * mesh->width); /* same as pw[ 0 ] */
\r
753 /* generate decal for first triangle */
\r
754 w = AllocWinding( 3 );
\r
756 VectorCopy( mesh->verts[ pw[ r + 0 ] ].xyz, w->p[ 0 ] );
\r
757 VectorCopy( mesh->verts[ pw[ r + 1 ] ].xyz, w->p[ 1 ] );
\r
758 VectorCopy( mesh->verts[ pw[ r + 2 ] ].xyz, w->p[ 2 ] );
\r
759 ProjectDecalOntoWinding( dp, ds, w );
\r
761 /* generate decal for second triangle */
\r
762 w = AllocWinding( 3 );
\r
764 VectorCopy( mesh->verts[ pw[ r + 0 ] ].xyz, w->p[ 0 ] );
\r
765 VectorCopy( mesh->verts[ pw[ r + 2 ] ].xyz, w->p[ 1 ] );
\r
766 VectorCopy( mesh->verts[ pw[ r + 3 ] ].xyz, w->p[ 2 ] );
\r
767 ProjectDecalOntoWinding( dp, ds, w );
\r
778 ProjectDecalOntoTriangles()
\r
779 projects a decal onto a triangle surface
\r
782 static void ProjectDecalOntoTriangles( decalProjector_t *dp, mapDrawSurface_t *ds )
\r
790 /* triangle surfaces without shaders don't get marks by default */
\r
791 if( (ds->type == SURFACE_TRIANGLES || ds->type == SURFACE_FORCED_META) &&
\r
792 ds->shaderInfo->shaderText == NULL )
\r
795 /* backface check */
\r
798 VectorCopy( mapplanes[ ds->planeNum ].normal, plane );
\r
799 plane[ 3 ] = mapplanes[ ds->planeNum ].dist + DotProduct( plane, entityOrigin );
\r
800 d = DotProduct( dp->planes[ 0 ], plane );
\r
805 /* iterate through triangles */
\r
806 for( i = 0; i < ds->numIndexes; i += 3 )
\r
808 /* generate decal */
\r
809 w = AllocWinding( 3 );
\r
811 VectorCopy( ds->verts[ ds->indexes[ i ] ].xyz, w->p[ 0 ] );
\r
812 VectorCopy( ds->verts[ ds->indexes[ i + 1 ] ].xyz, w->p[ 1 ] );
\r
813 VectorCopy( ds->verts[ ds->indexes[ i + 2 ] ].xyz, w->p[ 2 ] );
\r
814 ProjectDecalOntoWinding( dp, ds, w );
\r
822 projects decals onto world surfaces
\r
825 void MakeEntityDecals( entity_t *e )
\r
827 int i, j, k, f, fOld, start;
\r
828 decalProjector_t dp;
\r
829 mapDrawSurface_t *ds;
\r
830 vec3_t identityAxis[ 3 ] = { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } };
\r
834 Sys_FPrintf( SYS_VRB, "--- MakeEntityDecals ---\n" );
\r
836 /* set entity origin */
\r
837 VectorCopy( e->origin, entityOrigin );
\r
839 /* transform projector instead of geometry */
\r
840 VectorClear( entityOrigin );
\r
842 /* init pacifier */
\r
844 start = I_FloatTime();
\r
846 /* walk the list of decal projectors */
\r
847 for( i = 0; i < numProjectors; i++ )
\r
849 /* print pacifier */
\r
850 f = 10 * i / numProjectors;
\r
854 Sys_FPrintf( SYS_VRB, "%d...", f );
\r
857 /* get projector */
\r
858 TransformDecalProjector( &projectors[ i ], identityAxis, e->origin, &dp );
\r
860 /* walk the list of surfaces in the entity */
\r
861 for( j = e->firstDrawSurf; j < numMapDrawSurfs; j++ )
\r
864 ds = &mapDrawSurfs[ j ];
\r
865 if( ds->numVerts <= 0 )
\r
868 /* ignore autosprite or nomarks */
\r
869 if( ds->shaderInfo->autosprite || (ds->shaderInfo->compileFlags & C_NOMARKS) )
\r
873 for( k = 0; k < 3; k++ )
\r
874 if( ds->mins[ k ] >= (dp.center[ k ] + dp.radius) ||
\r
875 ds->maxs[ k ] <= (dp.center[ k ] - dp.radius) )
\r
880 /* switch on type */
\r
884 ProjectDecalOntoFace( &dp, ds );
\r
887 case SURFACE_PATCH:
\r
888 ProjectDecalOntoPatch( &dp, ds );
\r
891 case SURFACE_TRIANGLES:
\r
892 case SURFACE_FORCED_META:
\r
894 ProjectDecalOntoTriangles( &dp, ds );
\r
904 Sys_FPrintf( SYS_VRB, " (%d)\n", (int) (I_FloatTime() - start) );
\r
906 /* emit some stats */
\r
907 Sys_FPrintf( SYS_VRB, "%9d decal surfaces\n", numDecalSurfaces );
\r