1 /*
2 ===========================================================================
3
4 Return to Castle Wolfenstein single player GPL Source Code
5 Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
6
7 This file is part of the Return to Castle Wolfenstein single player GPL Source Code (RTCW SP Source Code).
8
9 RTCW SP Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 RTCW SP Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with RTCW SP Source Code. If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the RTCW SP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW SP Source Code. If not, please request a copy in writing from id Software at the address below.
23
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25
26 ===========================================================================
27 */
28
29 // tr_marks.c -- polygon projection on the world polygons
30
31 #include "tr_local.h"
32 //#include "assert.h"
33
34 #define MAX_VERTS_ON_POLY 64
35
36 #define MARKER_OFFSET 0 // 1
37
38 // Ridah, just make these global to prevent having to add more paramaters, which add overhead
39 static vec3_t bestnormal;
40 static float bestdist;
41
42 /*
43 =============
44 R_ChopPolyBehindPlane
45
46 Out must have space for two more vertexes than in
47 =============
48 */
49 #define SIDE_FRONT 0
50 #define SIDE_BACK 1
51 #define SIDE_ON 2
R_ChopPolyBehindPlane(int numInPoints,vec3_t inPoints[MAX_VERTS_ON_POLY],int * numOutPoints,vec3_t outPoints[MAX_VERTS_ON_POLY],vec3_t normal,vec_t dist,vec_t epsilon)52 static void R_ChopPolyBehindPlane( int numInPoints, vec3_t inPoints[MAX_VERTS_ON_POLY],
53 int *numOutPoints, vec3_t outPoints[MAX_VERTS_ON_POLY],
54 vec3_t normal, vec_t dist, vec_t epsilon ) {
55 float dists[MAX_VERTS_ON_POLY + 4] = { 0 };
56 int sides[MAX_VERTS_ON_POLY + 4] = { 0 };
57 int counts[3];
58 float dot;
59 int i, j;
60 float *p1, *p2, *clip;
61 float d;
62
63 // don't clip if it might overflow
64 if ( numInPoints >= MAX_VERTS_ON_POLY - 2 ) {
65 *numOutPoints = 0;
66 return;
67 }
68
69 counts[0] = counts[1] = counts[2] = 0;
70
71 // determine sides for each point
72 for ( i = 0 ; i < numInPoints ; i++ ) {
73 dot = DotProduct( inPoints[i], normal );
74 dot -= dist;
75 dists[i] = dot;
76 if ( dot > epsilon ) {
77 sides[i] = SIDE_FRONT;
78 } else if ( dot < -epsilon ) {
79 sides[i] = SIDE_BACK;
80 } else {
81 sides[i] = SIDE_ON;
82 }
83 counts[sides[i]]++;
84 }
85 sides[i] = sides[0];
86 dists[i] = dists[0];
87
88 *numOutPoints = 0;
89
90 if ( !counts[0] ) {
91 return;
92 }
93 if ( !counts[1] ) {
94 *numOutPoints = numInPoints;
95 memcpy( outPoints, inPoints, numInPoints * sizeof( vec3_t ) );
96 return;
97 }
98
99 for ( i = 0 ; i < numInPoints ; i++ ) {
100 p1 = inPoints[i];
101 clip = outPoints[ *numOutPoints ];
102
103 if ( sides[i] == SIDE_ON ) {
104 VectorCopy( p1, clip );
105 ( *numOutPoints )++;
106 continue;
107 }
108
109 if ( sides[i] == SIDE_FRONT ) {
110 VectorCopy( p1, clip );
111 ( *numOutPoints )++;
112 clip = outPoints[ *numOutPoints ];
113 }
114
115 if ( sides[i + 1] == SIDE_ON || sides[i + 1] == sides[i] ) {
116 continue;
117 }
118
119 // generate a split point
120 p2 = inPoints[ ( i + 1 ) % numInPoints ];
121
122 d = dists[i] - dists[i + 1];
123 if ( d == 0 ) {
124 dot = 0;
125 } else {
126 dot = dists[i] / d;
127 }
128
129 // clip xyz
130
131 for ( j = 0 ; j < 3 ; j++ ) {
132 clip[j] = p1[j] + dot * ( p2[j] - p1[j] );
133 }
134
135 ( *numOutPoints )++;
136 }
137 }
138
139 /*
140 =================
141 R_BoxSurfaces_r
142
143 =================
144 */
R_BoxSurfaces_r(mnode_t * node,vec3_t mins,vec3_t maxs,surfaceType_t ** list,int listsize,int * listlength,vec3_t dir)145 void R_BoxSurfaces_r( mnode_t *node, vec3_t mins, vec3_t maxs, surfaceType_t **list, int listsize, int *listlength, vec3_t dir ) {
146
147 int s, c;
148 msurface_t *surf, **mark;
149
150 // RF, if this node hasn't been rendered recently, ignore it
151 if ( node->visframe < tr.visCount - 2 ) { // allow us to be a few frames behind
152 return;
153 }
154
155 // do the tail recursion in a loop
156 while ( node->contents == -1 ) {
157 s = BoxOnPlaneSide( mins, maxs, node->plane );
158 if ( s == 1 ) {
159 node = node->children[0];
160 } else if ( s == 2 ) {
161 node = node->children[1];
162 } else {
163 R_BoxSurfaces_r( node->children[0], mins, maxs, list, listsize, listlength, dir );
164 node = node->children[1];
165 }
166 }
167
168 // Ridah, don't mark alpha surfaces
169 if ( node->contents & CONTENTS_TRANSLUCENT ) {
170 return;
171 }
172
173 // add the individual surfaces
174 mark = node->firstmarksurface;
175 c = node->nummarksurfaces;
176 while ( c-- ) {
177 //
178 if ( *listlength >= listsize ) {
179 break;
180 }
181 //
182 surf = *mark;
183 // check if the surface has NOIMPACT or NOMARKS set
184 if ( ( surf->shader->surfaceFlags & ( SURF_NOIMPACT | SURF_NOMARKS ) )
185 || ( surf->shader->contentFlags & CONTENTS_FOG ) ) {
186 surf->viewCount = tr.viewCount;
187 }
188 // extra check for surfaces to avoid list overflows
189 else if ( *( surf->data ) == SF_FACE ) {
190 // the face plane should go through the box
191 s = BoxOnPlaneSide( mins, maxs, &( ( srfSurfaceFace_t * ) surf->data )->plane );
192 if ( s == 1 || s == 2 ) {
193 surf->viewCount = tr.viewCount;
194 } else if ( DotProduct( ( ( srfSurfaceFace_t * ) surf->data )->plane.normal, dir ) < -0.5 ) {
195 // don't add faces that make sharp angles with the projection direction
196 surf->viewCount = tr.viewCount;
197 }
198 }
199 else if (*(surfaceType_t *) (surf->data) != SF_GRID &&
200 *(surfaceType_t *) (surf->data) != SF_TRIANGLES)
201 surf->viewCount = tr.viewCount;
202 // check the viewCount because the surface may have
203 // already been added if it spans multiple leafs
204 if ( surf->viewCount != tr.viewCount ) {
205 surf->viewCount = tr.viewCount;
206 list[*listlength] = (surfaceType_t *) surf->data;
207 ( *listlength )++;
208 }
209 mark++;
210 }
211 }
212
213 /*
214 =================
215 R_AddMarkFragments
216
217 =================
218 */
R_AddMarkFragments(int numClipPoints,vec3_t clipPoints[2][MAX_VERTS_ON_POLY],int numPlanes,vec3_t * normals,float * dists,int maxPoints,vec3_t pointBuffer,int maxFragments,markFragment_t * fragmentBuffer,int * returnedPoints,int * returnedFragments,vec3_t mins,vec3_t maxs)219 void R_AddMarkFragments( int numClipPoints, vec3_t clipPoints[2][MAX_VERTS_ON_POLY],
220 int numPlanes, vec3_t *normals, float *dists,
221 int maxPoints, vec3_t pointBuffer,
222 int maxFragments, markFragment_t *fragmentBuffer,
223 int *returnedPoints, int *returnedFragments,
224 vec3_t mins, vec3_t maxs ) {
225 int pingPong, i;
226 markFragment_t *mf;
227
228 // chop the surface by all the bounding planes of the to be projected polygon
229 pingPong = 0;
230
231 for ( i = 0 ; i < numPlanes ; i++ ) {
232
233 R_ChopPolyBehindPlane( numClipPoints, clipPoints[pingPong],
234 &numClipPoints, clipPoints[!pingPong],
235 normals[i], dists[i], 0.5 );
236 pingPong ^= 1;
237 if ( numClipPoints == 0 ) {
238 break;
239 }
240 }
241 // completely clipped away?
242 if ( numClipPoints == 0 ) {
243 return;
244 }
245
246 // add this fragment to the returned list
247 if ( numClipPoints + ( *returnedPoints ) > maxPoints ) {
248 return; // not enough space for this polygon
249 }
250 /*
251 // all the clip points should be within the bounding box
252 for ( i = 0 ; i < numClipPoints ; i++ ) {
253 int j;
254 for ( j = 0 ; j < 3 ; j++ ) {
255 if (clipPoints[pingPong][i][j] < mins[j] - 0.5) break;
256 if (clipPoints[pingPong][i][j] > maxs[j] + 0.5) break;
257 }
258 if (j < 3) break;
259 }
260 if (i < numClipPoints) return;
261 */
262
263 mf = fragmentBuffer + ( *returnedFragments );
264 mf->firstPoint = ( *returnedPoints );
265 mf->numPoints = numClipPoints;
266 //memcpy( pointBuffer + (*returnedPoints) * 3, clipPoints[pingPong], numClipPoints * sizeof(vec3_t) );
267 for ( i = 0; i < numClipPoints; i++ ) {
268 VectorCopy( clipPoints[pingPong][i], (float *)pointBuffer + 5 * ( *returnedPoints + i ) );
269 }
270
271 ( *returnedPoints ) += numClipPoints;
272 ( *returnedFragments )++;
273 }
274
275 /*
276 =================
277 R_OldMarkFragments
278
279 =================
280 */
R_OldMarkFragments(int numPoints,const vec3_t * points,const vec3_t projection,int maxPoints,vec3_t pointBuffer,int maxFragments,markFragment_t * fragmentBuffer)281 int R_OldMarkFragments( int numPoints, const vec3_t *points, const vec3_t projection,
282 int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ) {
283 int numsurfaces, numPlanes;
284 int i, j, k, m, n;
285 surfaceType_t *surfaces[64];
286 vec3_t mins, maxs;
287 int returnedFragments;
288 int returnedPoints;
289 vec3_t normals[MAX_VERTS_ON_POLY + 2];
290 float dists[MAX_VERTS_ON_POLY + 2];
291 vec3_t clipPoints[2][MAX_VERTS_ON_POLY];
292 int numClipPoints;
293 float *v;
294 srfGridMesh_t *cv;
295 drawVert_t *dv;
296 vec3_t normal;
297 vec3_t projectionDir;
298 vec3_t v1, v2;
299 int *indexes;
300
301 if (numPoints <= 0) {
302 return 0;
303 }
304
305 //increment view count for double check prevention
306 tr.viewCount++;
307
308 //
309 VectorNormalize2( projection, projectionDir );
310 // find all the brushes that are to be considered
311 ClearBounds( mins, maxs );
312 for ( i = 0 ; i < numPoints ; i++ ) {
313 vec3_t temp;
314
315 AddPointToBounds( points[i], mins, maxs );
316 VectorAdd( points[i], projection, temp );
317 AddPointToBounds( temp, mins, maxs );
318 // make sure we get all the leafs (also the one(s) in front of the hit surface)
319 VectorMA( points[i], -20, projectionDir, temp );
320 AddPointToBounds( temp, mins, maxs );
321 }
322
323 if ( numPoints > MAX_VERTS_ON_POLY ) {
324 numPoints = MAX_VERTS_ON_POLY;
325 }
326 // create the bounding planes for the to be projected polygon
327 for ( i = 0 ; i < numPoints ; i++ ) {
328 VectorSubtract( points[( i + 1 ) % numPoints], points[i], v1 );
329 VectorAdd( points[i], projection, v2 );
330 VectorSubtract( points[i], v2, v2 );
331 CrossProduct( v1, v2, normals[i] );
332 VectorNormalizeFast( normals[i] );
333 dists[i] = DotProduct( normals[i], points[i] );
334 }
335 // add near and far clipping planes for projection
336 VectorCopy( projectionDir, normals[numPoints] );
337 dists[numPoints] = DotProduct( normals[numPoints], points[0] ) - 32;
338 VectorCopy( projectionDir, normals[numPoints + 1] );
339 VectorInverse( normals[numPoints + 1] );
340 dists[numPoints + 1] = DotProduct( normals[numPoints + 1], points[0] ) - 20;
341 numPlanes = numPoints + 2;
342
343 numsurfaces = 0;
344 R_BoxSurfaces_r( tr.world->nodes, mins, maxs, surfaces, 64, &numsurfaces, projectionDir );
345 //assert(numsurfaces <= 64);
346 //assert(numsurfaces != 64);
347
348 returnedPoints = 0;
349 returnedFragments = 0;
350
351 for ( i = 0 ; i < numsurfaces ; i++ ) {
352
353 if ( *surfaces[i] == SF_GRID ) {
354
355 cv = (srfGridMesh_t *) surfaces[i];
356 for ( m = 0 ; m < cv->height - 1 ; m++ ) {
357 for ( n = 0 ; n < cv->width - 1 ; n++ ) {
358 // We triangulate the grid and chop all triangles within
359 // the bounding planes of the to be projected polygon.
360 // LOD is not taken into account, not such a big deal though.
361 //
362 // It's probably much nicer to chop the grid itself and deal
363 // with this grid as a normal SF_GRID surface so LOD will
364 // be applied. However the LOD of that chopped grid must
365 // be synced with the LOD of the original curve.
366 // One way to do this; the chopped grid shares vertices with
367 // the original curve. When LOD is applied to the original
368 // curve the unused vertices are flagged. Now the chopped curve
369 // should skip the flagged vertices. This still leaves the
370 // problems with the vertices at the chopped grid edges.
371 //
372 // To avoid issues when LOD applied to "hollow curves" (like
373 // the ones around many jump pads) we now just add a 2 unit
374 // offset to the triangle vertices.
375 // The offset is added in the vertex normal vector direction
376 // so all triangles will still fit together.
377 // The 2 unit offset should avoid pretty much all LOD problems.
378
379 numClipPoints = 3;
380
381 dv = cv->verts + m * cv->width + n;
382
383 VectorCopy( dv[0].xyz, clipPoints[0][0] );
384 VectorMA( clipPoints[0][0], MARKER_OFFSET, dv[0].normal, clipPoints[0][0] );
385 VectorCopy( dv[cv->width].xyz, clipPoints[0][1] );
386 VectorMA( clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1] );
387 VectorCopy( dv[1].xyz, clipPoints[0][2] );
388 VectorMA( clipPoints[0][2], MARKER_OFFSET, dv[1].normal, clipPoints[0][2] );
389 // check the normal of this triangle
390 VectorSubtract( clipPoints[0][0], clipPoints[0][1], v1 );
391 VectorSubtract( clipPoints[0][2], clipPoints[0][1], v2 );
392 CrossProduct( v1, v2, normal );
393 VectorNormalizeFast( normal );
394 if ( DotProduct( normal, projectionDir ) < -0.1 ) {
395 // add the fragments of this triangle
396 R_AddMarkFragments( numClipPoints, clipPoints,
397 numPlanes, normals, dists,
398 maxPoints, pointBuffer,
399 maxFragments, fragmentBuffer,
400 &returnedPoints, &returnedFragments, mins, maxs );
401
402 if ( returnedFragments == maxFragments ) {
403 return returnedFragments; // not enough space for more fragments
404 }
405 }
406
407 VectorCopy( dv[1].xyz, clipPoints[0][0] );
408 VectorMA( clipPoints[0][0], MARKER_OFFSET, dv[1].normal, clipPoints[0][0] );
409 VectorCopy( dv[cv->width].xyz, clipPoints[0][1] );
410 VectorMA( clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1] );
411 VectorCopy( dv[cv->width + 1].xyz, clipPoints[0][2] );
412 VectorMA( clipPoints[0][2], MARKER_OFFSET, dv[cv->width + 1].normal, clipPoints[0][2] );
413 // check the normal of this triangle
414 VectorSubtract( clipPoints[0][0], clipPoints[0][1], v1 );
415 VectorSubtract( clipPoints[0][2], clipPoints[0][1], v2 );
416 CrossProduct( v1, v2, normal );
417 VectorNormalizeFast( normal );
418 if ( DotProduct( normal, projectionDir ) < -0.05 ) {
419 // add the fragments of this triangle
420 R_AddMarkFragments( numClipPoints, clipPoints,
421 numPlanes, normals, dists,
422 maxPoints, pointBuffer,
423 maxFragments, fragmentBuffer,
424 &returnedPoints, &returnedFragments, mins, maxs );
425
426 if ( returnedFragments == maxFragments ) {
427 return returnedFragments; // not enough space for more fragments
428 }
429 }
430 }
431 }
432 } else if ( *surfaces[i] == SF_FACE ) {
433
434 srfSurfaceFace_t *surf = ( srfSurfaceFace_t * ) surfaces[i];
435 // check the normal of this face
436 if ( DotProduct( surf->plane.normal, projectionDir ) > -0.5 ) {
437 continue;
438 }
439
440 indexes = ( int * )( (byte *)surf + surf->ofsIndices );
441 for ( k = 0 ; k < surf->numIndices ; k += 3 ) {
442 for ( j = 0 ; j < 3 ; j++ ) {
443 v = &surf->points[0][0] + VERTEXSIZE * indexes[k + j];
444 VectorMA( v, MARKER_OFFSET, surf->plane.normal, clipPoints[0][j] );
445 }
446 // add the fragments of this face
447 R_AddMarkFragments( 3, clipPoints,
448 numPlanes, normals, dists,
449 maxPoints, pointBuffer,
450 maxFragments, fragmentBuffer,
451 &returnedPoints, &returnedFragments, mins, maxs );
452 if ( returnedFragments == maxFragments ) {
453 return returnedFragments; // not enough space for more fragments
454 }
455 }
456 }
457 else if(*surfaces[i] == SF_TRIANGLES && r_marksOnTriangleMeshes->integer) {
458
459 srfTriangles_t *surf = (srfTriangles_t *) surfaces[i];
460
461 for (k = 0; k < surf->numIndexes; k += 3)
462 {
463 for(j = 0; j < 3; j++)
464 {
465 v = surf->verts[surf->indexes[k + j]].xyz;
466 VectorMA(v, MARKER_OFFSET, surf->verts[surf->indexes[k + j]].normal, clipPoints[0][j]);
467 }
468
469 // add the fragments of this face
470 R_AddMarkFragments(3, clipPoints,
471 numPlanes, normals, dists,
472 maxPoints, pointBuffer,
473 maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs);
474 if(returnedFragments == maxFragments)
475 {
476 return returnedFragments; // not enough space for more fragments
477 }
478 }
479 }
480 }
481 return returnedFragments;
482 }
483
484 /*
485 =================
486 R_MarkFragments
487
488 =================
489 */
R_MarkFragments(int orientation,const vec3_t * points,const vec3_t projection,int maxPoints,vec3_t pointBuffer,int maxFragments,markFragment_t * fragmentBuffer)490 int R_MarkFragments( int orientation, const vec3_t *points, const vec3_t projection,
491 int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ) {
492 int numsurfaces, numPlanes;
493 int i, j, k, m, n;
494 surfaceType_t *surfaces[4096];
495 vec3_t mins, maxs;
496 int returnedFragments;
497 int returnedPoints;
498 vec3_t normals[MAX_VERTS_ON_POLY + 2];
499 float dists[MAX_VERTS_ON_POLY + 2];
500 vec3_t clipPoints[2][MAX_VERTS_ON_POLY];
501 int numClipPoints;
502 float *v;
503 srfGridMesh_t *cv;
504 drawVert_t *dv;
505 vec3_t normal;
506 vec3_t projectionDir;
507 vec3_t v1, v2;
508 int *indexes;
509 float radius;
510 vec3_t center; // center of original mark
511 int numPoints = 4; // Ridah, we were only ever passing in 4, so I made this local and used the parameter for the orientation
512 qboolean oldMapping = qfalse;
513
514 if (numPoints <= 0) {
515 return 0;
516 }
517
518 //increment view count for double check prevention
519 tr.viewCount++;
520
521 // RF, negative maxFragments means we want original mapping
522 if ( maxFragments < 0 ) {
523 maxFragments = -maxFragments;
524 oldMapping = qtrue;
525 }
526
527 VectorClear( center );
528 for ( i = 0 ; i < numPoints ; i++ ) {
529 VectorAdd( points[i], center, center );
530 }
531 VectorScale( center, 1.0 / numPoints, center );
532 //
533 radius = VectorNormalize2( projection, projectionDir ) / 2.0;
534 bestdist = 0;
535 VectorNegate( projectionDir, bestnormal );
536 // find all the brushes that are to be considered
537 ClearBounds( mins, maxs );
538 for ( i = 0 ; i < numPoints ; i++ ) {
539 vec3_t temp;
540
541 AddPointToBounds( points[i], mins, maxs );
542 VectorMA( points[i], 1 * ( 1 + oldMapping * radius * 4 ), projection, temp );
543 AddPointToBounds( temp, mins, maxs );
544 // make sure we get all the leafs (also the one(s) in front of the hit surface)
545 VectorMA( points[i], -20 * ( 1.0 + (float)oldMapping * ( radius / 20.0 ) * 4 ), projectionDir, temp );
546 AddPointToBounds( temp, mins, maxs );
547 }
548
549 if ( numPoints > MAX_VERTS_ON_POLY ) {
550 numPoints = MAX_VERTS_ON_POLY;
551 }
552 // create the bounding planes for the to be projected polygon
553 for ( i = 0 ; i < numPoints ; i++ ) {
554 VectorSubtract( points[( i + 1 ) % numPoints], points[i], v1 );
555 VectorAdd( points[i], projection, v2 );
556 VectorSubtract( points[i], v2, v2 );
557 CrossProduct( v1, v2, normals[i] );
558 VectorNormalize( normals[i] );
559 dists[i] = DotProduct( normals[i], points[i] );
560 }
561 // add near and far clipping planes for projection
562 VectorCopy( projectionDir, normals[numPoints] );
563 dists[numPoints] = DotProduct( normals[numPoints], points[0] ) - radius * ( 1 + oldMapping * 10 );
564 VectorCopy( projectionDir, normals[numPoints + 1] );
565 VectorInverse( normals[numPoints + 1] );
566 dists[numPoints + 1] = DotProduct( normals[numPoints + 1], points[0] ) - radius * ( 1 + oldMapping * 10 );
567 numPlanes = numPoints + 2;
568
569 numsurfaces = 0;
570 R_BoxSurfaces_r( tr.world->nodes, mins, maxs, surfaces, 4096, &numsurfaces, projectionDir );
571
572 returnedPoints = 0;
573 returnedFragments = 0;
574
575 // find the closest surface to center the decal there, and wrap around other surfaces
576 if ( !oldMapping ) {
577 VectorNegate( bestnormal, bestnormal );
578 }
579
580 for ( i = 0 ; i < numsurfaces ; i++ ) {
581
582 if ( *surfaces[i] == SF_GRID ) {
583
584 cv = (srfGridMesh_t *) surfaces[i];
585 for ( m = 0 ; m < cv->height - 1 ; m++ ) {
586 for ( n = 0 ; n < cv->width - 1 ; n++ ) {
587 // We triangulate the grid and chop all triangles within
588 // the bounding planes of the to be projected polygon.
589 // LOD is not taken into account, not such a big deal though.
590 //
591 // It's probably much nicer to chop the grid itself and deal
592 // with this grid as a normal SF_GRID surface so LOD will
593 // be applied. However the LOD of that chopped grid must
594 // be synced with the LOD of the original curve.
595 // One way to do this; the chopped grid shares vertices with
596 // the original curve. When LOD is applied to the original
597 // curve the unused vertices are flagged. Now the chopped curve
598 // should skip the flagged vertices. This still leaves the
599 // problems with the vertices at the chopped grid edges.
600 //
601 // To avoid issues when LOD applied to "hollow curves" (like
602 // the ones around many jump pads) we now just add a 2 unit
603 // offset to the triangle vertices.
604 // The offset is added in the vertex normal vector direction
605 // so all triangles will still fit together.
606 // The 2 unit offset should avoid pretty much all LOD problems.
607
608 numClipPoints = 3;
609
610 dv = cv->verts + m * cv->width + n;
611
612 VectorCopy( dv[0].xyz, clipPoints[0][0] );
613 VectorMA( clipPoints[0][0], MARKER_OFFSET, dv[0].normal, clipPoints[0][0] );
614 VectorCopy( dv[cv->width].xyz, clipPoints[0][1] );
615 VectorMA( clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1] );
616 VectorCopy( dv[1].xyz, clipPoints[0][2] );
617 VectorMA( clipPoints[0][2], MARKER_OFFSET, dv[1].normal, clipPoints[0][2] );
618 // check the normal of this triangle
619 VectorSubtract( clipPoints[0][0], clipPoints[0][1], v1 );
620 VectorSubtract( clipPoints[0][2], clipPoints[0][1], v2 );
621 CrossProduct( v1, v2, normal );
622 VectorNormalize( normal );
623 if ( DotProduct( normal, projectionDir ) < -0.1 ) {
624 // add the fragments of this triangle
625 R_AddMarkFragments( numClipPoints, clipPoints,
626 numPlanes, normals, dists,
627 maxPoints, pointBuffer,
628 maxFragments, fragmentBuffer,
629 &returnedPoints, &returnedFragments, mins, maxs );
630
631 if ( returnedFragments == maxFragments ) {
632 return returnedFragments; // not enough space for more fragments
633 }
634 }
635
636 VectorCopy( dv[1].xyz, clipPoints[0][0] );
637 VectorMA( clipPoints[0][0], MARKER_OFFSET, dv[1].normal, clipPoints[0][0] );
638 VectorCopy( dv[cv->width].xyz, clipPoints[0][1] );
639 VectorMA( clipPoints[0][1], MARKER_OFFSET, dv[cv->width].normal, clipPoints[0][1] );
640 VectorCopy( dv[cv->width + 1].xyz, clipPoints[0][2] );
641 VectorMA( clipPoints[0][2], MARKER_OFFSET, dv[cv->width + 1].normal, clipPoints[0][2] );
642 // check the normal of this triangle
643 VectorSubtract( clipPoints[0][0], clipPoints[0][1], v1 );
644 VectorSubtract( clipPoints[0][2], clipPoints[0][1], v2 );
645 CrossProduct( v1, v2, normal );
646 VectorNormalize( normal );
647 if ( DotProduct( normal, projectionDir ) < -0.05 ) {
648 // add the fragments of this triangle
649 R_AddMarkFragments( numClipPoints, clipPoints,
650 numPlanes, normals, dists,
651 maxPoints, pointBuffer,
652 maxFragments, fragmentBuffer,
653 &returnedPoints, &returnedFragments, mins, maxs );
654
655 if ( returnedFragments == maxFragments ) {
656 return returnedFragments; // not enough space for more fragments
657 }
658 }
659 }
660 }
661 } else if ( *surfaces[i] == SF_FACE ) {
662 extern float VectorDistance( vec3_t v1, vec3_t v2 );
663 vec3_t axis[3];
664 float texCoordScale, dot;
665 vec3_t originalPoints[4];
666 vec3_t newCenter, delta;
667 int oldNumPoints;
668 float epsilon = 0.5;
669 // duplicated so we don't mess with the original clips for the curved surfaces
670 vec3_t lnormals[MAX_VERTS_ON_POLY + 2];
671 float ldists[MAX_VERTS_ON_POLY + 2];
672 vec3_t lmins, lmaxs;
673
674 srfSurfaceFace_t *surf = ( srfSurfaceFace_t * ) surfaces[i];
675
676 if ( !oldMapping ) {
677
678 // Ridah, create a new clip box such that this decal surface is mapped onto
679 // the current surface without distortion. To find the center of the new clip box,
680 // we project the center of the original impact center out along the projection vector,
681 // onto the current surface
682
683 // find the center of the new decal
684 dot = DotProduct( center, surf->plane.normal );
685 dot -= surf->plane.dist;
686 // check the normal of this face
687 if ( dot < -epsilon && DotProduct( surf->plane.normal, projectionDir ) >= 0.01 ) {
688 continue;
689 } else if ( fabs( dot ) > radius ) {
690 continue;
691 }
692 // if the impact point is behind the surface, subtract the projection, otherwise add it
693 VectorMA( center, -dot, bestnormal, newCenter );
694
695 // recalc dot from the offset position
696 dot = DotProduct( newCenter, surf->plane.normal );
697 dot -= surf->plane.dist;
698 VectorMA( newCenter, -dot, surf->plane.normal, newCenter );
699
700 VectorMA( newCenter, MARKER_OFFSET, surf->plane.normal, newCenter );
701
702 // create the texture axis
703 VectorNormalize2( surf->plane.normal, axis[0] );
704 PerpendicularVector( axis[1], axis[0] );
705 RotatePointAroundVector( axis[2], axis[0], axis[1], (float)orientation );
706 CrossProduct( axis[0], axis[2], axis[1] );
707
708 texCoordScale = 0.5 * 1.0 / radius;
709
710 // create the full polygon
711 for ( j = 0 ; j < 3 ; j++ ) {
712 originalPoints[0][j] = newCenter[j] - radius * axis[1][j] - radius * axis[2][j];
713 originalPoints[1][j] = newCenter[j] + radius * axis[1][j] - radius * axis[2][j];
714 originalPoints[2][j] = newCenter[j] + radius * axis[1][j] + radius * axis[2][j];
715 originalPoints[3][j] = newCenter[j] - radius * axis[1][j] + radius * axis[2][j];
716 }
717
718 ClearBounds( lmins, lmaxs );
719
720 // create the bounding planes for the to be projected polygon
721 for ( j = 0 ; j < 4 ; j++ ) {
722 AddPointToBounds( originalPoints[j], lmins, lmaxs );
723
724 VectorSubtract( originalPoints[( j + 1 ) % numPoints], originalPoints[j], v1 );
725 VectorSubtract( originalPoints[j], surf->plane.normal, v2 );
726 VectorSubtract( originalPoints[j], v2, v2 );
727 CrossProduct( v1, v2, lnormals[j] );
728 VectorNormalize( lnormals[j] );
729 ldists[j] = DotProduct( lnormals[j], originalPoints[j] );
730 }
731 numPlanes = numPoints;
732
733 // done.
734
735 indexes = ( int * )( (byte *)surf + surf->ofsIndices );
736 for ( k = 0 ; k < surf->numIndices ; k += 3 ) {
737 for ( j = 0 ; j < 3 ; j++ ) {
738 v = &surf->points[0][0] + VERTEXSIZE * indexes[k + j];
739 VectorMA( v, MARKER_OFFSET, surf->plane.normal, clipPoints[0][j] );
740 }
741
742 oldNumPoints = returnedPoints;
743
744 // add the fragments of this face
745 R_AddMarkFragments( 3, clipPoints,
746 numPlanes, lnormals, ldists,
747 maxPoints, pointBuffer,
748 maxFragments, fragmentBuffer,
749 &returnedPoints, &returnedFragments, lmins, lmaxs );
750
751 if ( oldNumPoints != returnedPoints ) {
752 // flag this surface as already having computed ST's
753 fragmentBuffer[returnedFragments - 1].numPoints *= -1;
754
755 // Ridah, calculate ST's
756 for ( j = 0 ; j < ( returnedPoints - oldNumPoints ) ; j++ ) {
757 VectorSubtract( (float *)pointBuffer + 5 * ( oldNumPoints + j ), newCenter, delta );
758 *( (float *)pointBuffer + 5 * ( oldNumPoints + j ) + 3 ) = 0.5 + DotProduct( delta, axis[1] ) * texCoordScale;
759 *( (float *)pointBuffer + 5 * ( oldNumPoints + j ) + 4 ) = 0.5 + DotProduct( delta, axis[2] ) * texCoordScale;
760 }
761 }
762
763 if ( returnedFragments == maxFragments ) {
764 return returnedFragments; // not enough space for more fragments
765 }
766 }
767
768 } else { // old mapping
769
770 // check the normal of this face
771 //if (DotProduct(surf->plane.normal, projectionDir) > 0.0) {
772 // continue;
773 //}
774
775 indexes = ( int * )( (byte *)surf + surf->ofsIndices );
776 for ( k = 0 ; k < surf->numIndices ; k += 3 ) {
777 for ( j = 0 ; j < 3 ; j++ ) {
778 v = &surf->points[0][0] + VERTEXSIZE * indexes[k + j];
779 VectorMA( v, MARKER_OFFSET, surf->plane.normal, clipPoints[0][j] );
780 }
781 // add the fragments of this face
782 R_AddMarkFragments( 3, clipPoints,
783 numPlanes, normals, dists,
784 maxPoints, pointBuffer,
785 maxFragments, fragmentBuffer,
786 &returnedPoints, &returnedFragments, mins, maxs );
787 if ( returnedFragments == maxFragments ) {
788 return returnedFragments; // not enough space for more fragments
789 }
790 }
791
792 }
793
794 }
795 else if(*surfaces[i] == SF_TRIANGLES && r_marksOnTriangleMeshes->integer) {
796
797 srfTriangles_t *surf = (srfTriangles_t *) surfaces[i];
798
799 for (k = 0; k < surf->numIndexes; k += 3)
800 {
801 for(j = 0; j < 3; j++)
802 {
803 v = surf->verts[surf->indexes[k + j]].xyz;
804 VectorMA(v, MARKER_OFFSET, surf->verts[surf->indexes[k + j]].normal, clipPoints[0][j]);
805 }
806
807 // add the fragments of this face
808 R_AddMarkFragments(3, clipPoints,
809 numPlanes, normals, dists,
810 maxPoints, pointBuffer,
811 maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs);
812 if(returnedFragments == maxFragments)
813 {
814 return returnedFragments; // not enough space for more fragments
815 }
816 }
817 }
818 }
819 return returnedFragments;
820 }
821
822