]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/q3map2/decals.c
transfer from internal tree r5311 branches/1.4-gpl
[xonotic/netradiant.git] / tools / quake3 / q3map2 / decals.c
1 /*\r
2 Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
3 For a list of contributors, see the accompanying CONTRIBUTORS file.\r
4 \r
5 This file is part of GtkRadiant.\r
6 \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
11 \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
16 \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
20 \r
21 ----------------------------------------------------------------------------------\r
22 \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
25 \r
26 ------------------------------------------------------------------------------- */\r
27 \r
28 \r
29 \r
30 /* marker */\r
31 #define DECALS_C\r
32 \r
33 \r
34 \r
35 /* dependencies */\r
36 #include "q3map2.h"\r
37 \r
38 \r
39 \r
40 #define MAX_PROJECTORS          1024\r
41 \r
42 typedef struct decalProjector_s\r
43 {\r
44         shaderInfo_t                    *si;\r
45         vec3_t                                  mins, maxs;\r
46         vec3_t                                  center;\r
47         float                                   radius, radius2;\r
48         int                                             numPlanes;      /* either 5 or 6, for quad or triangle projectors */\r
49         vec4_t                                  planes[ 6 ];\r
50         vec4_t                                  texMat[ 2 ];\r
51 }\r
52 decalProjector_t;\r
53 \r
54 static int                                      numProjectors = 0;\r
55 static decalProjector_t         projectors[ MAX_PROJECTORS ];\r
56 \r
57 static int                                      numDecalSurfaces = 0;\r
58 \r
59 static vec3_t                           entityOrigin;\r
60 \r
61 \r
62 \r
63 /*\r
64 DVectorNormalize()\r
65 normalizes a vector, returns the length, operates using doubles\r
66 */\r
67 \r
68 typedef double  dvec_t;\r
69 typedef dvec_t  dvec3_t[ 3 ];\r
70 \r
71 dvec_t DVectorNormalize( dvec3_t in, dvec3_t out )\r
72 {\r
73         dvec_t  len, ilen;\r
74         \r
75         \r
76         len = (dvec_t) sqrt( in[ 0 ] * in[ 0 ] + in[ 1 ] * in[ 1 ] + in[ 2 ] * in[ 2 ] );\r
77         if( len == 0.0 )\r
78         {\r
79                 VectorClear( out );\r
80                 return 0.0;\r
81         }\r
82         \r
83         ilen = 1.0 / len;\r
84         out[ 0 ] = in[ 0 ] * ilen;\r
85         out[ 1 ] = in[ 1 ] * ilen;\r
86         out[ 2 ] = in[ 2 ] * ilen;\r
87         \r
88         return len;\r
89 }\r
90 \r
91 \r
92 \r
93 /*\r
94 MakeTextureMatrix()\r
95 generates a texture projection matrix for a triangle\r
96 returns qfalse if a texture matrix cannot be created\r
97 */\r
98 \r
99 #define Vector2Subtract(a,b,c)  ((c)[ 0 ] = (a)[ 0 ] - (b)[ 0 ], (c)[ 1 ] = (a)[ 1 ] - (b)[ 1 ])\r
100 \r
101 static qboolean MakeTextureMatrix( decalProjector_t *dp, vec4_t projection, bspDrawVert_t *a, bspDrawVert_t *b, bspDrawVert_t *c )\r
102 {\r
103         int                     i, j;\r
104         double          bb, s, t, d;\r
105         dvec3_t         pa, pb, pc;\r
106         dvec3_t         bary, xyz;\r
107         dvec3_t         vecs[ 3 ], axis[ 3 ], lengths;\r
108         \r
109         \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
117         \r
118         /* two methods */\r
119         #if 1\r
120         {\r
121                 /* old code */\r
122                 \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
126                         return qfalse;\r
127                 \r
128                 /* calculate texture origin */\r
129                 #if 0\r
130                 s = 0.0;\r
131                 t = 0.0;\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
135                 \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
139                 #endif\r
140                 \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
147                 \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
151                 \r
152                 //%     VectorSubtract( xyz, origin, vecs[ 0 ] );\r
153                 VectorSubtract( xyz, pa, vecs[ 0 ] );\r
154                 \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
161                 \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
165                 \r
166                 //%     VectorSubtract( xyz, origin, vecs[ 1 ] );\r
167                 VectorSubtract( xyz, pa, vecs[ 1 ] );\r
168                 \r
169                 /* calcuate r vector */\r
170                 VectorScale( projection, -1.0, vecs[ 2 ] );\r
171                 \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
180                 \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
184         }\r
185         #else\r
186         {\r
187                 int                     k;\r
188                 dvec3_t         origin, deltas[ 3 ];\r
189                 double          texDeltas[ 3 ][ 2 ];\r
190                 double          delta, texDelta;\r
191                 \r
192                 \r
193                 /* new code */\r
194                 \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
202                 \r
203                 /* walk st */\r
204                 for( i = 0; i < 2; i++ )\r
205                 {\r
206                         /* walk xyz */\r
207                         for( j = 0; j < 3; j++ )\r
208                         {\r
209                                 /* clear deltas */\r
210                                 delta = 0.0;\r
211                                 texDelta = 0.0;\r
212                                 \r
213                                 /* walk deltas */\r
214                                 for( k = 0; k < 3; k++ )\r
215                                 {\r
216                                         if( fabs( deltas[ k ][ j ] ) > delta &&\r
217                                                 fabs( texDeltas[ k ][ i ] ) > texDelta  )\r
218                                         {\r
219                                                 delta = deltas[ k ][ j ];\r
220                                                 texDelta = texDeltas[ k ][ i ];\r
221                                         }\r
222                                 }\r
223                                 \r
224                                 /* set texture matrix component */\r
225                                 if( fabs( delta ) > 0.0 )\r
226                                         dp->texMat[ i ][ j ] = texDelta / delta;\r
227                                 else\r
228                                         dp->texMat[ i ][ j ] = 0.0;\r
229                         }\r
230                 \r
231                         /* set translation component */\r
232                         dp->texMat[ i ][ 3 ] = a->st[ i ] - DotProduct( pa, dp->texMat[ i ] );\r
233                 }\r
234         }\r
235         #endif\r
236         \r
237         /* debug code */\r
238         #if 1\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
244                 \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
249         #endif\r
250         \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
255         {\r
256                 Sys_Printf( "Bad texture matrix! (A) (%f, %f) != (%f, %f)\n",\r
257                         s, t, a->st[ 0 ], a->st[ 1 ] );\r
258                 //%     return qfalse;\r
259         }\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
263         {\r
264                 Sys_Printf( "Bad texture matrix! (B) (%f, %f) != (%f, %f)\n",\r
265                         s, t, b->st[ 0 ], b->st[ 1 ] );\r
266                 //%     return qfalse;\r
267         }\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
271         {\r
272                 Sys_Printf( "Bad texture matrix! (C) (%f, %f) != (%f, %f)\n",\r
273                         s, t, c->st[ 0 ], c->st[ 1 ] );\r
274                 //%     return qfalse;\r
275         }\r
276         \r
277         /* disco */\r
278         return qtrue;\r
279 }\r
280 \r
281 \r
282 \r
283 /*\r
284 TransformDecalProjector()\r
285 transforms a decal projector\r
286 note: non-normalized axes will screw up the plane transform\r
287 */\r
288 \r
289 static void TransformDecalProjector( decalProjector_t *in, vec3_t axis[ 3 ], vec3_t origin, decalProjector_t *out )\r
290 {\r
291         int             i;\r
292         \r
293         \r
294         /* copy misc stuff */\r
295         out->si = in->si;\r
296         out->numPlanes = in->numPlanes;\r
297         \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
304         \r
305         /* translate planes */\r
306         for( i = 0; i < in->numPlanes; i++ )\r
307         {\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
312         }\r
313         \r
314         /* translate texture matrix */\r
315         for( i = 0; i < 2; i++ )\r
316         {\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
321         }\r
322 }\r
323 \r
324 \r
325 \r
326 /*\r
327 MakeDecalProjector()\r
328 creates a new decal projector from a triangle\r
329 */\r
330 \r
331 static int MakeDecalProjector( shaderInfo_t *si, vec4_t projection, float distance, int numVerts, bspDrawVert_t **dv )\r
332 {\r
333         int                                     i, j;\r
334         decalProjector_t        *dp;\r
335         vec3_t                          xyz;\r
336         \r
337         \r
338         /* dummy check */\r
339         if( numVerts != 3 && numVerts != 4 )\r
340                 return -1;\r
341         \r
342         /* limit check */\r
343         if( numProjectors >= MAX_PROJECTORS )\r
344         {\r
345                 Sys_Printf( "WARNING: MAX_PROJECTORS (%d) exceeded, no more decal projectors available.\n", MAX_PROJECTORS );\r
346                 return -2;\r
347         }\r
348         \r
349         /* create a new projector */\r
350         dp = &projectors[ numProjectors ];\r
351         memset( dp, 0, sizeof( *dp ) );\r
352         \r
353         /* basic setup */\r
354         dp->si = si;\r
355         dp->numPlanes = numVerts + 2;\r
356         \r
357         /* make texture matrix */\r
358         if( !MakeTextureMatrix( dp, projection, dv[ 0 ], dv[ 1 ], dv[ 2 ] ) )\r
359                 return -1;\r
360         \r
361         /* bound the projector */\r
362         ClearBounds( dp->mins, dp->maxs );\r
363         for( i = 0; i < numVerts; i++ )\r
364         {\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
368         }\r
369         \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
376         \r
377         /* make the front plane */\r
378         if( !PlaneFromPoints( dp->planes[ 0 ], dv[ 0 ]->xyz, dv[ 1 ]->xyz, dv[ 2 ]->xyz ) )\r
379                 return -1;\r
380         \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
385         \r
386         /* make the side planes */\r
387         for( i = 0; i < numVerts; i++ )\r
388         {\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
392                         return -1;\r
393         }\r
394         \r
395         /* return ok */\r
396         numProjectors++;\r
397         return numProjectors - 1;\r
398 }\r
399 \r
400 \r
401 \r
402 /*\r
403 ProcessDecals()\r
404 finds all decal entities and creates decal projectors\r
405 */\r
406 \r
407 #define PLANAR_EPSILON  0.5f\r
408 \r
409 void ProcessDecals( void )\r
410 {\r
411         int                                     i, j, x, y, pw[ 5 ], r, iterations;\r
412         float                           distance;\r
413         vec4_t                          projection, plane;\r
414         vec3_t                          origin, target, delta;\r
415         entity_t                        *e, *e2;\r
416         parseMesh_t                     *p;\r
417         mesh_t                          *mesh, *subdivided;\r
418         bspDrawVert_t           *dv[ 4 ];\r
419         const char                      *value;\r
420         \r
421         \r
422         /* note it */\r
423         Sys_FPrintf( SYS_VRB, "--- ProcessDecals ---\n" );\r
424         \r
425         /* walk entity list */\r
426         for( i = 0; i < numEntities; i++ )\r
427         {\r
428                 /* get entity */\r
429                 e = &entities[ i ];\r
430                 value = ValueForKey( e, "classname" );\r
431                 if( Q_stricmp( value, "_decal" ) )\r
432                         continue;\r
433                 \r
434                 /* any patches? */\r
435                 if( e->patches == NULL )\r
436                 {\r
437                         Sys_Printf( "WARNING: Decal entity without any patch meshes, ignoring.\n" );\r
438                         e->epairs = NULL;       /* fixme: leak! */\r
439                         continue;\r
440                 }\r
441                 \r
442                 /* find target */\r
443                 value = ValueForKey( e, "target" );\r
444                 e2 = FindTargetEntity( value );\r
445                 \r
446                 /* no target? */\r
447                 if( e2 == NULL )\r
448                 {\r
449                         Sys_Printf( "WARNING: Decal entity without a valid target, ignoring.\n" );\r
450                         continue;\r
451                 }\r
452                 \r
453                 /* walk entity patches */\r
454                 for( p = e->patches; p != NULL; p = e->patches )\r
455                 {\r
456                         /* setup projector */\r
457                         if( VectorCompare( e->origin, vec3_origin ) )\r
458                         {\r
459                                 VectorAdd( p->eMins, p->eMaxs, origin );\r
460                                 VectorScale( origin, 0.5f, origin );\r
461                         }\r
462                         else\r
463                                 VectorCopy( e->origin, origin );\r
464                         \r
465                         VectorCopy( e2->origin, target );\r
466                         VectorSubtract( target, origin, delta );\r
467                         \r
468                         /* setup projection plane */\r
469                         distance = VectorNormalize( delta, projection );\r
470                         projection[ 3 ] = DotProduct( origin, projection );\r
471                         \r
472                         /* create projectors */\r
473                         if( distance > 0.125f )\r
474                         {\r
475                                 /* tesselate the patch */\r
476                                 iterations = IterationsForCurve( p->longestCurve, patchSubdivisions );\r
477                                 subdivided = SubdivideMesh2( p->mesh, iterations );\r
478                                 \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
483                                 \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
487                                 \r
488                                 /* iterate through the mesh quads */\r
489                                 for( y = 0; y < (mesh->height - 1); y++ )\r
490                                 {\r
491                                         for( x = 0; x < (mesh->width - 1); x++ )\r
492                                         {\r
493                                                 /* set indexes */\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
499                                                 \r
500                                                 /* set radix */\r
501                                                 r = (x + y) & 1;\r
502                                                 \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
508                                                 \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
513                                                 {\r
514                                                         /* make a quad projector */\r
515                                                         MakeDecalProjector( p->shaderInfo, projection, distance, 4, dv );\r
516                                                 }\r
517                                                 else\r
518                                                 {\r
519                                                         /* make first triangle */\r
520                                                         MakeDecalProjector( p->shaderInfo, projection, distance, 3, dv );\r
521                                                         \r
522                                                         /* make second triangle */\r
523                                                         dv[ 1 ] = dv[ 2 ];\r
524                                                         dv[ 2 ] = dv[ 3 ];\r
525                                                         MakeDecalProjector( p->shaderInfo, projection, distance, 3, dv );\r
526                                                 }\r
527                                         }\r
528                                 }\r
529                                 \r
530                                 /* clean up */\r
531                                 free( mesh );\r
532                         }\r
533                         \r
534                         /* remove patch from entity (fixme: leak!) */\r
535                         e->patches = p->next;\r
536                         \r
537                         /* push patch to worldspawn (enable this to debug projectors) */\r
538                         #if 0\r
539                                 p->next = entities[ 0 ].patches;\r
540                                 entities[ 0 ].patches = p;\r
541                         #endif\r
542                 }\r
543         }\r
544         \r
545         /* emit some stats */\r
546         Sys_FPrintf( SYS_VRB, "%9d decal projectors\n", numProjectors );\r
547 }\r
548 \r
549 \r
550 \r
551 /*\r
552 ProjectDecalOntoWinding()\r
553 projects a decal onto a winding\r
554 */\r
555 \r
556 static void ProjectDecalOntoWinding( decalProjector_t *dp, mapDrawSurface_t *ds, winding_t *w )\r
557 {\r
558         int                                     i, j;\r
559         float                           d, d2, alpha;\r
560         winding_t                       *front, *back;\r
561         mapDrawSurface_t        *ds2;\r
562         bspDrawVert_t           *dv;\r
563         vec4_t                          plane;\r
564         \r
565         \r
566         /* dummy check */\r
567         if( w->numpoints < 3 )\r
568         {\r
569                 FreeWinding( w );\r
570                 return;\r
571         }\r
572         \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
576         \r
577         /* make a plane from the winding */\r
578         if( !PlaneFromPoints( plane, w->p[ 0 ], w->p[ 1 ], w->p[ 2 ] ) )\r
579         {\r
580                 FreeWinding( w );\r
581                 return;\r
582         }\r
583         \r
584         /* backface check */\r
585         d = DotProduct( dp->planes[ 0 ], plane );\r
586         if( d < -0.0001f )\r
587         {\r
588                 FreeWinding( w );\r
589                 return;\r
590         }\r
591         \r
592         /* walk list of planes */\r
593         for( i = 0; i < dp->numPlanes; i++ )\r
594         {\r
595                 /* chop winding by the plane */\r
596                 ClipWindingEpsilon( w, dp->planes[ i ], dp->planes[ i ][ 3 ], 0.0625f, &front, &back );\r
597                 FreeWinding( w );\r
598                 \r
599                 /* lose the front fragment */\r
600                 if( front != NULL )\r
601                         FreeWinding( front );\r
602                 \r
603                 /* if nothing left in back, then bail */\r
604                 if( back == NULL )\r
605                         return;\r
606                 \r
607                 /* reset winding */\r
608                 w = back;\r
609         }\r
610         \r
611         /* nothing left? */\r
612         if( w == NULL || w->numpoints < 3 )\r
613                 return;\r
614         \r
615         /* add to counts */\r
616         numDecalSurfaces++;\r
617         \r
618         /* make a new surface */\r
619         ds2 = AllocDrawSurface( SURFACE_DECAL );\r
620         \r
621         /* set it up */\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
631         \r
632         /* set vertexes */\r
633         for( i = 0; i < ds2->numVerts; i++ )\r
634         {\r
635                 /* get vertex */\r
636                 dv = &ds2->verts[ i ];\r
637                 \r
638                 /* set alpha */\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
642                 if( alpha > 255 )\r
643                         alpha = 255;\r
644                 else if( alpha < 0 )\r
645                         alpha = 0;\r
646                 \r
647                 /* set misc */\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
652                 \r
653                 /* set color */\r
654                 for( j = 0; j < MAX_LIGHTMAPS; j++ )\r
655                 {\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
660                 }\r
661         }\r
662         \r
663         /* ydnar: finish the surface */\r
664         FinishSurface( ds2 );\r
665 }\r
666 \r
667 \r
668 \r
669 /*\r
670 ProjectDecalOntoFace()\r
671 projects a decal onto a brushface surface\r
672 */\r
673 \r
674 static void ProjectDecalOntoFace( decalProjector_t *dp, mapDrawSurface_t *ds )\r
675 {\r
676         vec4_t          plane;\r
677         float           d;\r
678         winding_t       *w;\r
679         \r
680         \r
681         /* dummy check */\r
682         if( ds->sideRef == NULL || ds->sideRef->side == NULL )\r
683                 return;\r
684         \r
685         /* backface check */\r
686         if( ds->planar )\r
687         {\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
691                 if( d < -0.0001f )\r
692                         return;\r
693         }\r
694         \r
695         /* generate decal */\r
696         w = WindingFromDrawSurf( ds );\r
697         ProjectDecalOntoWinding( dp, ds, w );\r
698 }\r
699 \r
700 \r
701 \r
702 /*\r
703 ProjectDecalOntoPatch()\r
704 projects a decal onto a patch surface\r
705 */\r
706 \r
707 static void ProjectDecalOntoPatch( decalProjector_t *dp, mapDrawSurface_t *ds )\r
708 {\r
709         int                     x, y, pw[ 5 ], r, iterations;\r
710         vec4_t          plane;\r
711         float           d;\r
712         mesh_t          src, *mesh, *subdivided;\r
713         winding_t       *w;\r
714         \r
715         \r
716         /* backface check */\r
717         if( ds->planar )\r
718         {\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
722                 if( d < -0.0001f )\r
723                         return;\r
724         }\r
725         \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
732         \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
737         \r
738         /* iterate through the mesh quads */\r
739         for( y = 0; y < (mesh->height - 1); y++ )\r
740         {\r
741                 for( x = 0; x < (mesh->width - 1); x++ )\r
742                 {\r
743                         /* set indexes */\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
749                         \r
750                         /* set radix */\r
751                         r = (x + y) & 1;\r
752                         \r
753                         /* generate decal for first triangle */\r
754                         w = AllocWinding( 3 );\r
755                         w->numpoints = 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
760                         \r
761                         /* generate decal for second triangle */\r
762                         w = AllocWinding( 3 );\r
763                         w->numpoints = 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
768                 }\r
769         }\r
770         \r
771         /* clean up */\r
772         free( mesh );\r
773 }\r
774 \r
775 \r
776 \r
777 /*\r
778 ProjectDecalOntoTriangles()\r
779 projects a decal onto a triangle surface\r
780 */\r
781 \r
782 static void ProjectDecalOntoTriangles( decalProjector_t *dp, mapDrawSurface_t *ds )\r
783 {\r
784         int                     i;\r
785         vec4_t          plane;\r
786         float           d;\r
787         winding_t       *w;\r
788         \r
789         \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
793                 return;\r
794         \r
795         /* backface check */\r
796         if( ds->planar )\r
797         {\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
801                 if( d < -0.0001f )\r
802                         return;\r
803         }\r
804         \r
805         /* iterate through triangles */\r
806         for( i = 0; i < ds->numIndexes; i += 3 )\r
807         {\r
808                 /* generate decal */\r
809                 w = AllocWinding( 3 );\r
810                 w->numpoints = 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
815         }\r
816 }\r
817 \r
818 \r
819 \r
820 /*\r
821 MakeEntityDecals()\r
822 projects decals onto world surfaces\r
823 */\r
824 \r
825 void MakeEntityDecals( entity_t *e )\r
826 {\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
831         \r
832         \r
833         /* note it */\r
834         Sys_FPrintf( SYS_VRB, "--- MakeEntityDecals ---\n" );\r
835         \r
836         /* set entity origin */\r
837         VectorCopy( e->origin, entityOrigin );\r
838         \r
839         /* transform projector instead of geometry */\r
840         VectorClear( entityOrigin );\r
841         \r
842         /* init pacifier */\r
843         fOld = -1;\r
844         start = I_FloatTime();\r
845         \r
846         /* walk the list of decal projectors */\r
847         for( i = 0; i < numProjectors; i++ )\r
848         {\r
849                 /* print pacifier */\r
850                 f = 10 * i / numProjectors;\r
851                 if( f != fOld )\r
852                 {\r
853                         fOld = f;\r
854                         Sys_FPrintf( SYS_VRB, "%d...", f );\r
855                 }\r
856                 \r
857                 /* get projector */\r
858                 TransformDecalProjector( &projectors[ i ], identityAxis, e->origin, &dp );\r
859                 \r
860                 /* walk the list of surfaces in the entity */\r
861                 for( j = e->firstDrawSurf; j < numMapDrawSurfs; j++ )\r
862                 {\r
863                         /* get surface */\r
864                         ds = &mapDrawSurfs[ j ];\r
865                         if( ds->numVerts <= 0 )\r
866                                 continue;\r
867                         \r
868                         /* ignore autosprite or nomarks */\r
869                         if( ds->shaderInfo->autosprite || (ds->shaderInfo->compileFlags & C_NOMARKS) )\r
870                                 continue;\r
871                         \r
872                         /* bounds check */\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
876                                         break;\r
877                         if( k < 3 )\r
878                                 continue;\r
879                         \r
880                         /* switch on type */\r
881                         switch( ds->type )\r
882                         {\r
883                                 case SURFACE_FACE:\r
884                                         ProjectDecalOntoFace( &dp, ds );\r
885                                         break;\r
886                                 \r
887                                 case SURFACE_PATCH:\r
888                                         ProjectDecalOntoPatch( &dp, ds );\r
889                                         break;\r
890                                 \r
891                                 case SURFACE_TRIANGLES:\r
892                                 case SURFACE_FORCED_META:\r
893                                 case SURFACE_META:\r
894                                         ProjectDecalOntoTriangles( &dp, ds );\r
895                                         break;\r
896                                 \r
897                                 default:\r
898                                         break;\r
899                         }\r
900                 }\r
901         }\r
902         \r
903         /* print time */\r
904         Sys_FPrintf( SYS_VRB, " (%d)\n", (int) (I_FloatTime() - start) );\r
905         \r
906         /* emit some stats */\r
907         Sys_FPrintf( SYS_VRB, "%9d decal surfaces\n", numDecalSurfaces );\r
908 }\r