-/*\r
-Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
-For a list of contributors, see the accompanying CONTRIBUTORS file.\r
-\r
-This file is part of GtkRadiant.\r
-\r
-GtkRadiant is free software; you can redistribute it and/or modify\r
-it under the terms of the GNU General Public License as published by\r
-the Free Software Foundation; either version 2 of the License, or\r
-(at your option) any later version.\r
-\r
-GtkRadiant is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-GNU General Public License for more details.\r
-\r
-You should have received a copy of the GNU General Public License\r
-along with GtkRadiant; if not, write to the Free Software\r
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\r
-\r
-----------------------------------------------------------------------------------\r
-\r
-This code has been altered significantly from its original form, to support\r
-several games based on the Quake III Arena engine, in the form of "Q3Map2."\r
-\r
-------------------------------------------------------------------------------- */\r
-\r
-\r
-\r
-/* marker */\r
-#define DECALS_C\r
-\r
-\r
-\r
-/* dependencies */\r
-#include "q3map2.h"\r
-\r
-\r
-\r
-#define MAX_PROJECTORS 1024\r
-\r
-typedef struct decalProjector_s\r
-{\r
- shaderInfo_t *si;\r
- vec3_t mins, maxs;\r
- vec3_t center;\r
- float radius, radius2;\r
- int numPlanes; /* either 5 or 6, for quad or triangle projectors */\r
- vec4_t planes[ 6 ];\r
- vec4_t texMat[ 2 ];\r
-}\r
-decalProjector_t;\r
-\r
-static int numProjectors = 0;\r
-static decalProjector_t projectors[ MAX_PROJECTORS ];\r
-\r
-static int numDecalSurfaces = 0;\r
-\r
-static vec3_t entityOrigin;\r
-\r
-\r
-\r
-/*\r
-DVectorNormalize()\r
-normalizes a vector, returns the length, operates using doubles\r
-*/\r
-\r
-typedef double dvec_t;\r
-typedef dvec_t dvec3_t[ 3 ];\r
-\r
-dvec_t DVectorNormalize( dvec3_t in, dvec3_t out )\r
-{\r
- dvec_t len, ilen;\r
- \r
- \r
- len = (dvec_t) sqrt( in[ 0 ] * in[ 0 ] + in[ 1 ] * in[ 1 ] + in[ 2 ] * in[ 2 ] );\r
- if( len == 0.0 )\r
- {\r
- VectorClear( out );\r
- return 0.0;\r
- }\r
- \r
- ilen = 1.0 / len;\r
- out[ 0 ] = in[ 0 ] * ilen;\r
- out[ 1 ] = in[ 1 ] * ilen;\r
- out[ 2 ] = in[ 2 ] * ilen;\r
- \r
- return len;\r
-}\r
-\r
-\r
-\r
-/*\r
-MakeTextureMatrix()\r
-generates a texture projection matrix for a triangle\r
-returns qfalse if a texture matrix cannot be created\r
-*/\r
-\r
-#define Vector2Subtract(a,b,c) ((c)[ 0 ] = (a)[ 0 ] - (b)[ 0 ], (c)[ 1 ] = (a)[ 1 ] - (b)[ 1 ])\r
-\r
-static qboolean MakeTextureMatrix( decalProjector_t *dp, vec4_t projection, bspDrawVert_t *a, bspDrawVert_t *b, bspDrawVert_t *c )\r
-{\r
- int i, j;\r
- double bb, s, t, d;\r
- dvec3_t pa, pb, pc;\r
- dvec3_t bary, xyz;\r
- dvec3_t vecs[ 3 ], axis[ 3 ], lengths;\r
- \r
- \r
- /* project triangle onto plane of projection */\r
- d = DotProduct( a->xyz, projection ) - projection[ 3 ];\r
- VectorMA( a->xyz, -d, projection, pa );\r
- d = DotProduct( b->xyz, projection ) - projection[ 3 ];\r
- VectorMA( b->xyz, -d, projection, pb );\r
- d = DotProduct( c->xyz, projection ) - projection[ 3 ];\r
- VectorMA( c->xyz, -d, projection, pc );\r
- \r
- /* two methods */\r
- #if 1\r
- {\r
- /* old code */\r
- \r
- /* calculate barycentric basis for the triangle */\r
- 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
- if( fabs( bb ) < 0.00000001 )\r
- return qfalse;\r
- \r
- /* calculate texture origin */\r
- #if 0\r
- s = 0.0;\r
- t = 0.0;\r
- bary[ 0 ] = ((b->st[ 0 ] - s) * (c->st[ 1 ] - t) - (c->st[ 0 ] - s) * (b->st[ 1 ] - t)) / bb;\r
- bary[ 1 ] = ((c->st[ 0 ] - s) * (a->st[ 1 ] - t) - (a->st[ 0 ] - s) * (c->st[ 1 ] - t)) / bb;\r
- bary[ 2 ] = ((a->st[ 0 ] - s) * (b->st[ 1 ] - t) - (b->st[ 0 ] - s) * (a->st[ 1 ] - t)) / bb;\r
- \r
- origin[ 0 ] = bary[ 0 ] * pa[ 0 ] + bary[ 1 ] * pb[ 0 ] + bary[ 2 ] * pc[ 0 ];\r
- origin[ 1 ] = bary[ 0 ] * pa[ 1 ] + bary[ 1 ] * pb[ 1 ] + bary[ 2 ] * pc[ 1 ];\r
- origin[ 2 ] = bary[ 0 ] * pa[ 2 ] + bary[ 1 ] * pb[ 2 ] + bary[ 2 ] * pc[ 2 ];\r
- #endif\r
- \r
- /* calculate s vector */\r
- s = a->st[ 0 ] + 1.0;\r
- t = a->st[ 1 ] + 0.0;\r
- bary[ 0 ] = ((b->st[ 0 ] - s) * (c->st[ 1 ] - t) - (c->st[ 0 ] - s) * (b->st[ 1 ] - t)) / bb;\r
- bary[ 1 ] = ((c->st[ 0 ] - s) * (a->st[ 1 ] - t) - (a->st[ 0 ] - s) * (c->st[ 1 ] - t)) / bb;\r
- bary[ 2 ] = ((a->st[ 0 ] - s) * (b->st[ 1 ] - t) - (b->st[ 0 ] - s) * (a->st[ 1 ] - t)) / bb;\r
- \r
- xyz[ 0 ] = bary[ 0 ] * pa[ 0 ] + bary[ 1 ] * pb[ 0 ] + bary[ 2 ] * pc[ 0 ];\r
- xyz[ 1 ] = bary[ 0 ] * pa[ 1 ] + bary[ 1 ] * pb[ 1 ] + bary[ 2 ] * pc[ 1 ];\r
- xyz[ 2 ] = bary[ 0 ] * pa[ 2 ] + bary[ 1 ] * pb[ 2 ] + bary[ 2 ] * pc[ 2 ];\r
- \r
- //% VectorSubtract( xyz, origin, vecs[ 0 ] );\r
- VectorSubtract( xyz, pa, vecs[ 0 ] );\r
- \r
- /* calculate t vector */\r
- s = a->st[ 0 ] + 0.0;\r
- t = a->st[ 1 ] + 1.0;\r
- bary[ 0 ] = ((b->st[ 0 ] - s) * (c->st[ 1 ] - t) - (c->st[ 0 ] - s) * (b->st[ 1 ] - t)) / bb;\r
- bary[ 1 ] = ((c->st[ 0 ] - s) * (a->st[ 1 ] - t) - (a->st[ 0 ] - s) * (c->st[ 1 ] - t)) / bb;\r
- bary[ 2 ] = ((a->st[ 0 ] - s) * (b->st[ 1 ] - t) - (b->st[ 0 ] - s) * (a->st[ 1 ] - t)) / bb;\r
- \r
- xyz[ 0 ] = bary[ 0 ] * pa[ 0 ] + bary[ 1 ] * pb[ 0 ] + bary[ 2 ] * pc[ 0 ];\r
- xyz[ 1 ] = bary[ 0 ] * pa[ 1 ] + bary[ 1 ] * pb[ 1 ] + bary[ 2 ] * pc[ 1 ];\r
- xyz[ 2 ] = bary[ 0 ] * pa[ 2 ] + bary[ 1 ] * pb[ 2 ] + bary[ 2 ] * pc[ 2 ];\r
- \r
- //% VectorSubtract( xyz, origin, vecs[ 1 ] );\r
- VectorSubtract( xyz, pa, vecs[ 1 ] );\r
- \r
- /* calcuate r vector */\r
- VectorScale( projection, -1.0, vecs[ 2 ] );\r
- \r
- /* calculate transform axis */\r
- for( i = 0; i < 3; i++ )\r
- lengths[ i ] = DVectorNormalize( vecs[ i ], axis[ i ] );\r
- for( i = 0; i < 2; i++ )\r
- for( j = 0; j < 3; j++ )\r
- dp->texMat[ i ][ j ] = lengths[ i ] > 0.0 ? (axis[ i ][ j ] / lengths[ i ]) : 0.0;\r
- //% dp->texMat[ i ][ j ] = fabs( vecs[ i ][ j ] ) > 0.0 ? (1.0 / vecs[ i ][ j ]) : 0.0;\r
- //% dp->texMat[ i ][ j ] = axis[ i ][ j ] > 0.0 ? (1.0 / axis[ i ][ j ]) : 0.0;\r
- \r
- /* calculalate translation component */\r
- dp->texMat[ 0 ][ 3 ] = a->st[ 0 ] - DotProduct( a->xyz, dp->texMat[ 0 ] );\r
- dp->texMat[ 1 ][ 3 ] = a->st[ 1 ] - DotProduct( a->xyz, dp->texMat[ 1 ] );\r
- }\r
- #else\r
- {\r
- int k;\r
- dvec3_t origin, deltas[ 3 ];\r
- double texDeltas[ 3 ][ 2 ];\r
- double delta, texDelta;\r
- \r
- \r
- /* new code */\r
- \r
- /* calculate deltas */\r
- VectorSubtract( pa, pb, deltas[ 0 ] );\r
- VectorSubtract( pa, pc, deltas[ 1 ] );\r
- VectorSubtract( pb, pc, deltas[ 2 ] );\r
- Vector2Subtract( a->st, b->st, texDeltas[ 0 ] );\r
- Vector2Subtract( a->st, c->st, texDeltas[ 1 ] );\r
- Vector2Subtract( b->st, c->st, texDeltas[ 2 ] );\r
- \r
- /* walk st */\r
- for( i = 0; i < 2; i++ )\r
- {\r
- /* walk xyz */\r
- for( j = 0; j < 3; j++ )\r
- {\r
- /* clear deltas */\r
- delta = 0.0;\r
- texDelta = 0.0;\r
- \r
- /* walk deltas */\r
- for( k = 0; k < 3; k++ )\r
- {\r
- if( fabs( deltas[ k ][ j ] ) > delta &&\r
- fabs( texDeltas[ k ][ i ] ) > texDelta )\r
- {\r
- delta = deltas[ k ][ j ];\r
- texDelta = texDeltas[ k ][ i ];\r
- }\r
- }\r
- \r
- /* set texture matrix component */\r
- if( fabs( delta ) > 0.0 )\r
- dp->texMat[ i ][ j ] = texDelta / delta;\r
- else\r
- dp->texMat[ i ][ j ] = 0.0;\r
- }\r
- \r
- /* set translation component */\r
- dp->texMat[ i ][ 3 ] = a->st[ i ] - DotProduct( pa, dp->texMat[ i ] );\r
- }\r
- }\r
- #endif\r
- \r
- /* debug code */\r
- #if 1\r
- Sys_Printf( "Mat: [ %f %f %f %f ] [ %f %f %f %f ] Theta: %f (%f)\n",\r
- dp->texMat[ 0 ][ 0 ], dp->texMat[ 0 ][ 1 ], dp->texMat[ 0 ][ 2 ], dp->texMat[ 0 ][ 3 ], \r
- dp->texMat[ 1 ][ 0 ], dp->texMat[ 1 ][ 1 ], dp->texMat[ 1 ][ 2 ], dp->texMat[ 1 ][ 3 ],\r
- RAD2DEG( acos( DotProduct( dp->texMat[ 0 ], dp->texMat[ 1 ] ) ) ),\r
- RAD2DEG( acos( DotProduct( axis[ 0 ], axis[ 1 ] ) ) ) );\r
- \r
- Sys_Printf( "XYZ: %f %f %f ST: %f %f ST(t): %f %f\n",\r
- a->xyz[ 0 ], a->xyz[ 1 ], a->xyz[ 2 ],\r
- a->st[ 0 ], a->st[ 1 ],\r
- DotProduct( a->xyz, dp->texMat[ 0 ] ) + dp->texMat[ 0 ][ 3 ], DotProduct( a->xyz, dp->texMat[ 1 ] ) + dp->texMat[ 1 ][ 3 ] );\r
- #endif\r
- \r
- /* test texture matrix */\r
- s = DotProduct( a->xyz, dp->texMat[ 0 ] ) + dp->texMat[ 0 ][ 3 ];\r
- t = DotProduct( a->xyz, dp->texMat[ 1 ] ) + dp->texMat[ 1 ][ 3 ];\r
- if( fabs( s - a->st[ 0 ] ) > 0.01 || fabs( t - a->st[ 1 ] ) > 0.01 )\r
- {\r
- Sys_Printf( "Bad texture matrix! (A) (%f, %f) != (%f, %f)\n",\r
- s, t, a->st[ 0 ], a->st[ 1 ] );\r
- //% return qfalse;\r
- }\r
- s = DotProduct( b->xyz, dp->texMat[ 0 ] ) + dp->texMat[ 0 ][ 3 ];\r
- t = DotProduct( b->xyz, dp->texMat[ 1 ] ) + dp->texMat[ 1 ][ 3 ];\r
- if( fabs( s - b->st[ 0 ] ) > 0.01 || fabs( t - b->st[ 1 ] ) > 0.01 )\r
- {\r
- Sys_Printf( "Bad texture matrix! (B) (%f, %f) != (%f, %f)\n",\r
- s, t, b->st[ 0 ], b->st[ 1 ] );\r
- //% return qfalse;\r
- }\r
- s = DotProduct( c->xyz, dp->texMat[ 0 ] ) + dp->texMat[ 0 ][ 3 ];\r
- t = DotProduct( c->xyz, dp->texMat[ 1 ] ) + dp->texMat[ 1 ][ 3 ];\r
- if( fabs( s - c->st[ 0 ] ) > 0.01 || fabs( t - c->st[ 1 ] ) > 0.01 )\r
- {\r
- Sys_Printf( "Bad texture matrix! (C) (%f, %f) != (%f, %f)\n",\r
- s, t, c->st[ 0 ], c->st[ 1 ] );\r
- //% return qfalse;\r
- }\r
- \r
- /* disco */\r
- return qtrue;\r
-}\r
-\r
-\r
-\r
-/*\r
-TransformDecalProjector()\r
-transforms a decal projector\r
-note: non-normalized axes will screw up the plane transform\r
-*/\r
-\r
-static void TransformDecalProjector( decalProjector_t *in, vec3_t axis[ 3 ], vec3_t origin, decalProjector_t *out )\r
-{\r
- int i;\r
- \r
- \r
- /* copy misc stuff */\r
- out->si = in->si;\r
- out->numPlanes = in->numPlanes;\r
- \r
- /* translate bounding box and sphere (note: rotated projector bounding box will be invalid!) */\r
- VectorSubtract( in->mins, origin, out->mins );\r
- VectorSubtract( in->maxs, origin, out->maxs );\r
- VectorSubtract( in->center, origin, out->center );\r
- out->radius = in->radius;\r
- out->radius2 = in->radius2;\r
- \r
- /* translate planes */\r
- for( i = 0; i < in->numPlanes; i++ )\r
- {\r
- out->planes[ i ][ 0 ] = DotProduct( in->planes[ i ], axis[ 0 ] );\r
- out->planes[ i ][ 1 ] = DotProduct( in->planes[ i ], axis[ 1 ] );\r
- out->planes[ i ][ 2 ] = DotProduct( in->planes[ i ], axis[ 2 ] );\r
- out->planes[ i ][ 3 ] = in->planes[ i ][ 3 ] - DotProduct( out->planes[ i ], origin );\r
- }\r
- \r
- /* translate texture matrix */\r
- for( i = 0; i < 2; i++ )\r
- {\r
- out->texMat[ i ][ 0 ] = DotProduct( in->texMat[ i ], axis[ 0 ] );\r
- out->texMat[ i ][ 1 ] = DotProduct( in->texMat[ i ], axis[ 1 ] );\r
- out->texMat[ i ][ 2 ] = DotProduct( in->texMat[ i ], axis[ 2 ] );\r
- out->texMat[ i ][ 3 ] = in->texMat[ i ][ 3 ] + DotProduct( out->texMat[ i ], origin );\r
- }\r
-}\r
-\r
-\r
-\r
-/*\r
-MakeDecalProjector()\r
-creates a new decal projector from a triangle\r
-*/\r
-\r
-static int MakeDecalProjector( shaderInfo_t *si, vec4_t projection, float distance, int numVerts, bspDrawVert_t **dv )\r
-{\r
- int i, j;\r
- decalProjector_t *dp;\r
- vec3_t xyz;\r
- \r
- \r
- /* dummy check */\r
- if( numVerts != 3 && numVerts != 4 )\r
- return -1;\r
- \r
- /* limit check */\r
- if( numProjectors >= MAX_PROJECTORS )\r
- {\r
- Sys_Printf( "WARNING: MAX_PROJECTORS (%d) exceeded, no more decal projectors available.\n", MAX_PROJECTORS );\r
- return -2;\r
- }\r
- \r
- /* create a new projector */\r
- dp = &projectors[ numProjectors ];\r
- memset( dp, 0, sizeof( *dp ) );\r
- \r
- /* basic setup */\r
- dp->si = si;\r
- dp->numPlanes = numVerts + 2;\r
- \r
- /* make texture matrix */\r
- if( !MakeTextureMatrix( dp, projection, dv[ 0 ], dv[ 1 ], dv[ 2 ] ) )\r
- return -1;\r
- \r
- /* bound the projector */\r
- ClearBounds( dp->mins, dp->maxs );\r
- for( i = 0; i < numVerts; i++ )\r
- {\r
- AddPointToBounds( dv[ i ]->xyz, dp->mins, dp->maxs );\r
- VectorMA( dv[ i ]->xyz, distance, projection, xyz );\r
- AddPointToBounds( xyz, dp->mins, dp->maxs );\r
- }\r
- \r
- /* make bouding sphere */\r
- VectorAdd( dp->mins, dp->maxs, dp->center );\r
- VectorScale( dp->center, 0.5f, dp->center );\r
- VectorSubtract( dp->maxs, dp->center, xyz );\r
- dp->radius = VectorLength( xyz );\r
- dp->radius2 = dp->radius * dp->radius;\r
- \r
- /* make the front plane */\r
- if( !PlaneFromPoints( dp->planes[ 0 ], dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) )\r
- return -1;\r
- \r
- /* make the back plane */\r
- VectorSubtract( vec3_origin, dp->planes[ 0 ], dp->planes[ 1 ] );\r
- VectorMA( dv[ 0 ]->xyz, distance, projection, xyz );\r
- dp->planes[ 1 ][ 3 ] = DotProduct( xyz, dp->planes[ 1 ] );\r
- \r
- /* make the side planes */\r
- for( i = 0; i < numVerts; i++ )\r
- {\r
- j = (i + 1) % numVerts;\r
- VectorMA( dv[ i ]->xyz, distance, projection, xyz );\r
- if( !PlaneFromPoints( dp->planes[ i + 2 ], dv[ j ]->xyz, dv[ i ]->xyz, xyz ) )\r
- return -1;\r
- }\r
- \r
- /* return ok */\r
- numProjectors++;\r
- return numProjectors - 1;\r
-}\r
-\r
-\r
-\r
-/*\r
-ProcessDecals()\r
-finds all decal entities and creates decal projectors\r
-*/\r
-\r
-#define PLANAR_EPSILON 0.5f\r
-\r
-void ProcessDecals( void )\r
-{\r
- int i, j, x, y, pw[ 5 ], r, iterations;\r
- float distance;\r
- vec4_t projection, plane;\r
- vec3_t origin, target, delta;\r
- entity_t *e, *e2;\r
- parseMesh_t *p;\r
- mesh_t *mesh, *subdivided;\r
- bspDrawVert_t *dv[ 4 ];\r
- const char *value;\r
- \r
- \r
- /* note it */\r
- Sys_FPrintf( SYS_VRB, "--- ProcessDecals ---\n" );\r
- \r
- /* walk entity list */\r
- for( i = 0; i < numEntities; i++ )\r
- {\r
- /* get entity */\r
- e = &entities[ i ];\r
- value = ValueForKey( e, "classname" );\r
- if( Q_stricmp( value, "_decal" ) )\r
- continue;\r
- \r
- /* any patches? */\r
- if( e->patches == NULL )\r
- {\r
- Sys_Printf( "WARNING: Decal entity without any patch meshes, ignoring.\n" );\r
- e->epairs = NULL; /* fixme: leak! */\r
- continue;\r
- }\r
- \r
- /* find target */\r
- value = ValueForKey( e, "target" );\r
- e2 = FindTargetEntity( value );\r
- \r
- /* no target? */\r
- if( e2 == NULL )\r
- {\r
- Sys_Printf( "WARNING: Decal entity without a valid target, ignoring.\n" );\r
- continue;\r
- }\r
- \r
- /* walk entity patches */\r
- for( p = e->patches; p != NULL; p = e->patches )\r
- {\r
- /* setup projector */\r
- if( VectorCompare( e->origin, vec3_origin ) )\r
- {\r
- VectorAdd( p->eMins, p->eMaxs, origin );\r
- VectorScale( origin, 0.5f, origin );\r
- }\r
- else\r
- VectorCopy( e->origin, origin );\r
- \r
- VectorCopy( e2->origin, target );\r
- VectorSubtract( target, origin, delta );\r
- \r
- /* setup projection plane */\r
- distance = VectorNormalize( delta, projection );\r
- projection[ 3 ] = DotProduct( origin, projection );\r
- \r
- /* create projectors */\r
- if( distance > 0.125f )\r
- {\r
- /* tesselate the patch */\r
- iterations = IterationsForCurve( p->longestCurve, patchSubdivisions );\r
- subdivided = SubdivideMesh2( p->mesh, iterations );\r
- \r
- /* fit it to the curve and remove colinear verts on rows/columns */\r
- PutMeshOnCurve( *subdivided );\r
- mesh = RemoveLinearMeshColumnsRows( subdivided );\r
- FreeMesh( subdivided );\r
- \r
- /* offset by projector origin */\r
- for( j = 0; j < (mesh->width * mesh->height); j++ )\r
- VectorAdd( mesh->verts[ j ].xyz, e->origin, mesh->verts[ j ].xyz );\r
- \r
- /* iterate through the mesh quads */\r
- for( y = 0; y < (mesh->height - 1); y++ )\r
- {\r
- for( x = 0; x < (mesh->width - 1); x++ )\r
- {\r
- /* set indexes */\r
- pw[ 0 ] = x + (y * mesh->width);\r
- pw[ 1 ] = x + ((y + 1) * mesh->width);\r
- pw[ 2 ] = x + 1 + ((y + 1) * mesh->width);\r
- pw[ 3 ] = x + 1 + (y * mesh->width);\r
- pw[ 4 ] = x + (y * mesh->width); /* same as pw[ 0 ] */\r
- \r
- /* set radix */\r
- r = (x + y) & 1;\r
- \r
- /* get drawverts */\r
- dv[ 0 ] = &mesh->verts[ pw[ r + 0 ] ];\r
- dv[ 1 ] = &mesh->verts[ pw[ r + 1 ] ];\r
- dv[ 2 ] = &mesh->verts[ pw[ r + 2 ] ];\r
- dv[ 3 ] = &mesh->verts[ pw[ r + 3 ] ];\r
- \r
- /* planar? (nuking this optimization as it doesn't work on non-rectangular quads) */\r
- plane[ 0 ] = 0.0f; /* stupid msvc */\r
- if( 0 && PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) &&\r
- fabs( DotProduct( dv[ 1 ]->xyz, plane ) - plane[ 3 ] ) <= PLANAR_EPSILON )\r
- {\r
- /* make a quad projector */\r
- MakeDecalProjector( p->shaderInfo, projection, distance, 4, dv );\r
- }\r
- else\r
- {\r
- /* make first triangle */\r
- MakeDecalProjector( p->shaderInfo, projection, distance, 3, dv );\r
- \r
- /* make second triangle */\r
- dv[ 1 ] = dv[ 2 ];\r
- dv[ 2 ] = dv[ 3 ];\r
- MakeDecalProjector( p->shaderInfo, projection, distance, 3, dv );\r
- }\r
- }\r
- }\r
- \r
- /* clean up */\r
- free( mesh );\r
- }\r
- \r
- /* remove patch from entity (fixme: leak!) */\r
- e->patches = p->next;\r
- \r
- /* push patch to worldspawn (enable this to debug projectors) */\r
- #if 0\r
- p->next = entities[ 0 ].patches;\r
- entities[ 0 ].patches = p;\r
- #endif\r
- }\r
- }\r
- \r
- /* emit some stats */\r
- Sys_FPrintf( SYS_VRB, "%9d decal projectors\n", numProjectors );\r
-}\r
-\r
-\r
-\r
-/*\r
-ProjectDecalOntoWinding()\r
-projects a decal onto a winding\r
-*/\r
-\r
-static void ProjectDecalOntoWinding( decalProjector_t *dp, mapDrawSurface_t *ds, winding_t *w )\r
-{\r
- int i, j;\r
- float d, d2, alpha;\r
- winding_t *front, *back;\r
- mapDrawSurface_t *ds2;\r
- bspDrawVert_t *dv;\r
- vec4_t plane;\r
- \r
- \r
- /* dummy check */\r
- if( w->numpoints < 3 )\r
- {\r
- FreeWinding( w );\r
- return;\r
- }\r
- \r
- /* offset by entity origin */\r
- for( i = 0; i < w->numpoints; i++ )\r
- VectorAdd( w->p[ i ], entityOrigin, w->p[ i ] );\r
- \r
- /* make a plane from the winding */\r
- if( !PlaneFromPoints( plane, w->p[ 0 ], w->p[ 1 ], w->p[ 2 ] ) )\r
- {\r
- FreeWinding( w );\r
- return;\r
- }\r
- \r
- /* backface check */\r
- d = DotProduct( dp->planes[ 0 ], plane );\r
- if( d < -0.0001f )\r
- {\r
- FreeWinding( w );\r
- return;\r
- }\r
- \r
- /* walk list of planes */\r
- for( i = 0; i < dp->numPlanes; i++ )\r
- {\r
- /* chop winding by the plane */\r
- ClipWindingEpsilon( w, dp->planes[ i ], dp->planes[ i ][ 3 ], 0.0625f, &front, &back );\r
- FreeWinding( w );\r
- \r
- /* lose the front fragment */\r
- if( front != NULL )\r
- FreeWinding( front );\r
- \r
- /* if nothing left in back, then bail */\r
- if( back == NULL )\r
- return;\r
- \r
- /* reset winding */\r
- w = back;\r
- }\r
- \r
- /* nothing left? */\r
- if( w == NULL || w->numpoints < 3 )\r
- return;\r
- \r
- /* add to counts */\r
- numDecalSurfaces++;\r
- \r
- /* make a new surface */\r
- ds2 = AllocDrawSurface( SURFACE_DECAL );\r
- \r
- /* set it up */\r
- ds2->entityNum = ds->entityNum;\r
- ds2->castShadows = ds->castShadows;\r
- ds2->recvShadows = ds->recvShadows;\r
- ds2->shaderInfo = dp->si;\r
- ds2->fogNum = ds->fogNum; /* why was this -1? */\r
- ds2->lightmapScale = ds->lightmapScale;\r
- ds2->numVerts = w->numpoints;\r
- ds2->verts = safe_malloc( ds2->numVerts * sizeof( *ds2->verts ) );\r
- memset( ds2->verts, 0, ds2->numVerts * sizeof( *ds2->verts ) );\r
- \r
- /* set vertexes */\r
- for( i = 0; i < ds2->numVerts; i++ )\r
- {\r
- /* get vertex */\r
- dv = &ds2->verts[ i ];\r
- \r
- /* set alpha */\r
- d = DotProduct( w->p[ i ], dp->planes[ 0 ] ) - dp->planes[ 0 ][ 3 ];\r
- d2 = DotProduct( w->p[ i ], dp->planes[ 1 ] ) - dp->planes[ 1 ][ 3 ];\r
- alpha = 255.0f * d2 / (d + d2);\r
- if( alpha > 255 )\r
- alpha = 255;\r
- else if( alpha < 0 )\r
- alpha = 0;\r
- \r
- /* set misc */\r
- VectorSubtract( w->p[ i ], entityOrigin, dv->xyz );\r
- VectorCopy( plane, dv->normal );\r
- dv->st[ 0 ] = DotProduct( dv->xyz, dp->texMat[ 0 ] ) + dp->texMat[ 0 ][ 3 ];\r
- dv->st[ 1 ] = DotProduct( dv->xyz, dp->texMat[ 1 ] ) + dp->texMat[ 1 ][ 3 ];\r
- \r
- /* set color */\r
- for( j = 0; j < MAX_LIGHTMAPS; j++ )\r
- {\r
- dv->color[ j ][ 0 ] = 255;\r
- dv->color[ j ][ 1 ] = 255;\r
- dv->color[ j ][ 2 ] = 255;\r
- dv->color[ j ][ 3 ] = alpha;\r
- }\r
- }\r
- \r
- /* ydnar: finish the surface */\r
- FinishSurface( ds2 );\r
-}\r
-\r
-\r
-\r
-/*\r
-ProjectDecalOntoFace()\r
-projects a decal onto a brushface surface\r
-*/\r
-\r
-static void ProjectDecalOntoFace( decalProjector_t *dp, mapDrawSurface_t *ds )\r
-{\r
- vec4_t plane;\r
- float d;\r
- winding_t *w;\r
- \r
- \r
- /* dummy check */\r
- if( ds->sideRef == NULL || ds->sideRef->side == NULL )\r
- return;\r
- \r
- /* backface check */\r
- if( ds->planar )\r
- {\r
- VectorCopy( mapplanes[ ds->planeNum ].normal, plane );\r
- plane[ 3 ] = mapplanes[ ds->planeNum ].dist + DotProduct( plane, entityOrigin );\r
- d = DotProduct( dp->planes[ 0 ], plane );\r
- if( d < -0.0001f )\r
- return;\r
- }\r
- \r
- /* generate decal */\r
- w = WindingFromDrawSurf( ds );\r
- ProjectDecalOntoWinding( dp, ds, w );\r
-}\r
-\r
-\r
-\r
-/*\r
-ProjectDecalOntoPatch()\r
-projects a decal onto a patch surface\r
-*/\r
-\r
-static void ProjectDecalOntoPatch( decalProjector_t *dp, mapDrawSurface_t *ds )\r
-{\r
- int x, y, pw[ 5 ], r, iterations;\r
- vec4_t plane;\r
- float d;\r
- mesh_t src, *mesh, *subdivided;\r
- winding_t *w;\r
- \r
- \r
- /* backface check */\r
- if( ds->planar )\r
- {\r
- VectorCopy( mapplanes[ ds->planeNum ].normal, plane );\r
- plane[ 3 ] = mapplanes[ ds->planeNum ].dist + DotProduct( plane, entityOrigin );\r
- d = DotProduct( dp->planes[ 0 ], plane );\r
- if( d < -0.0001f )\r
- return;\r
- }\r
- \r
- /* tesselate the patch */\r
- src.width = ds->patchWidth;\r
- src.height = ds->patchHeight;\r
- src.verts = ds->verts;\r
- iterations = IterationsForCurve( ds->longestCurve, patchSubdivisions );\r
- subdivided = SubdivideMesh2( src, iterations );\r
- \r
- /* fit it to the curve and remove colinear verts on rows/columns */\r
- PutMeshOnCurve( *subdivided );\r
- mesh = RemoveLinearMeshColumnsRows( subdivided );\r
- FreeMesh( subdivided );\r
- \r
- /* iterate through the mesh quads */\r
- for( y = 0; y < (mesh->height - 1); y++ )\r
- {\r
- for( x = 0; x < (mesh->width - 1); x++ )\r
- {\r
- /* set indexes */\r
- pw[ 0 ] = x + (y * mesh->width);\r
- pw[ 1 ] = x + ((y + 1) * mesh->width);\r
- pw[ 2 ] = x + 1 + ((y + 1) * mesh->width);\r
- pw[ 3 ] = x + 1 + (y * mesh->width);\r
- pw[ 4 ] = x + (y * mesh->width); /* same as pw[ 0 ] */\r
- \r
- /* set radix */\r
- r = (x + y) & 1;\r
- \r
- /* generate decal for first triangle */\r
- w = AllocWinding( 3 );\r
- w->numpoints = 3;\r
- VectorCopy( mesh->verts[ pw[ r + 0 ] ].xyz, w->p[ 0 ] );\r
- VectorCopy( mesh->verts[ pw[ r + 1 ] ].xyz, w->p[ 1 ] );\r
- VectorCopy( mesh->verts[ pw[ r + 2 ] ].xyz, w->p[ 2 ] );\r
- ProjectDecalOntoWinding( dp, ds, w );\r
- \r
- /* generate decal for second triangle */\r
- w = AllocWinding( 3 );\r
- w->numpoints = 3;\r
- VectorCopy( mesh->verts[ pw[ r + 0 ] ].xyz, w->p[ 0 ] );\r
- VectorCopy( mesh->verts[ pw[ r + 2 ] ].xyz, w->p[ 1 ] );\r
- VectorCopy( mesh->verts[ pw[ r + 3 ] ].xyz, w->p[ 2 ] );\r
- ProjectDecalOntoWinding( dp, ds, w );\r
- }\r
- }\r
- \r
- /* clean up */\r
- free( mesh );\r
-}\r
-\r
-\r
-\r
-/*\r
-ProjectDecalOntoTriangles()\r
-projects a decal onto a triangle surface\r
-*/\r
-\r
-static void ProjectDecalOntoTriangles( decalProjector_t *dp, mapDrawSurface_t *ds )\r
-{\r
- int i;\r
- vec4_t plane;\r
- float d;\r
- winding_t *w;\r
- \r
- \r
- /* triangle surfaces without shaders don't get marks by default */\r
- if( (ds->type == SURFACE_TRIANGLES || ds->type == SURFACE_FORCED_META) &&\r
- ds->shaderInfo->shaderText == NULL )\r
- return;\r
- \r
- /* backface check */\r
- if( ds->planar )\r
- {\r
- VectorCopy( mapplanes[ ds->planeNum ].normal, plane );\r
- plane[ 3 ] = mapplanes[ ds->planeNum ].dist + DotProduct( plane, entityOrigin );\r
- d = DotProduct( dp->planes[ 0 ], plane );\r
- if( d < -0.0001f )\r
- return;\r
- }\r
- \r
- /* iterate through triangles */\r
- for( i = 0; i < ds->numIndexes; i += 3 )\r
- {\r
- /* generate decal */\r
- w = AllocWinding( 3 );\r
- w->numpoints = 3;\r
- VectorCopy( ds->verts[ ds->indexes[ i ] ].xyz, w->p[ 0 ] );\r
- VectorCopy( ds->verts[ ds->indexes[ i + 1 ] ].xyz, w->p[ 1 ] );\r
- VectorCopy( ds->verts[ ds->indexes[ i + 2 ] ].xyz, w->p[ 2 ] );\r
- ProjectDecalOntoWinding( dp, ds, w );\r
- }\r
-}\r
-\r
-\r
-\r
-/*\r
-MakeEntityDecals()\r
-projects decals onto world surfaces\r
-*/\r
-\r
-void MakeEntityDecals( entity_t *e )\r
-{\r
- int i, j, k, f, fOld, start;\r
- decalProjector_t dp;\r
- mapDrawSurface_t *ds;\r
- vec3_t identityAxis[ 3 ] = { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } };\r
- \r
- \r
- /* note it */\r
- Sys_FPrintf( SYS_VRB, "--- MakeEntityDecals ---\n" );\r
- \r
- /* set entity origin */\r
- VectorCopy( e->origin, entityOrigin );\r
- \r
- /* transform projector instead of geometry */\r
- VectorClear( entityOrigin );\r
- \r
- /* init pacifier */\r
- fOld = -1;\r
- start = I_FloatTime();\r
- \r
- /* walk the list of decal projectors */\r
- for( i = 0; i < numProjectors; i++ )\r
- {\r
- /* print pacifier */\r
- f = 10 * i / numProjectors;\r
- if( f != fOld )\r
- {\r
- fOld = f;\r
- Sys_FPrintf( SYS_VRB, "%d...", f );\r
- }\r
- \r
- /* get projector */\r
- TransformDecalProjector( &projectors[ i ], identityAxis, e->origin, &dp );\r
- \r
- /* walk the list of surfaces in the entity */\r
- for( j = e->firstDrawSurf; j < numMapDrawSurfs; j++ )\r
- {\r
- /* get surface */\r
- ds = &mapDrawSurfs[ j ];\r
- if( ds->numVerts <= 0 )\r
- continue;\r
- \r
- /* ignore autosprite or nomarks */\r
- if( ds->shaderInfo->autosprite || (ds->shaderInfo->compileFlags & C_NOMARKS) )\r
- continue;\r
- \r
- /* bounds check */\r
- for( k = 0; k < 3; k++ )\r
- if( ds->mins[ k ] >= (dp.center[ k ] + dp.radius) ||\r
- ds->maxs[ k ] <= (dp.center[ k ] - dp.radius) )\r
- break;\r
- if( k < 3 )\r
- continue;\r
- \r
- /* switch on type */\r
- switch( ds->type )\r
- {\r
- case SURFACE_FACE:\r
- ProjectDecalOntoFace( &dp, ds );\r
- break;\r
- \r
- case SURFACE_PATCH:\r
- ProjectDecalOntoPatch( &dp, ds );\r
- break;\r
- \r
- case SURFACE_TRIANGLES:\r
- case SURFACE_FORCED_META:\r
- case SURFACE_META:\r
- ProjectDecalOntoTriangles( &dp, ds );\r
- break;\r
- \r
- default:\r
- break;\r
- }\r
- }\r
- }\r
- \r
- /* print time */\r
- Sys_FPrintf( SYS_VRB, " (%d)\n", (int) (I_FloatTime() - start) );\r
- \r
- /* emit some stats */\r
- Sys_FPrintf( SYS_VRB, "%9d decal surfaces\n", numDecalSurfaces );\r
-}\r
+/* -------------------------------------------------------------------------------
+
+ Copyright (C) 1999-2007 id Software, Inc. and contributors.
+ For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+ This file is part of GtkRadiant.
+
+ GtkRadiant is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ GtkRadiant is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GtkRadiant; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+ ----------------------------------------------------------------------------------
+
+ This code has been altered significantly from its original form, to support
+ several games based on the Quake III Arena engine, in the form of "Q3Map2."
+
+ ------------------------------------------------------------------------------- */
+
+
+
+/* marker */
+#define DECALS_C
+
+
+
+/* dependencies */
+#include "q3map2.h"
+
+
+
+#define MAX_PROJECTORS 1024
+
+typedef struct decalProjector_s
+{
+ shaderInfo_t *si;
+ vec3_t mins, maxs;
+ vec3_t center;
+ float radius, radius2;
+ int numPlanes; /* either 5 or 6, for quad or triangle projectors */
+ vec4_t planes[ 6 ];
+ vec4_t texMat[ 2 ];
+}
+decalProjector_t;
+
+static int numProjectors = 0;
+static decalProjector_t projectors[ MAX_PROJECTORS ];
+
+static int numDecalSurfaces = 0;
+
+static vec3_t entityOrigin;
+
+
+
+/*
+ DVectorNormalize()
+ normalizes a vector, returns the length, operates using doubles
+ */
+
+typedef double dvec_t;
+typedef dvec_t dvec3_t[ 3 ];
+
+dvec_t DVectorNormalize( dvec3_t in, dvec3_t out ){
+ dvec_t len, ilen;
+
+
+ len = (dvec_t) sqrt( in[ 0 ] * in[ 0 ] + in[ 1 ] * in[ 1 ] + in[ 2 ] * in[ 2 ] );
+ if ( len == 0.0 ) {
+ VectorClear( out );
+ return 0.0;
+ }
+
+ ilen = 1.0 / len;
+ out[ 0 ] = in[ 0 ] * ilen;
+ out[ 1 ] = in[ 1 ] * ilen;
+ out[ 2 ] = in[ 2 ] * ilen;
+
+ return len;
+}
+
+
+
+/*
+ MakeTextureMatrix()
+ generates a texture projection matrix for a triangle
+ returns qfalse if a texture matrix cannot be created
+ */
+
+#define Vector2Subtract( a,b,c ) ( ( c )[ 0 ] = ( a )[ 0 ] - ( b )[ 0 ], ( c )[ 1 ] = ( a )[ 1 ] - ( b )[ 1 ] )
+
+static qboolean MakeTextureMatrix( decalProjector_t *dp, vec4_t projection, bspDrawVert_t *a, bspDrawVert_t *b, bspDrawVert_t *c ){
+ int i, j;
+ double bb, s, t, d;
+ dvec3_t pa, pb, pc;
+ dvec3_t bary, xyz;
+ dvec3_t vecs[ 3 ], axis[ 3 ], lengths;
+
+
+ /* project triangle onto plane of projection */
+ d = DotProduct( a->xyz, projection ) - projection[ 3 ];
+ VectorMA( a->xyz, -d, projection, pa );
+ d = DotProduct( b->xyz, projection ) - projection[ 3 ];
+ VectorMA( b->xyz, -d, projection, pb );
+ d = DotProduct( c->xyz, projection ) - projection[ 3 ];
+ VectorMA( c->xyz, -d, projection, pc );
+
+ /* two methods */
+ #if 1
+ {
+ /* old code */
+
+ /* calculate barycentric basis for the triangle */
+ 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 ] );
+ if ( fabs( bb ) < 0.00000001 ) {
+ return qfalse;
+ }
+
+ /* calculate texture origin */
+ #if 0
+ s = 0.0;
+ t = 0.0;
+ bary[ 0 ] = ( ( b->st[ 0 ] - s ) * ( c->st[ 1 ] - t ) - ( c->st[ 0 ] - s ) * ( b->st[ 1 ] - t ) ) / bb;
+ bary[ 1 ] = ( ( c->st[ 0 ] - s ) * ( a->st[ 1 ] - t ) - ( a->st[ 0 ] - s ) * ( c->st[ 1 ] - t ) ) / bb;
+ bary[ 2 ] = ( ( a->st[ 0 ] - s ) * ( b->st[ 1 ] - t ) - ( b->st[ 0 ] - s ) * ( a->st[ 1 ] - t ) ) / bb;
+
+ origin[ 0 ] = bary[ 0 ] * pa[ 0 ] + bary[ 1 ] * pb[ 0 ] + bary[ 2 ] * pc[ 0 ];
+ origin[ 1 ] = bary[ 0 ] * pa[ 1 ] + bary[ 1 ] * pb[ 1 ] + bary[ 2 ] * pc[ 1 ];
+ origin[ 2 ] = bary[ 0 ] * pa[ 2 ] + bary[ 1 ] * pb[ 2 ] + bary[ 2 ] * pc[ 2 ];
+ #endif
+
+ /* calculate s vector */
+ s = a->st[ 0 ] + 1.0;
+ t = a->st[ 1 ] + 0.0;
+ bary[ 0 ] = ( ( b->st[ 0 ] - s ) * ( c->st[ 1 ] - t ) - ( c->st[ 0 ] - s ) * ( b->st[ 1 ] - t ) ) / bb;
+ bary[ 1 ] = ( ( c->st[ 0 ] - s ) * ( a->st[ 1 ] - t ) - ( a->st[ 0 ] - s ) * ( c->st[ 1 ] - t ) ) / bb;
+ bary[ 2 ] = ( ( a->st[ 0 ] - s ) * ( b->st[ 1 ] - t ) - ( b->st[ 0 ] - s ) * ( a->st[ 1 ] - t ) ) / bb;
+
+ xyz[ 0 ] = bary[ 0 ] * pa[ 0 ] + bary[ 1 ] * pb[ 0 ] + bary[ 2 ] * pc[ 0 ];
+ xyz[ 1 ] = bary[ 0 ] * pa[ 1 ] + bary[ 1 ] * pb[ 1 ] + bary[ 2 ] * pc[ 1 ];
+ xyz[ 2 ] = bary[ 0 ] * pa[ 2 ] + bary[ 1 ] * pb[ 2 ] + bary[ 2 ] * pc[ 2 ];
+
+ //% VectorSubtract( xyz, origin, vecs[ 0 ] );
+ VectorSubtract( xyz, pa, vecs[ 0 ] );
+
+ /* calculate t vector */
+ s = a->st[ 0 ] + 0.0;
+ t = a->st[ 1 ] + 1.0;
+ bary[ 0 ] = ( ( b->st[ 0 ] - s ) * ( c->st[ 1 ] - t ) - ( c->st[ 0 ] - s ) * ( b->st[ 1 ] - t ) ) / bb;
+ bary[ 1 ] = ( ( c->st[ 0 ] - s ) * ( a->st[ 1 ] - t ) - ( a->st[ 0 ] - s ) * ( c->st[ 1 ] - t ) ) / bb;
+ bary[ 2 ] = ( ( a->st[ 0 ] - s ) * ( b->st[ 1 ] - t ) - ( b->st[ 0 ] - s ) * ( a->st[ 1 ] - t ) ) / bb;
+
+ xyz[ 0 ] = bary[ 0 ] * pa[ 0 ] + bary[ 1 ] * pb[ 0 ] + bary[ 2 ] * pc[ 0 ];
+ xyz[ 1 ] = bary[ 0 ] * pa[ 1 ] + bary[ 1 ] * pb[ 1 ] + bary[ 2 ] * pc[ 1 ];
+ xyz[ 2 ] = bary[ 0 ] * pa[ 2 ] + bary[ 1 ] * pb[ 2 ] + bary[ 2 ] * pc[ 2 ];
+
+ //% VectorSubtract( xyz, origin, vecs[ 1 ] );
+ VectorSubtract( xyz, pa, vecs[ 1 ] );
+
+ /* calcuate r vector */
+ VectorScale( projection, -1.0, vecs[ 2 ] );
+
+ /* calculate transform axis */
+ for ( i = 0; i < 3; i++ )
+ lengths[ i ] = DVectorNormalize( vecs[ i ], axis[ i ] );
+ for ( i = 0; i < 2; i++ )
+ for ( j = 0; j < 3; j++ )
+ dp->texMat[ i ][ j ] = lengths[ i ] > 0.0 ? ( axis[ i ][ j ] / lengths[ i ] ) : 0.0;
+ //% dp->texMat[ i ][ j ] = fabs( vecs[ i ][ j ] ) > 0.0 ? (1.0 / vecs[ i ][ j ]) : 0.0;
+ //% dp->texMat[ i ][ j ] = axis[ i ][ j ] > 0.0 ? (1.0 / axis[ i ][ j ]) : 0.0;
+
+ /* calculalate translation component */
+ dp->texMat[ 0 ][ 3 ] = a->st[ 0 ] - DotProduct( a->xyz, dp->texMat[ 0 ] );
+ dp->texMat[ 1 ][ 3 ] = a->st[ 1 ] - DotProduct( a->xyz, dp->texMat[ 1 ] );
+ }
+ #else
+ {
+ int k;
+ dvec3_t origin, deltas[ 3 ];
+ double texDeltas[ 3 ][ 2 ];
+ double delta, texDelta;
+
+
+ /* new code */
+
+ /* calculate deltas */
+ VectorSubtract( pa, pb, deltas[ 0 ] );
+ VectorSubtract( pa, pc, deltas[ 1 ] );
+ VectorSubtract( pb, pc, deltas[ 2 ] );
+ Vector2Subtract( a->st, b->st, texDeltas[ 0 ] );
+ Vector2Subtract( a->st, c->st, texDeltas[ 1 ] );
+ Vector2Subtract( b->st, c->st, texDeltas[ 2 ] );
+
+ /* walk st */
+ for ( i = 0; i < 2; i++ )
+ {
+ /* walk xyz */
+ for ( j = 0; j < 3; j++ )
+ {
+ /* clear deltas */
+ delta = 0.0;
+ texDelta = 0.0;
+
+ /* walk deltas */
+ for ( k = 0; k < 3; k++ )
+ {
+ if ( fabs( deltas[ k ][ j ] ) > delta &&
+ fabs( texDeltas[ k ][ i ] ) > texDelta ) {
+ delta = deltas[ k ][ j ];
+ texDelta = texDeltas[ k ][ i ];
+ }
+ }
+
+ /* set texture matrix component */
+ if ( fabs( delta ) > 0.0 ) {
+ dp->texMat[ i ][ j ] = texDelta / delta;
+ }
+ else{
+ dp->texMat[ i ][ j ] = 0.0;
+ }
+ }
+
+ /* set translation component */
+ dp->texMat[ i ][ 3 ] = a->st[ i ] - DotProduct( pa, dp->texMat[ i ] );
+ }
+ }
+ #endif
+
+ /* debug code */
+ #if 1
+ Sys_Printf( "Mat: [ %f %f %f %f ] [ %f %f %f %f ] Theta: %f (%f)\n",
+ dp->texMat[ 0 ][ 0 ], dp->texMat[ 0 ][ 1 ], dp->texMat[ 0 ][ 2 ], dp->texMat[ 0 ][ 3 ],
+ dp->texMat[ 1 ][ 0 ], dp->texMat[ 1 ][ 1 ], dp->texMat[ 1 ][ 2 ], dp->texMat[ 1 ][ 3 ],
+ RAD2DEG( acos( DotProduct( dp->texMat[ 0 ], dp->texMat[ 1 ] ) ) ),
+ RAD2DEG( acos( DotProduct( axis[ 0 ], axis[ 1 ] ) ) ) );
+
+ Sys_Printf( "XYZ: %f %f %f ST: %f %f ST(t): %f %f\n",
+ a->xyz[ 0 ], a->xyz[ 1 ], a->xyz[ 2 ],
+ a->st[ 0 ], a->st[ 1 ],
+ DotProduct( a->xyz, dp->texMat[ 0 ] ) + dp->texMat[ 0 ][ 3 ], DotProduct( a->xyz, dp->texMat[ 1 ] ) + dp->texMat[ 1 ][ 3 ] );
+ #endif
+
+ /* test texture matrix */
+ s = DotProduct( a->xyz, dp->texMat[ 0 ] ) + dp->texMat[ 0 ][ 3 ];
+ t = DotProduct( a->xyz, dp->texMat[ 1 ] ) + dp->texMat[ 1 ][ 3 ];
+ if ( fabs( s - a->st[ 0 ] ) > 0.01 || fabs( t - a->st[ 1 ] ) > 0.01 ) {
+ Sys_Printf( "Bad texture matrix! (A) (%f, %f) != (%f, %f)\n",
+ s, t, a->st[ 0 ], a->st[ 1 ] );
+ //% return qfalse;
+ }
+ s = DotProduct( b->xyz, dp->texMat[ 0 ] ) + dp->texMat[ 0 ][ 3 ];
+ t = DotProduct( b->xyz, dp->texMat[ 1 ] ) + dp->texMat[ 1 ][ 3 ];
+ if ( fabs( s - b->st[ 0 ] ) > 0.01 || fabs( t - b->st[ 1 ] ) > 0.01 ) {
+ Sys_Printf( "Bad texture matrix! (B) (%f, %f) != (%f, %f)\n",
+ s, t, b->st[ 0 ], b->st[ 1 ] );
+ //% return qfalse;
+ }
+ s = DotProduct( c->xyz, dp->texMat[ 0 ] ) + dp->texMat[ 0 ][ 3 ];
+ t = DotProduct( c->xyz, dp->texMat[ 1 ] ) + dp->texMat[ 1 ][ 3 ];
+ if ( fabs( s - c->st[ 0 ] ) > 0.01 || fabs( t - c->st[ 1 ] ) > 0.01 ) {
+ Sys_Printf( "Bad texture matrix! (C) (%f, %f) != (%f, %f)\n",
+ s, t, c->st[ 0 ], c->st[ 1 ] );
+ //% return qfalse;
+ }
+
+ /* disco */
+ return qtrue;
+}
+
+
+
+/*
+ TransformDecalProjector()
+ transforms a decal projector
+ note: non-normalized axes will screw up the plane transform
+ */
+
+static void TransformDecalProjector( decalProjector_t *in, vec3_t axis[ 3 ], vec3_t origin, decalProjector_t *out ){
+ int i;
+
+
+ /* copy misc stuff */
+ out->si = in->si;
+ out->numPlanes = in->numPlanes;
+
+ /* translate bounding box and sphere (note: rotated projector bounding box will be invalid!) */
+ VectorSubtract( in->mins, origin, out->mins );
+ VectorSubtract( in->maxs, origin, out->maxs );
+ VectorSubtract( in->center, origin, out->center );
+ out->radius = in->radius;
+ out->radius2 = in->radius2;
+
+ /* translate planes */
+ for ( i = 0; i < in->numPlanes; i++ )
+ {
+ out->planes[ i ][ 0 ] = DotProduct( in->planes[ i ], axis[ 0 ] );
+ out->planes[ i ][ 1 ] = DotProduct( in->planes[ i ], axis[ 1 ] );
+ out->planes[ i ][ 2 ] = DotProduct( in->planes[ i ], axis[ 2 ] );
+ out->planes[ i ][ 3 ] = in->planes[ i ][ 3 ] - DotProduct( out->planes[ i ], origin );
+ }
+
+ /* translate texture matrix */
+ for ( i = 0; i < 2; i++ )
+ {
+ out->texMat[ i ][ 0 ] = DotProduct( in->texMat[ i ], axis[ 0 ] );
+ out->texMat[ i ][ 1 ] = DotProduct( in->texMat[ i ], axis[ 1 ] );
+ out->texMat[ i ][ 2 ] = DotProduct( in->texMat[ i ], axis[ 2 ] );
+ out->texMat[ i ][ 3 ] = in->texMat[ i ][ 3 ] + DotProduct( out->texMat[ i ], origin );
+ }
+}
+
+
+
+/*
+ MakeDecalProjector()
+ creates a new decal projector from a triangle
+ */
+
+static int MakeDecalProjector( shaderInfo_t *si, vec4_t projection, float distance, int numVerts, bspDrawVert_t **dv ){
+ int i, j;
+ decalProjector_t *dp;
+ vec3_t xyz;
+
+
+ /* dummy check */
+ if ( numVerts != 3 && numVerts != 4 ) {
+ return -1;
+ }
+
+ /* limit check */
+ if ( numProjectors >= MAX_PROJECTORS ) {
+ Sys_Printf( "WARNING: MAX_PROJECTORS (%d) exceeded, no more decal projectors available.\n", MAX_PROJECTORS );
+ return -2;
+ }
+
+ /* create a new projector */
+ dp = &projectors[ numProjectors ];
+ memset( dp, 0, sizeof( *dp ) );
+
+ /* basic setup */
+ dp->si = si;
+ dp->numPlanes = numVerts + 2;
+
+ /* make texture matrix */
+ if ( !MakeTextureMatrix( dp, projection, dv[ 0 ], dv[ 1 ], dv[ 2 ] ) ) {
+ return -1;
+ }
+
+ /* bound the projector */
+ ClearBounds( dp->mins, dp->maxs );
+ for ( i = 0; i < numVerts; i++ )
+ {
+ AddPointToBounds( dv[ i ]->xyz, dp->mins, dp->maxs );
+ VectorMA( dv[ i ]->xyz, distance, projection, xyz );
+ AddPointToBounds( xyz, dp->mins, dp->maxs );
+ }
+
+ /* make bouding sphere */
+ VectorAdd( dp->mins, dp->maxs, dp->center );
+ VectorScale( dp->center, 0.5f, dp->center );
+ VectorSubtract( dp->maxs, dp->center, xyz );
+ dp->radius = VectorLength( xyz );
+ dp->radius2 = dp->radius * dp->radius;
+
+ /* make the front plane */
+ if ( !PlaneFromPoints( dp->planes[ 0 ], dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) ) {
+ return -1;
+ }
+
+ /* make the back plane */
+ VectorSubtract( vec3_origin, dp->planes[ 0 ], dp->planes[ 1 ] );
+ VectorMA( dv[ 0 ]->xyz, distance, projection, xyz );
+ dp->planes[ 1 ][ 3 ] = DotProduct( xyz, dp->planes[ 1 ] );
+
+ /* make the side planes */
+ for ( i = 0; i < numVerts; i++ )
+ {
+ j = ( i + 1 ) % numVerts;
+ VectorMA( dv[ i ]->xyz, distance, projection, xyz );
+ if ( !PlaneFromPoints( dp->planes[ i + 2 ], dv[ j ]->xyz, dv[ i ]->xyz, xyz ) ) {
+ return -1;
+ }
+ }
+
+ /* return ok */
+ numProjectors++;
+ return numProjectors - 1;
+}
+
+
+
+/*
+ ProcessDecals()
+ finds all decal entities and creates decal projectors
+ */
+
+#define PLANAR_EPSILON 0.5f
+
+void ProcessDecals( void ){
+ int i, j, x, y, pw[ 5 ], r, iterations;
+ float distance;
+ vec4_t projection, plane;
+ vec3_t origin, target, delta;
+ entity_t *e, *e2;
+ parseMesh_t *p;
+ mesh_t *mesh, *subdivided;
+ bspDrawVert_t *dv[ 4 ];
+ const char *value;
+
+
+ /* note it */
+ Sys_FPrintf( SYS_VRB, "--- ProcessDecals ---\n" );
+
+ /* walk entity list */
+ for ( i = 0; i < numEntities; i++ )
+ {
+ /* get entity */
+ e = &entities[ i ];
+ value = ValueForKey( e, "classname" );
+ if ( Q_stricmp( value, "_decal" ) ) {
+ continue;
+ }
+
+ /* any patches? */
+ if ( e->patches == NULL ) {
+ Sys_Printf( "WARNING: Decal entity without any patch meshes, ignoring.\n" );
+ e->epairs = NULL; /* fixme: leak! */
+ continue;
+ }
+
+ /* find target */
+ value = ValueForKey( e, "target" );
+ e2 = FindTargetEntity( value );
+
+ /* no target? */
+ if ( e2 == NULL ) {
+ Sys_Printf( "WARNING: Decal entity without a valid target, ignoring.\n" );
+ continue;
+ }
+
+ /* walk entity patches */
+ for ( p = e->patches; p != NULL; p = e->patches )
+ {
+ /* setup projector */
+ if ( VectorCompare( e->origin, vec3_origin ) ) {
+ VectorAdd( p->eMins, p->eMaxs, origin );
+ VectorScale( origin, 0.5f, origin );
+ }
+ else{
+ VectorCopy( e->origin, origin );
+ }
+
+ VectorCopy( e2->origin, target );
+ VectorSubtract( target, origin, delta );
+
+ /* setup projection plane */
+ distance = VectorNormalize( delta, projection );
+ projection[ 3 ] = DotProduct( origin, projection );
+
+ /* create projectors */
+ if ( distance > 0.125f ) {
+ /* tesselate the patch */
+ iterations = IterationsForCurve( p->longestCurve, patchSubdivisions );
+ subdivided = SubdivideMesh2( p->mesh, iterations );
+
+ /* fit it to the curve and remove colinear verts on rows/columns */
+ PutMeshOnCurve( *subdivided );
+ mesh = RemoveLinearMeshColumnsRows( subdivided );
+ FreeMesh( subdivided );
+
+ /* offset by projector origin */
+ for ( j = 0; j < ( mesh->width * mesh->height ); j++ )
+ VectorAdd( mesh->verts[ j ].xyz, e->origin, mesh->verts[ j ].xyz );
+
+ /* iterate through the mesh quads */
+ for ( y = 0; y < ( mesh->height - 1 ); y++ )
+ {
+ for ( x = 0; x < ( mesh->width - 1 ); x++ )
+ {
+ /* set indexes */
+ pw[ 0 ] = x + ( y * mesh->width );
+ pw[ 1 ] = x + ( ( y + 1 ) * mesh->width );
+ pw[ 2 ] = x + 1 + ( ( y + 1 ) * mesh->width );
+ pw[ 3 ] = x + 1 + ( y * mesh->width );
+ pw[ 4 ] = x + ( y * mesh->width ); /* same as pw[ 0 ] */
+
+ /* set radix */
+ r = ( x + y ) & 1;
+
+ /* get drawverts */
+ dv[ 0 ] = &mesh->verts[ pw[ r + 0 ] ];
+ dv[ 1 ] = &mesh->verts[ pw[ r + 1 ] ];
+ dv[ 2 ] = &mesh->verts[ pw[ r + 2 ] ];
+ dv[ 3 ] = &mesh->verts[ pw[ r + 3 ] ];
+
+ /* planar? (nuking this optimization as it doesn't work on non-rectangular quads) */
+ plane[ 0 ] = 0.0f; /* stupid msvc */
+ if ( 0 && PlaneFromPoints( plane, dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) &&
+ fabs( DotProduct( dv[ 1 ]->xyz, plane ) - plane[ 3 ] ) <= PLANAR_EPSILON ) {
+ /* make a quad projector */
+ MakeDecalProjector( p->shaderInfo, projection, distance, 4, dv );
+ }
+ else
+ {
+ /* make first triangle */
+ MakeDecalProjector( p->shaderInfo, projection, distance, 3, dv );
+
+ /* make second triangle */
+ dv[ 1 ] = dv[ 2 ];
+ dv[ 2 ] = dv[ 3 ];
+ MakeDecalProjector( p->shaderInfo, projection, distance, 3, dv );
+ }
+ }
+ }
+
+ /* clean up */
+ free( mesh );
+ }
+
+ /* remove patch from entity (fixme: leak!) */
+ e->patches = p->next;
+
+ /* push patch to worldspawn (enable this to debug projectors) */
+ #if 0
+ p->next = entities[ 0 ].patches;
+ entities[ 0 ].patches = p;
+ #endif
+ }
+ }
+
+ /* emit some stats */
+ Sys_FPrintf( SYS_VRB, "%9d decal projectors\n", numProjectors );
+}
+
+
+
+/*
+ ProjectDecalOntoWinding()
+ projects a decal onto a winding
+ */
+
+static void ProjectDecalOntoWinding( decalProjector_t *dp, mapDrawSurface_t *ds, winding_t *w ){
+ int i, j;
+ float d, d2, alpha;
+ winding_t *front, *back;
+ mapDrawSurface_t *ds2;
+ bspDrawVert_t *dv;
+ vec4_t plane;
+
+
+ /* dummy check */
+ if ( w->numpoints < 3 ) {
+ FreeWinding( w );
+ return;
+ }
+
+ /* offset by entity origin */
+ for ( i = 0; i < w->numpoints; i++ )
+ VectorAdd( w->p[ i ], entityOrigin, w->p[ i ] );
+
+ /* make a plane from the winding */
+ if ( !PlaneFromPoints( plane, w->p[ 0 ], w->p[ 1 ], w->p[ 2 ] ) ) {
+ FreeWinding( w );
+ return;
+ }
+
+ /* backface check */
+ d = DotProduct( dp->planes[ 0 ], plane );
+ if ( d < -0.0001f ) {
+ FreeWinding( w );
+ return;
+ }
+
+ /* walk list of planes */
+ for ( i = 0; i < dp->numPlanes; i++ )
+ {
+ /* chop winding by the plane */
+ ClipWindingEpsilonStrict( w, dp->planes[ i ], dp->planes[ i ][ 3 ], 0.0625f, &front, &back ); /* strict, if identical plane we don't want to keep it */
+ FreeWinding( w );
+
+ /* lose the front fragment */
+ if ( front != NULL ) {
+ FreeWinding( front );
+ }
+
+ /* if nothing left in back, then bail */
+ if ( back == NULL ) {
+ return;
+ }
+
+ /* reset winding */
+ w = back;
+ }
+
+ /* nothing left? */
+ if ( w == NULL || w->numpoints < 3 ) {
+ return;
+ }
+
+ /* add to counts */
+ numDecalSurfaces++;
+
+ /* make a new surface */
+ ds2 = AllocDrawSurface( SURFACE_DECAL );
+
+ /* set it up */
+ ds2->entityNum = ds->entityNum;
+ ds2->castShadows = ds->castShadows;
+ ds2->recvShadows = ds->recvShadows;
+ ds2->shaderInfo = dp->si;
+ ds2->fogNum = ds->fogNum; /* why was this -1? */
+ ds2->lightmapScale = ds->lightmapScale;
+ ds2->shadeAngleDegrees = ds->shadeAngleDegrees;
+ ds2->numVerts = w->numpoints;
+ ds2->verts = safe_malloc( ds2->numVerts * sizeof( *ds2->verts ) );
+ memset( ds2->verts, 0, ds2->numVerts * sizeof( *ds2->verts ) );
+
+ /* set vertexes */
+ for ( i = 0; i < ds2->numVerts; i++ )
+ {
+ /* get vertex */
+ dv = &ds2->verts[ i ];
+
+ /* set alpha */
+ d = DotProduct( w->p[ i ], dp->planes[ 0 ] ) - dp->planes[ 0 ][ 3 ];
+ d2 = DotProduct( w->p[ i ], dp->planes[ 1 ] ) - dp->planes[ 1 ][ 3 ];
+ alpha = 255.0f * d2 / ( d + d2 );
+ if ( alpha > 255 ) {
+ alpha = 255;
+ }
+ else if ( alpha < 0 ) {
+ alpha = 0;
+ }
+
+ /* set misc */
+ VectorSubtract( w->p[ i ], entityOrigin, dv->xyz );
+ VectorCopy( plane, dv->normal );
+ dv->st[ 0 ] = DotProduct( dv->xyz, dp->texMat[ 0 ] ) + dp->texMat[ 0 ][ 3 ];
+ dv->st[ 1 ] = DotProduct( dv->xyz, dp->texMat[ 1 ] ) + dp->texMat[ 1 ][ 3 ];
+
+ /* set color */
+ for ( j = 0; j < MAX_LIGHTMAPS; j++ )
+ {
+ dv->color[ j ][ 0 ] = 255;
+ dv->color[ j ][ 1 ] = 255;
+ dv->color[ j ][ 2 ] = 255;
+ dv->color[ j ][ 3 ] = alpha;
+ }
+ }
+}
+
+
+
+/*
+ ProjectDecalOntoFace()
+ projects a decal onto a brushface surface
+ */
+
+static void ProjectDecalOntoFace( decalProjector_t *dp, mapDrawSurface_t *ds ){
+ vec4_t plane;
+ float d;
+ winding_t *w;
+
+
+ /* dummy check */
+ if ( ds->sideRef == NULL || ds->sideRef->side == NULL ) {
+ return;
+ }
+
+ /* backface check */
+ if ( ds->planar ) {
+ VectorCopy( mapplanes[ ds->planeNum ].normal, plane );
+ plane[ 3 ] = mapplanes[ ds->planeNum ].dist + DotProduct( plane, entityOrigin );
+ d = DotProduct( dp->planes[ 0 ], plane );
+ if ( d < -0.0001f ) {
+ return;
+ }
+ }
+
+ /* generate decal */
+ w = WindingFromDrawSurf( ds );
+ ProjectDecalOntoWinding( dp, ds, w );
+}
+
+
+
+/*
+ ProjectDecalOntoPatch()
+ projects a decal onto a patch surface
+ */
+
+static void ProjectDecalOntoPatch( decalProjector_t *dp, mapDrawSurface_t *ds ){
+ int x, y, pw[ 5 ], r, iterations;
+ vec4_t plane;
+ float d;
+ mesh_t src, *mesh, *subdivided;
+ winding_t *w;
+
+
+ /* backface check */
+ if ( ds->planar ) {
+ VectorCopy( mapplanes[ ds->planeNum ].normal, plane );
+ plane[ 3 ] = mapplanes[ ds->planeNum ].dist + DotProduct( plane, entityOrigin );
+ d = DotProduct( dp->planes[ 0 ], plane );
+ if ( d < -0.0001f ) {
+ return;
+ }
+ }
+
+ /* tesselate the patch */
+ src.width = ds->patchWidth;
+ src.height = ds->patchHeight;
+ src.verts = ds->verts;
+ iterations = IterationsForCurve( ds->longestCurve, patchSubdivisions );
+ subdivided = SubdivideMesh2( src, iterations );
+
+ /* fit it to the curve and remove colinear verts on rows/columns */
+ PutMeshOnCurve( *subdivided );
+ mesh = RemoveLinearMeshColumnsRows( subdivided );
+ FreeMesh( subdivided );
+
+ /* iterate through the mesh quads */
+ for ( y = 0; y < ( mesh->height - 1 ); y++ )
+ {
+ for ( x = 0; x < ( mesh->width - 1 ); x++ )
+ {
+ /* set indexes */
+ pw[ 0 ] = x + ( y * mesh->width );
+ pw[ 1 ] = x + ( ( y + 1 ) * mesh->width );
+ pw[ 2 ] = x + 1 + ( ( y + 1 ) * mesh->width );
+ pw[ 3 ] = x + 1 + ( y * mesh->width );
+ pw[ 4 ] = x + ( y * mesh->width ); /* same as pw[ 0 ] */
+
+ /* set radix */
+ r = ( x + y ) & 1;
+
+ /* generate decal for first triangle */
+ w = AllocWinding( 3 );
+ w->numpoints = 3;
+ VectorCopy( mesh->verts[ pw[ r + 0 ] ].xyz, w->p[ 0 ] );
+ VectorCopy( mesh->verts[ pw[ r + 1 ] ].xyz, w->p[ 1 ] );
+ VectorCopy( mesh->verts[ pw[ r + 2 ] ].xyz, w->p[ 2 ] );
+ ProjectDecalOntoWinding( dp, ds, w );
+
+ /* generate decal for second triangle */
+ w = AllocWinding( 3 );
+ w->numpoints = 3;
+ VectorCopy( mesh->verts[ pw[ r + 0 ] ].xyz, w->p[ 0 ] );
+ VectorCopy( mesh->verts[ pw[ r + 2 ] ].xyz, w->p[ 1 ] );
+ VectorCopy( mesh->verts[ pw[ r + 3 ] ].xyz, w->p[ 2 ] );
+ ProjectDecalOntoWinding( dp, ds, w );
+ }
+ }
+
+ /* clean up */
+ free( mesh );
+}
+
+
+
+/*
+ ProjectDecalOntoTriangles()
+ projects a decal onto a triangle surface
+ */
+
+static void ProjectDecalOntoTriangles( decalProjector_t *dp, mapDrawSurface_t *ds ){
+ int i;
+ vec4_t plane;
+ float d;
+ winding_t *w;
+
+
+ /* triangle surfaces without shaders don't get marks by default */
+ if ( ds->type == SURFACE_TRIANGLES && ds->shaderInfo->shaderText == NULL ) {
+ return;
+ }
+
+ /* backface check */
+ if ( ds->planar ) {
+ VectorCopy( mapplanes[ ds->planeNum ].normal, plane );
+ plane[ 3 ] = mapplanes[ ds->planeNum ].dist + DotProduct( plane, entityOrigin );
+ d = DotProduct( dp->planes[ 0 ], plane );
+ if ( d < -0.0001f ) {
+ return;
+ }
+ }
+
+ /* iterate through triangles */
+ for ( i = 0; i < ds->numIndexes; i += 3 )
+ {
+ /* generate decal */
+ w = AllocWinding( 3 );
+ w->numpoints = 3;
+ VectorCopy( ds->verts[ ds->indexes[ i ] ].xyz, w->p[ 0 ] );
+ VectorCopy( ds->verts[ ds->indexes[ i + 1 ] ].xyz, w->p[ 1 ] );
+ VectorCopy( ds->verts[ ds->indexes[ i + 2 ] ].xyz, w->p[ 2 ] );
+ ProjectDecalOntoWinding( dp, ds, w );
+ }
+}
+
+
+
+/*
+ MakeEntityDecals()
+ projects decals onto world surfaces
+ */
+
+void MakeEntityDecals( entity_t *e ){
+ int i, j, k, f, fOld, start;
+ decalProjector_t dp;
+ mapDrawSurface_t *ds;
+ vec3_t identityAxis[ 3 ] = { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } };
+
+
+ /* note it */
+ Sys_FPrintf( SYS_VRB, "--- MakeEntityDecals ---\n" );
+
+ /* set entity origin */
+ VectorCopy( e->origin, entityOrigin );
+
+ /* transform projector instead of geometry */
+ VectorClear( entityOrigin );
+
+ /* init pacifier */
+ fOld = -1;
+ start = I_FloatTime();
+
+ /* walk the list of decal projectors */
+ for ( i = 0; i < numProjectors; i++ )
+ {
+ /* print pacifier */
+ f = 10 * i / numProjectors;
+ if ( f != fOld ) {
+ fOld = f;
+ Sys_FPrintf( SYS_VRB, "%d...", f );
+ }
+
+ /* get projector */
+ TransformDecalProjector( &projectors[ i ], identityAxis, e->origin, &dp );
+
+ /* walk the list of surfaces in the entity */
+ for ( j = e->firstDrawSurf; j < numMapDrawSurfs; j++ )
+ {
+ /* get surface */
+ ds = &mapDrawSurfs[ j ];
+ if ( ds->numVerts <= 0 ) {
+ continue;
+ }
+
+ /* ignore autosprite or nomarks */
+ if ( ds->shaderInfo->autosprite || ( ds->shaderInfo->compileFlags & C_NOMARKS ) ) {
+ continue;
+ }
+
+ /* bounds check */
+ for ( k = 0; k < 3; k++ )
+ if ( ds->mins[ k ] >= ( dp.center[ k ] + dp.radius ) ||
+ ds->maxs[ k ] <= ( dp.center[ k ] - dp.radius ) ) {
+ break;
+ }
+ if ( k < 3 ) {
+ continue;
+ }
+
+ /* switch on type */
+ switch ( ds->type )
+ {
+ case SURFACE_FACE:
+ ProjectDecalOntoFace( &dp, ds );
+ break;
+
+ case SURFACE_PATCH:
+ ProjectDecalOntoPatch( &dp, ds );
+ break;
+
+ case SURFACE_TRIANGLES:
+ case SURFACE_FORCED_META:
+ case SURFACE_META:
+ ProjectDecalOntoTriangles( &dp, ds );
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ /* print time */
+ Sys_FPrintf( SYS_VRB, " (%d)\n", (int) ( I_FloatTime() - start ) );
+
+ /* emit some stats */
+ Sys_FPrintf( SYS_VRB, "%9d decal surfaces\n", numDecalSurfaces );
+}