1 /* -------------------------------------------------------------------------------
3 Copyright (C) 1999-2007 id Software, Inc. and contributors.
4 For a list of contributors, see the accompanying CONTRIBUTORS file.
6 This file is part of GtkRadiant.
8 GtkRadiant is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 GtkRadiant is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GtkRadiant; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 ----------------------------------------------------------------------------------
24 This code has been altered significantly from its original form, to support
25 several games based on the Quake III Arena engine, in the form of "Q3Map2."
27 ------------------------------------------------------------------------------- */
41 #define MAX_PROJECTORS 1024
43 typedef struct decalProjector_s
48 float radius, radius2;
49 int numPlanes; /* either 5 or 6, for quad or triangle projectors */
55 static int numProjectors = 0;
56 static decalProjector_t projectors[ MAX_PROJECTORS ];
58 static int numDecalSurfaces = 0;
60 static vec3_t entityOrigin;
66 normalizes a vector, returns the length, operates using doubles
69 typedef double dvec_t;
70 typedef dvec_t dvec3_t[ 3 ];
72 dvec_t DVectorNormalize( dvec3_t in, dvec3_t out )
77 len = (dvec_t) sqrt( in[ 0 ] * in[ 0 ] + in[ 1 ] * in[ 1 ] + in[ 2 ] * in[ 2 ] );
85 out[ 0 ] = in[ 0 ] * ilen;
86 out[ 1 ] = in[ 1 ] * ilen;
87 out[ 2 ] = in[ 2 ] * ilen;
96 generates a texture projection matrix for a triangle
97 returns qfalse if a texture matrix cannot be created
100 #define Vector2Subtract(a,b,c) ((c)[ 0 ] = (a)[ 0 ] - (b)[ 0 ], (c)[ 1 ] = (a)[ 1 ] - (b)[ 1 ])
102 static qboolean MakeTextureMatrix( decalProjector_t *dp, vec4_t projection, bspDrawVert_t *a, bspDrawVert_t *b, bspDrawVert_t *c )
108 dvec3_t vecs[ 3 ], axis[ 3 ], lengths;
111 /* project triangle onto plane of projection */
112 d = DotProduct( a->xyz, projection ) - projection[ 3 ];
113 VectorMA( a->xyz, -d, projection, pa );
114 d = DotProduct( b->xyz, projection ) - projection[ 3 ];
115 VectorMA( b->xyz, -d, projection, pb );
116 d = DotProduct( c->xyz, projection ) - projection[ 3 ];
117 VectorMA( c->xyz, -d, projection, pc );
124 /* calculate barycentric basis for the triangle */
125 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 ]);
126 if( fabs( bb ) < 0.00000001 )
129 /* calculate texture origin */
133 bary[ 0 ] = ((b->st[ 0 ] - s) * (c->st[ 1 ] - t) - (c->st[ 0 ] - s) * (b->st[ 1 ] - t)) / bb;
134 bary[ 1 ] = ((c->st[ 0 ] - s) * (a->st[ 1 ] - t) - (a->st[ 0 ] - s) * (c->st[ 1 ] - t)) / bb;
135 bary[ 2 ] = ((a->st[ 0 ] - s) * (b->st[ 1 ] - t) - (b->st[ 0 ] - s) * (a->st[ 1 ] - t)) / bb;
137 origin[ 0 ] = bary[ 0 ] * pa[ 0 ] + bary[ 1 ] * pb[ 0 ] + bary[ 2 ] * pc[ 0 ];
138 origin[ 1 ] = bary[ 0 ] * pa[ 1 ] + bary[ 1 ] * pb[ 1 ] + bary[ 2 ] * pc[ 1 ];
139 origin[ 2 ] = bary[ 0 ] * pa[ 2 ] + bary[ 1 ] * pb[ 2 ] + bary[ 2 ] * pc[ 2 ];
142 /* calculate s vector */
143 s = a->st[ 0 ] + 1.0;
144 t = a->st[ 1 ] + 0.0;
145 bary[ 0 ] = ((b->st[ 0 ] - s) * (c->st[ 1 ] - t) - (c->st[ 0 ] - s) * (b->st[ 1 ] - t)) / bb;
146 bary[ 1 ] = ((c->st[ 0 ] - s) * (a->st[ 1 ] - t) - (a->st[ 0 ] - s) * (c->st[ 1 ] - t)) / bb;
147 bary[ 2 ] = ((a->st[ 0 ] - s) * (b->st[ 1 ] - t) - (b->st[ 0 ] - s) * (a->st[ 1 ] - t)) / bb;
149 xyz[ 0 ] = bary[ 0 ] * pa[ 0 ] + bary[ 1 ] * pb[ 0 ] + bary[ 2 ] * pc[ 0 ];
150 xyz[ 1 ] = bary[ 0 ] * pa[ 1 ] + bary[ 1 ] * pb[ 1 ] + bary[ 2 ] * pc[ 1 ];
151 xyz[ 2 ] = bary[ 0 ] * pa[ 2 ] + bary[ 1 ] * pb[ 2 ] + bary[ 2 ] * pc[ 2 ];
153 //% VectorSubtract( xyz, origin, vecs[ 0 ] );
154 VectorSubtract( xyz, pa, vecs[ 0 ] );
156 /* calculate t vector */
157 s = a->st[ 0 ] + 0.0;
158 t = a->st[ 1 ] + 1.0;
159 bary[ 0 ] = ((b->st[ 0 ] - s) * (c->st[ 1 ] - t) - (c->st[ 0 ] - s) * (b->st[ 1 ] - t)) / bb;
160 bary[ 1 ] = ((c->st[ 0 ] - s) * (a->st[ 1 ] - t) - (a->st[ 0 ] - s) * (c->st[ 1 ] - t)) / bb;
161 bary[ 2 ] = ((a->st[ 0 ] - s) * (b->st[ 1 ] - t) - (b->st[ 0 ] - s) * (a->st[ 1 ] - t)) / bb;
163 xyz[ 0 ] = bary[ 0 ] * pa[ 0 ] + bary[ 1 ] * pb[ 0 ] + bary[ 2 ] * pc[ 0 ];
164 xyz[ 1 ] = bary[ 0 ] * pa[ 1 ] + bary[ 1 ] * pb[ 1 ] + bary[ 2 ] * pc[ 1 ];
165 xyz[ 2 ] = bary[ 0 ] * pa[ 2 ] + bary[ 1 ] * pb[ 2 ] + bary[ 2 ] * pc[ 2 ];
167 //% VectorSubtract( xyz, origin, vecs[ 1 ] );
168 VectorSubtract( xyz, pa, vecs[ 1 ] );
170 /* calcuate r vector */
171 VectorScale( projection, -1.0, vecs[ 2 ] );
173 /* calculate transform axis */
174 for( i = 0; i < 3; i++ )
175 lengths[ i ] = DVectorNormalize( vecs[ i ], axis[ i ] );
176 for( i = 0; i < 2; i++ )
177 for( j = 0; j < 3; j++ )
178 dp->texMat[ i ][ j ] = lengths[ i ] > 0.0 ? (axis[ i ][ j ] / lengths[ i ]) : 0.0;
179 //% dp->texMat[ i ][ j ] = fabs( vecs[ i ][ j ] ) > 0.0 ? (1.0 / vecs[ i ][ j ]) : 0.0;
180 //% dp->texMat[ i ][ j ] = axis[ i ][ j ] > 0.0 ? (1.0 / axis[ i ][ j ]) : 0.0;
182 /* calculalate translation component */
183 dp->texMat[ 0 ][ 3 ] = a->st[ 0 ] - DotProduct( a->xyz, dp->texMat[ 0 ] );
184 dp->texMat[ 1 ][ 3 ] = a->st[ 1 ] - DotProduct( a->xyz, dp->texMat[ 1 ] );
189 dvec3_t origin, deltas[ 3 ];
190 double texDeltas[ 3 ][ 2 ];
191 double delta, texDelta;
196 /* calculate deltas */
197 VectorSubtract( pa, pb, deltas[ 0 ] );
198 VectorSubtract( pa, pc, deltas[ 1 ] );
199 VectorSubtract( pb, pc, deltas[ 2 ] );
200 Vector2Subtract( a->st, b->st, texDeltas[ 0 ] );
201 Vector2Subtract( a->st, c->st, texDeltas[ 1 ] );
202 Vector2Subtract( b->st, c->st, texDeltas[ 2 ] );
205 for( i = 0; i < 2; i++ )
208 for( j = 0; j < 3; j++ )
215 for( k = 0; k < 3; k++ )
217 if( fabs( deltas[ k ][ j ] ) > delta &&
218 fabs( texDeltas[ k ][ i ] ) > texDelta )
220 delta = deltas[ k ][ j ];
221 texDelta = texDeltas[ k ][ i ];
225 /* set texture matrix component */
226 if( fabs( delta ) > 0.0 )
227 dp->texMat[ i ][ j ] = texDelta / delta;
229 dp->texMat[ i ][ j ] = 0.0;
232 /* set translation component */
233 dp->texMat[ i ][ 3 ] = a->st[ i ] - DotProduct( pa, dp->texMat[ i ] );
240 Sys_Printf( "Mat: [ %f %f %f %f ] [ %f %f %f %f ] Theta: %f (%f)\n",
241 dp->texMat[ 0 ][ 0 ], dp->texMat[ 0 ][ 1 ], dp->texMat[ 0 ][ 2 ], dp->texMat[ 0 ][ 3 ],
242 dp->texMat[ 1 ][ 0 ], dp->texMat[ 1 ][ 1 ], dp->texMat[ 1 ][ 2 ], dp->texMat[ 1 ][ 3 ],
243 RAD2DEG( acos( DotProduct( dp->texMat[ 0 ], dp->texMat[ 1 ] ) ) ),
244 RAD2DEG( acos( DotProduct( axis[ 0 ], axis[ 1 ] ) ) ) );
246 Sys_Printf( "XYZ: %f %f %f ST: %f %f ST(t): %f %f\n",
247 a->xyz[ 0 ], a->xyz[ 1 ], a->xyz[ 2 ],
248 a->st[ 0 ], a->st[ 1 ],
249 DotProduct( a->xyz, dp->texMat[ 0 ] ) + dp->texMat[ 0 ][ 3 ], DotProduct( a->xyz, dp->texMat[ 1 ] ) + dp->texMat[ 1 ][ 3 ] );
252 /* test texture matrix */
253 s = DotProduct( a->xyz, dp->texMat[ 0 ] ) + dp->texMat[ 0 ][ 3 ];
254 t = DotProduct( a->xyz, dp->texMat[ 1 ] ) + dp->texMat[ 1 ][ 3 ];
255 if( fabs( s - a->st[ 0 ] ) > 0.01 || fabs( t - a->st[ 1 ] ) > 0.01 )
257 Sys_Printf( "Bad texture matrix! (A) (%f, %f) != (%f, %f)\n",
258 s, t, a->st[ 0 ], a->st[ 1 ] );
261 s = DotProduct( b->xyz, dp->texMat[ 0 ] ) + dp->texMat[ 0 ][ 3 ];
262 t = DotProduct( b->xyz, dp->texMat[ 1 ] ) + dp->texMat[ 1 ][ 3 ];
263 if( fabs( s - b->st[ 0 ] ) > 0.01 || fabs( t - b->st[ 1 ] ) > 0.01 )
265 Sys_Printf( "Bad texture matrix! (B) (%f, %f) != (%f, %f)\n",
266 s, t, b->st[ 0 ], b->st[ 1 ] );
269 s = DotProduct( c->xyz, dp->texMat[ 0 ] ) + dp->texMat[ 0 ][ 3 ];
270 t = DotProduct( c->xyz, dp->texMat[ 1 ] ) + dp->texMat[ 1 ][ 3 ];
271 if( fabs( s - c->st[ 0 ] ) > 0.01 || fabs( t - c->st[ 1 ] ) > 0.01 )
273 Sys_Printf( "Bad texture matrix! (C) (%f, %f) != (%f, %f)\n",
274 s, t, c->st[ 0 ], c->st[ 1 ] );
285 TransformDecalProjector()
286 transforms a decal projector
287 note: non-normalized axes will screw up the plane transform
290 static void TransformDecalProjector( decalProjector_t *in, vec3_t axis[ 3 ], vec3_t origin, decalProjector_t *out )
295 /* copy misc stuff */
297 out->numPlanes = in->numPlanes;
299 /* translate bounding box and sphere (note: rotated projector bounding box will be invalid!) */
300 VectorSubtract( in->mins, origin, out->mins );
301 VectorSubtract( in->maxs, origin, out->maxs );
302 VectorSubtract( in->center, origin, out->center );
303 out->radius = in->radius;
304 out->radius2 = in->radius2;
306 /* translate planes */
307 for( i = 0; i < in->numPlanes; i++ )
309 out->planes[ i ][ 0 ] = DotProduct( in->planes[ i ], axis[ 0 ] );
310 out->planes[ i ][ 1 ] = DotProduct( in->planes[ i ], axis[ 1 ] );
311 out->planes[ i ][ 2 ] = DotProduct( in->planes[ i ], axis[ 2 ] );
312 out->planes[ i ][ 3 ] = in->planes[ i ][ 3 ] - DotProduct( out->planes[ i ], origin );
315 /* translate texture matrix */
316 for( i = 0; i < 2; i++ )
318 out->texMat[ i ][ 0 ] = DotProduct( in->texMat[ i ], axis[ 0 ] );
319 out->texMat[ i ][ 1 ] = DotProduct( in->texMat[ i ], axis[ 1 ] );
320 out->texMat[ i ][ 2 ] = DotProduct( in->texMat[ i ], axis[ 2 ] );
321 out->texMat[ i ][ 3 ] = in->texMat[ i ][ 3 ] + DotProduct( out->texMat[ i ], origin );
329 creates a new decal projector from a triangle
332 static int MakeDecalProjector( shaderInfo_t *si, vec4_t projection, float distance, int numVerts, bspDrawVert_t **dv )
335 decalProjector_t *dp;
340 if( numVerts != 3 && numVerts != 4 )
344 if( numProjectors >= MAX_PROJECTORS )
346 Sys_Printf( "WARNING: MAX_PROJECTORS (%d) exceeded, no more decal projectors available.\n", MAX_PROJECTORS );
350 /* create a new projector */
351 dp = &projectors[ numProjectors ];
352 memset( dp, 0, sizeof( *dp ) );
356 dp->numPlanes = numVerts + 2;
358 /* make texture matrix */
359 if( !MakeTextureMatrix( dp, projection, dv[ 0 ], dv[ 1 ], dv[ 2 ] ) )
362 /* bound the projector */
363 ClearBounds( dp->mins, dp->maxs );
364 for( i = 0; i < numVerts; i++ )
366 AddPointToBounds( dv[ i ]->xyz, dp->mins, dp->maxs );
367 VectorMA( dv[ i ]->xyz, distance, projection, xyz );
368 AddPointToBounds( xyz, dp->mins, dp->maxs );
371 /* make bouding sphere */
372 VectorAdd( dp->mins, dp->maxs, dp->center );
373 VectorScale( dp->center, 0.5f, dp->center );
374 VectorSubtract( dp->maxs, dp->center, xyz );
375 dp->radius = VectorLength( xyz );
376 dp->radius2 = dp->radius * dp->radius;
378 /* make the front plane */
379 if( !PlaneFromPoints( dp->planes[ 0 ], dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) )
382 /* make the back plane */
383 VectorSubtract( vec3_origin, dp->planes[ 0 ], dp->planes[ 1 ] );
384 VectorMA( dv[ 0 ]->xyz, distance, projection, xyz );
385 dp->planes[ 1 ][ 3 ] = DotProduct( xyz, dp->planes[ 1 ] );
387 /* make the side planes */
388 for( i = 0; i < numVerts; i++ )
390 j = (i + 1) % numVerts;
391 VectorMA( dv[ i ]->xyz, distance, projection, xyz );
392 if( !PlaneFromPoints( dp->planes[ i + 2 ], dv[ j ]->xyz, dv[ i ]->xyz, xyz ) )
398 return numProjectors - 1;
405 finds all decal entities and creates decal projectors
408 #define PLANAR_EPSILON 0.5f
410 void ProcessDecals( void )
412 int i, j, x, y, pw[ 5 ], r, iterations;
414 vec4_t projection, plane;
415 vec3_t origin, target, delta;
418 mesh_t *mesh, *subdivided;
419 bspDrawVert_t *dv[ 4 ];
424 Sys_FPrintf( SYS_VRB, "--- ProcessDecals ---\n" );
426 /* walk entity list */
427 for( i = 0; i < numEntities; i++ )
431 value = ValueForKey( e, "classname" );
432 if( Q_stricmp( value, "_decal" ) )
436 if( e->patches == NULL )
438 Sys_Printf( "WARNING: Decal entity without any patch meshes, ignoring.\n" );
439 e->epairs = NULL; /* fixme: leak! */
444 value = ValueForKey( e, "target" );
445 e2 = FindTargetEntity( value );
450 Sys_Printf( "WARNING: Decal entity without a valid target, ignoring.\n" );
454 /* walk entity patches */
455 for( p = e->patches; p != NULL; p = e->patches )
457 /* setup projector */
458 if( VectorCompare( e->origin, vec3_origin ) )
460 VectorAdd( p->eMins, p->eMaxs, origin );
461 VectorScale( origin, 0.5f, origin );
464 VectorCopy( e->origin, origin );
466 VectorCopy( e2->origin, target );
467 VectorSubtract( target, origin, delta );
469 /* setup projection plane */
470 distance = VectorNormalize( delta, projection );
471 projection[ 3 ] = DotProduct( origin, projection );
473 /* create projectors */
474 if( distance > 0.125f )
476 /* tesselate the patch */
477 iterations = IterationsForCurve( p->longestCurve, patchSubdivisions );
478 subdivided = SubdivideMesh2( p->mesh, iterations );
480 /* fit it to the curve and remove colinear verts on rows/columns */
481 PutMeshOnCurve( *subdivided );
482 mesh = RemoveLinearMeshColumnsRows( subdivided );
483 FreeMesh( subdivided );
485 /* offset by projector origin */
486 for( j = 0; j < (mesh->width * mesh->height); j++ )
487 VectorAdd( mesh->verts[ j ].xyz, e->origin, mesh->verts[ j ].xyz );
489 /* iterate through the mesh quads */
490 for( y = 0; y < (mesh->height - 1); y++ )
492 for( x = 0; x < (mesh->width - 1); x++ )
495 pw[ 0 ] = x + (y * mesh->width);
496 pw[ 1 ] = x + ((y + 1) * mesh->width);
497 pw[ 2 ] = x + 1 + ((y + 1) * mesh->width);
498 pw[ 3 ] = x + 1 + (y * mesh->width);
499 pw[ 4 ] = x + (y * mesh->width); /* same as pw[ 0 ] */
505 dv[ 0 ] = &mesh->verts[ pw[ r + 0 ] ];
506 dv[ 1 ] = &mesh->verts[ pw[ r + 1 ] ];
507 dv[ 2 ] = &mesh->verts[ pw[ r + 2 ] ];
508 dv[ 3 ] = &mesh->verts[ pw[ r + 3 ] ];
510 /* planar? (nuking this optimization as it doesn't work on non-rectangular quads) */
511 plane[ 0 ] = 0.0f; /* stupid msvc */
512 if( 0 && PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) &&
513 fabs( DotProduct( dv[ 1 ]->xyz, plane ) - plane[ 3 ] ) <= PLANAR_EPSILON )
515 /* make a quad projector */
516 MakeDecalProjector( p->shaderInfo, projection, distance, 4, dv );
520 /* make first triangle */
521 MakeDecalProjector( p->shaderInfo, projection, distance, 3, dv );
523 /* make second triangle */
526 MakeDecalProjector( p->shaderInfo, projection, distance, 3, dv );
535 /* remove patch from entity (fixme: leak!) */
536 e->patches = p->next;
538 /* push patch to worldspawn (enable this to debug projectors) */
540 p->next = entities[ 0 ].patches;
541 entities[ 0 ].patches = p;
546 /* emit some stats */
547 Sys_FPrintf( SYS_VRB, "%9d decal projectors\n", numProjectors );
553 ProjectDecalOntoWinding()
554 projects a decal onto a winding
557 static void ProjectDecalOntoWinding( decalProjector_t *dp, mapDrawSurface_t *ds, winding_t *w )
561 winding_t *front, *back;
562 mapDrawSurface_t *ds2;
568 if( w->numpoints < 3 )
574 /* offset by entity origin */
575 for( i = 0; i < w->numpoints; i++ )
576 VectorAdd( w->p[ i ], entityOrigin, w->p[ i ] );
578 /* make a plane from the winding */
579 if( !PlaneFromPoints( plane, w->p[ 0 ], w->p[ 1 ], w->p[ 2 ] ) )
586 d = DotProduct( dp->planes[ 0 ], plane );
593 /* walk list of planes */
594 for( i = 0; i < dp->numPlanes; i++ )
596 /* chop winding by the plane */
597 ClipWindingEpsilonStrict( w, dp->planes[ i ], dp->planes[ i ][ 3 ], 0.0625f, &front, &back ); /* strict, if identical plane we don't want to keep it */
600 /* lose the front fragment */
602 FreeWinding( front );
604 /* if nothing left in back, then bail */
613 if( w == NULL || w->numpoints < 3 )
619 /* make a new surface */
620 ds2 = AllocDrawSurface( SURFACE_DECAL );
623 ds2->entityNum = ds->entityNum;
624 ds2->castShadows = ds->castShadows;
625 ds2->recvShadows = ds->recvShadows;
626 ds2->shaderInfo = dp->si;
627 ds2->fogNum = ds->fogNum; /* why was this -1? */
628 ds2->lightmapScale = ds->lightmapScale;
629 ds2->shadeAngleDegrees = ds->shadeAngleDegrees;
630 ds2->numVerts = w->numpoints;
631 ds2->verts = safe_malloc( ds2->numVerts * sizeof( *ds2->verts ) );
632 memset( ds2->verts, 0, ds2->numVerts * sizeof( *ds2->verts ) );
635 for( i = 0; i < ds2->numVerts; i++ )
638 dv = &ds2->verts[ i ];
641 d = DotProduct( w->p[ i ], dp->planes[ 0 ] ) - dp->planes[ 0 ][ 3 ];
642 d2 = DotProduct( w->p[ i ], dp->planes[ 1 ] ) - dp->planes[ 1 ][ 3 ];
643 alpha = 255.0f * d2 / (d + d2);
650 VectorSubtract( w->p[ i ], entityOrigin, dv->xyz );
651 VectorCopy( plane, dv->normal );
652 dv->st[ 0 ] = DotProduct( dv->xyz, dp->texMat[ 0 ] ) + dp->texMat[ 0 ][ 3 ];
653 dv->st[ 1 ] = DotProduct( dv->xyz, dp->texMat[ 1 ] ) + dp->texMat[ 1 ][ 3 ];
656 for( j = 0; j < MAX_LIGHTMAPS; j++ )
658 dv->color[ j ][ 0 ] = 255;
659 dv->color[ j ][ 1 ] = 255;
660 dv->color[ j ][ 2 ] = 255;
661 dv->color[ j ][ 3 ] = alpha;
669 ProjectDecalOntoFace()
670 projects a decal onto a brushface surface
673 static void ProjectDecalOntoFace( decalProjector_t *dp, mapDrawSurface_t *ds )
681 if( ds->sideRef == NULL || ds->sideRef->side == NULL )
687 VectorCopy( mapplanes[ ds->planeNum ].normal, plane );
688 plane[ 3 ] = mapplanes[ ds->planeNum ].dist + DotProduct( plane, entityOrigin );
689 d = DotProduct( dp->planes[ 0 ], plane );
695 w = WindingFromDrawSurf( ds );
696 ProjectDecalOntoWinding( dp, ds, w );
702 ProjectDecalOntoPatch()
703 projects a decal onto a patch surface
706 static void ProjectDecalOntoPatch( decalProjector_t *dp, mapDrawSurface_t *ds )
708 int x, y, pw[ 5 ], r, iterations;
711 mesh_t src, *mesh, *subdivided;
718 VectorCopy( mapplanes[ ds->planeNum ].normal, plane );
719 plane[ 3 ] = mapplanes[ ds->planeNum ].dist + DotProduct( plane, entityOrigin );
720 d = DotProduct( dp->planes[ 0 ], plane );
725 /* tesselate the patch */
726 src.width = ds->patchWidth;
727 src.height = ds->patchHeight;
728 src.verts = ds->verts;
729 iterations = IterationsForCurve( ds->longestCurve, patchSubdivisions );
730 subdivided = SubdivideMesh2( src, iterations );
732 /* fit it to the curve and remove colinear verts on rows/columns */
733 PutMeshOnCurve( *subdivided );
734 mesh = RemoveLinearMeshColumnsRows( subdivided );
735 FreeMesh( subdivided );
737 /* iterate through the mesh quads */
738 for( y = 0; y < (mesh->height - 1); y++ )
740 for( x = 0; x < (mesh->width - 1); x++ )
743 pw[ 0 ] = x + (y * mesh->width);
744 pw[ 1 ] = x + ((y + 1) * mesh->width);
745 pw[ 2 ] = x + 1 + ((y + 1) * mesh->width);
746 pw[ 3 ] = x + 1 + (y * mesh->width);
747 pw[ 4 ] = x + (y * mesh->width); /* same as pw[ 0 ] */
752 /* generate decal for first triangle */
753 w = AllocWinding( 3 );
755 VectorCopy( mesh->verts[ pw[ r + 0 ] ].xyz, w->p[ 0 ] );
756 VectorCopy( mesh->verts[ pw[ r + 1 ] ].xyz, w->p[ 1 ] );
757 VectorCopy( mesh->verts[ pw[ r + 2 ] ].xyz, w->p[ 2 ] );
758 ProjectDecalOntoWinding( dp, ds, w );
760 /* generate decal for second triangle */
761 w = AllocWinding( 3 );
763 VectorCopy( mesh->verts[ pw[ r + 0 ] ].xyz, w->p[ 0 ] );
764 VectorCopy( mesh->verts[ pw[ r + 2 ] ].xyz, w->p[ 1 ] );
765 VectorCopy( mesh->verts[ pw[ r + 3 ] ].xyz, w->p[ 2 ] );
766 ProjectDecalOntoWinding( dp, ds, w );
777 ProjectDecalOntoTriangles()
778 projects a decal onto a triangle surface
781 static void ProjectDecalOntoTriangles( decalProjector_t *dp, mapDrawSurface_t *ds )
789 /* triangle surfaces without shaders don't get marks by default */
790 if( ds->type == SURFACE_TRIANGLES && ds->shaderInfo->shaderText == NULL )
796 VectorCopy( mapplanes[ ds->planeNum ].normal, plane );
797 plane[ 3 ] = mapplanes[ ds->planeNum ].dist + DotProduct( plane, entityOrigin );
798 d = DotProduct( dp->planes[ 0 ], plane );
803 /* iterate through triangles */
804 for( i = 0; i < ds->numIndexes; i += 3 )
807 w = AllocWinding( 3 );
809 VectorCopy( ds->verts[ ds->indexes[ i ] ].xyz, w->p[ 0 ] );
810 VectorCopy( ds->verts[ ds->indexes[ i + 1 ] ].xyz, w->p[ 1 ] );
811 VectorCopy( ds->verts[ ds->indexes[ i + 2 ] ].xyz, w->p[ 2 ] );
812 ProjectDecalOntoWinding( dp, ds, w );
820 projects decals onto world surfaces
823 void MakeEntityDecals( entity_t *e )
825 int i, j, k, f, fOld, start;
827 mapDrawSurface_t *ds;
828 vec3_t identityAxis[ 3 ] = { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } };
832 Sys_FPrintf( SYS_VRB, "--- MakeEntityDecals ---\n" );
834 /* set entity origin */
835 VectorCopy( e->origin, entityOrigin );
837 /* transform projector instead of geometry */
838 VectorClear( entityOrigin );
842 start = I_FloatTime();
844 /* walk the list of decal projectors */
845 for( i = 0; i < numProjectors; i++ )
848 f = 10 * i / numProjectors;
852 Sys_FPrintf( SYS_VRB, "%d...", f );
856 TransformDecalProjector( &projectors[ i ], identityAxis, e->origin, &dp );
858 /* walk the list of surfaces in the entity */
859 for( j = e->firstDrawSurf; j < numMapDrawSurfs; j++ )
862 ds = &mapDrawSurfs[ j ];
863 if( ds->numVerts <= 0 )
866 /* ignore autosprite or nomarks */
867 if( ds->shaderInfo->autosprite || (ds->shaderInfo->compileFlags & C_NOMARKS) )
871 for( k = 0; k < 3; k++ )
872 if( ds->mins[ k ] >= (dp.center[ k ] + dp.radius) ||
873 ds->maxs[ k ] <= (dp.center[ k ] - dp.radius) )
882 ProjectDecalOntoFace( &dp, ds );
886 ProjectDecalOntoPatch( &dp, ds );
889 case SURFACE_TRIANGLES:
890 case SURFACE_FORCED_META:
892 ProjectDecalOntoTriangles( &dp, ds );
902 Sys_FPrintf( SYS_VRB, " (%d)\n", (int) (I_FloatTime() - start) );
904 /* emit some stats */
905 Sys_FPrintf( SYS_VRB, "%9d decal surfaces\n", numDecalSurfaces );