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;
149 int *mark;
150
151 // do the tail recursion in a loop
152 while ( node->contents == -1 ) {
153 s = BoxOnPlaneSide( mins, maxs, node->plane );
154 if ( s == 1 ) {
155 node = node->children[0];
156 } else if ( s == 2 ) {
157 node = node->children[1];
158 } else {
159 R_BoxSurfaces_r( node->children[0], mins, maxs, list, listsize, listlength, dir );
160 node = node->children[1];
161 }
162 }
163
164 // Ridah, don't mark alpha surfaces
165 if ( node->contents & CONTENTS_TRANSLUCENT ) {
166 return;
167 }
168
169 // add the individual surfaces
170 mark = tr.world->marksurfaces + node->firstmarksurface;
171 c = node->nummarksurfaces;
172 while ( c-- ) {
173 int *surfViewCount;
174 //
175 if ( *listlength >= listsize ) {
176 break;
177 }
178 //
179 surfViewCount = &tr.world->surfacesViewCount[*mark];
180 surf = tr.world->surfaces + *mark;
181 // check if the surface has NOIMPACT or NOMARKS set
182 if ( ( surf->shader->surfaceFlags & ( SURF_NOIMPACT | SURF_NOMARKS ) )
183 || ( surf->shader->contentFlags & CONTENTS_FOG ) ) {
184 *surfViewCount = tr.viewCount;
185 }
186 // extra check for surfaces to avoid list overflows
187 else if ( *( surf->data ) == SF_FACE ) {
188 // the face plane should go through the box
189 s = BoxOnPlaneSide( mins, maxs, &surf->cullinfo.plane );
190 if ( s == 1 || s == 2 ) {
191 *surfViewCount = tr.viewCount;
192 } else if (DotProduct(surf->cullinfo.plane.normal, dir) < -0.5) {
193 // don't add faces that make sharp angles with the projection direction
194 *surfViewCount = tr.viewCount;
195 }
196 }
197 else if (*(surf->data) != SF_GRID &&
198 *(surf->data) != SF_TRIANGLES)
199 *surfViewCount = tr.viewCount;
200 // check the viewCount because the surface may have
201 // already been added if it spans multiple leafs
202 if (*surfViewCount != tr.viewCount) {
203 *surfViewCount = tr.viewCount;
204 list[*listlength] = surf->data;
205 ( *listlength )++;
206 }
207 mark++;
208 }
209 }
210
211 /*
212 =================
213 R_AddMarkFragments
214
215 =================
216 */
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)217 void R_AddMarkFragments( int numClipPoints, vec3_t clipPoints[2][MAX_VERTS_ON_POLY],
218 int numPlanes, vec3_t *normals, float *dists,
219 int maxPoints, vec3_t pointBuffer,
220 int maxFragments, markFragment_t *fragmentBuffer,
221 int *returnedPoints, int *returnedFragments,
222 vec3_t mins, vec3_t maxs ) {
223 int pingPong, i;
224 markFragment_t *mf;
225
226 // chop the surface by all the bounding planes of the to be projected polygon
227 pingPong = 0;
228
229 for ( i = 0 ; i < numPlanes ; i++ ) {
230
231 R_ChopPolyBehindPlane( numClipPoints, clipPoints[pingPong],
232 &numClipPoints, clipPoints[!pingPong],
233 normals[i], dists[i], 0.5 );
234 pingPong ^= 1;
235 if ( numClipPoints == 0 ) {
236 break;
237 }
238 }
239 // completely clipped away?
240 if ( numClipPoints == 0 ) {
241 return;
242 }
243
244 // add this fragment to the returned list
245 if ( numClipPoints + ( *returnedPoints ) > maxPoints ) {
246 return; // not enough space for this polygon
247 }
248 /*
249 // all the clip points should be within the bounding box
250 for ( i = 0 ; i < numClipPoints ; i++ ) {
251 int j;
252 for ( j = 0 ; j < 3 ; j++ ) {
253 if (clipPoints[pingPong][i][j] < mins[j] - 0.5) break;
254 if (clipPoints[pingPong][i][j] > maxs[j] + 0.5) break;
255 }
256 if (j < 3) break;
257 }
258 if (i < numClipPoints) return;
259 */
260
261 mf = fragmentBuffer + ( *returnedFragments );
262 mf->firstPoint = ( *returnedPoints );
263 mf->numPoints = numClipPoints;
264 //memcpy( pointBuffer + (*returnedPoints) * 3, clipPoints[pingPong], numClipPoints * sizeof(vec3_t) );
265 for ( i = 0; i < numClipPoints; i++ ) {
266 VectorCopy( clipPoints[pingPong][i], (float *)pointBuffer + 5 * ( *returnedPoints + i ) );
267 }
268
269 ( *returnedPoints ) += numClipPoints;
270 ( *returnedFragments )++;
271 }
272
273 /*
274 =================
275 R_OldMarkFragments
276
277 =================
278 */
R_OldMarkFragments(int numPoints,const vec3_t * points,const vec3_t projection,int maxPoints,vec3_t pointBuffer,int maxFragments,markFragment_t * fragmentBuffer)279 int R_OldMarkFragments( int numPoints, const vec3_t *points, const vec3_t projection,
280 int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ) {
281 int numsurfaces, numPlanes;
282 int i, j, k, m, n;
283 surfaceType_t *surfaces[64];
284 vec3_t mins, maxs;
285 int returnedFragments;
286 int returnedPoints;
287 vec3_t normals[MAX_VERTS_ON_POLY + 2];
288 float dists[MAX_VERTS_ON_POLY + 2];
289 vec3_t clipPoints[2][MAX_VERTS_ON_POLY];
290 int numClipPoints;
291 float *v;
292 srfBspSurface_t *cv;
293 glIndex_t *tri;
294 srfVert_t *dv;
295 vec3_t normal;
296 vec3_t projectionDir;
297 vec3_t v1, v2;
298
299 if (numPoints <= 0) {
300 return 0;
301 }
302
303 //increment view count for double check prevention
304 tr.viewCount++;
305
306 //
307 VectorNormalize2( projection, projectionDir );
308 // find all the brushes that are to be considered
309 ClearBounds( mins, maxs );
310 for ( i = 0 ; i < numPoints ; i++ ) {
311 vec3_t temp;
312
313 AddPointToBounds( points[i], mins, maxs );
314 VectorAdd( points[i], projection, temp );
315 AddPointToBounds( temp, mins, maxs );
316 // make sure we get all the leafs (also the one(s) in front of the hit surface)
317 VectorMA( points[i], -20, projectionDir, temp );
318 AddPointToBounds( temp, mins, maxs );
319 }
320
321 if ( numPoints > MAX_VERTS_ON_POLY ) {
322 numPoints = MAX_VERTS_ON_POLY;
323 }
324 // create the bounding planes for the to be projected polygon
325 for ( i = 0 ; i < numPoints ; i++ ) {
326 VectorSubtract( points[( i + 1 ) % numPoints], points[i], v1 );
327 VectorAdd( points[i], projection, v2 );
328 VectorSubtract( points[i], v2, v2 );
329 CrossProduct( v1, v2, normals[i] );
330 VectorNormalizeFast( normals[i] );
331 dists[i] = DotProduct( normals[i], points[i] );
332 }
333 // add near and far clipping planes for projection
334 VectorCopy( projectionDir, normals[numPoints] );
335 dists[numPoints] = DotProduct( normals[numPoints], points[0] ) - 32;
336 VectorCopy( projectionDir, normals[numPoints + 1] );
337 VectorInverse( normals[numPoints + 1] );
338 dists[numPoints + 1] = DotProduct( normals[numPoints + 1], points[0] ) - 20;
339 numPlanes = numPoints + 2;
340
341 numsurfaces = 0;
342 R_BoxSurfaces_r( tr.world->nodes, mins, maxs, surfaces, 64, &numsurfaces, projectionDir );
343 //assert(numsurfaces <= 64);
344 //assert(numsurfaces != 64);
345
346 returnedPoints = 0;
347 returnedFragments = 0;
348
349 for ( i = 0 ; i < numsurfaces ; i++ ) {
350
351 if ( *surfaces[i] == SF_GRID ) {
352
353 cv = (srfBspSurface_t *) surfaces[i];
354 for ( m = 0 ; m < cv->height - 1 ; m++ ) {
355 for ( n = 0 ; n < cv->width - 1 ; n++ ) {
356 // We triangulate the grid and chop all triangles within
357 // the bounding planes of the to be projected polygon.
358 // LOD is not taken into account, not such a big deal though.
359 //
360 // It's probably much nicer to chop the grid itself and deal
361 // with this grid as a normal SF_GRID surface so LOD will
362 // be applied. However the LOD of that chopped grid must
363 // be synced with the LOD of the original curve.
364 // One way to do this; the chopped grid shares vertices with
365 // the original curve. When LOD is applied to the original
366 // curve the unused vertices are flagged. Now the chopped curve
367 // should skip the flagged vertices. This still leaves the
368 // problems with the vertices at the chopped grid edges.
369 //
370 // To avoid issues when LOD applied to "hollow curves" (like
371 // the ones around many jump pads) we now just add a 2 unit
372 // offset to the triangle vertices.
373 // The offset is added in the vertex normal vector direction
374 // so all triangles will still fit together.
375 // The 2 unit offset should avoid pretty much all LOD problems.
376 vec3_t fNormal;
377
378 numClipPoints = 3;
379
380 dv = cv->verts + m * cv->width + n;
381
382 VectorCopy( dv[0].xyz, clipPoints[0][0] );
383 R_VaoUnpackNormal(fNormal, dv[0].normal);
384 VectorMA(clipPoints[0][0], MARKER_OFFSET, fNormal, clipPoints[0][0]);
385 VectorCopy( dv[cv->width].xyz, clipPoints[0][1] );
386 R_VaoUnpackNormal(fNormal, dv[cv->width].normal);
387 VectorMA(clipPoints[0][1], MARKER_OFFSET, fNormal, clipPoints[0][1]);
388 VectorCopy( dv[1].xyz, clipPoints[0][2] );
389 R_VaoUnpackNormal(fNormal, dv[1].normal);
390 VectorMA(clipPoints[0][2], MARKER_OFFSET, fNormal, clipPoints[0][2]);
391 // check the normal of this triangle
392 VectorSubtract( clipPoints[0][0], clipPoints[0][1], v1 );
393 VectorSubtract( clipPoints[0][2], clipPoints[0][1], v2 );
394 CrossProduct( v1, v2, normal );
395 VectorNormalizeFast( normal );
396 if ( DotProduct( normal, projectionDir ) < -0.1 ) {
397 // add the fragments of this triangle
398 R_AddMarkFragments( numClipPoints, clipPoints,
399 numPlanes, normals, dists,
400 maxPoints, pointBuffer,
401 maxFragments, fragmentBuffer,
402 &returnedPoints, &returnedFragments, mins, maxs );
403
404 if ( returnedFragments == maxFragments ) {
405 return returnedFragments; // not enough space for more fragments
406 }
407 }
408
409 VectorCopy( dv[1].xyz, clipPoints[0][0] );
410 R_VaoUnpackNormal(fNormal, dv[1].normal);
411 VectorMA(clipPoints[0][0], MARKER_OFFSET, fNormal, clipPoints[0][0]);
412 VectorCopy( dv[cv->width].xyz, clipPoints[0][1] );
413 R_VaoUnpackNormal(fNormal, dv[cv->width].normal);
414 VectorMA(clipPoints[0][1], MARKER_OFFSET, fNormal, clipPoints[0][1]);
415 VectorCopy( dv[cv->width + 1].xyz, clipPoints[0][2] );
416 R_VaoUnpackNormal(fNormal, dv[cv->width + 1].normal);
417 VectorMA(clipPoints[0][2], MARKER_OFFSET, fNormal, clipPoints[0][2]);
418 // check the normal of this triangle
419 VectorSubtract( clipPoints[0][0], clipPoints[0][1], v1 );
420 VectorSubtract( clipPoints[0][2], clipPoints[0][1], v2 );
421 CrossProduct( v1, v2, normal );
422 VectorNormalizeFast( normal );
423 if ( DotProduct( normal, projectionDir ) < -0.05 ) {
424 // add the fragments of this triangle
425 R_AddMarkFragments( numClipPoints, clipPoints,
426 numPlanes, normals, dists,
427 maxPoints, pointBuffer,
428 maxFragments, fragmentBuffer,
429 &returnedPoints, &returnedFragments, mins, maxs );
430
431 if ( returnedFragments == maxFragments ) {
432 return returnedFragments; // not enough space for more fragments
433 }
434 }
435 }
436 }
437 } else if ( *surfaces[i] == SF_FACE ) {
438
439 srfBspSurface_t *surf = ( srfBspSurface_t * ) surfaces[i];
440
441 // check the normal of this face
442 if (DotProduct(surf->cullPlane.normal, projectionDir) > -0.5) {
443 continue;
444 }
445
446 for(k = 0, tri = surf->indexes; k < surf->numIndexes; k += 3, tri += 3)
447 {
448 for(j = 0; j < 3; j++)
449 {
450 v = surf->verts[tri[j]].xyz;
451 VectorMA(v, MARKER_OFFSET, surf->cullPlane.normal, clipPoints[0][j]);
452 }
453 // add the fragments of this face
454 R_AddMarkFragments( 3, clipPoints,
455 numPlanes, normals, dists,
456 maxPoints, pointBuffer,
457 maxFragments, fragmentBuffer,
458 &returnedPoints, &returnedFragments, mins, maxs );
459 if ( returnedFragments == maxFragments ) {
460 return returnedFragments; // not enough space for more fragments
461 }
462 }
463 }
464 else if(*surfaces[i] == SF_TRIANGLES && r_marksOnTriangleMeshes->integer) {
465
466 srfBspSurface_t *surf = (srfBspSurface_t *) surfaces[i];
467
468 for(k = 0, tri = surf->indexes; k < surf->numIndexes; k += 3, tri += 3)
469 {
470 for(j = 0; j < 3; j++)
471 {
472 vec3_t fNormal;
473 v = surf->verts[tri[j]].xyz;
474 R_VaoUnpackNormal(fNormal, surf->verts[tri[j]].normal);
475 VectorMA(v, MARKER_OFFSET, fNormal, clipPoints[0][j]);
476 }
477
478 // add the fragments of this face
479 R_AddMarkFragments(3, clipPoints,
480 numPlanes, normals, dists,
481 maxPoints, pointBuffer,
482 maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs);
483 if(returnedFragments == maxFragments)
484 {
485 return returnedFragments; // not enough space for more fragments
486 }
487 }
488 }
489 }
490 return returnedFragments;
491 }
492
493 /*
494 =================
495 R_MarkFragments
496
497 =================
498 */
R_MarkFragments(int orientation,const vec3_t * points,const vec3_t projection,int maxPoints,vec3_t pointBuffer,int maxFragments,markFragment_t * fragmentBuffer)499 int R_MarkFragments( int orientation, const vec3_t *points, const vec3_t projection,
500 int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ) {
501 int numsurfaces, numPlanes;
502 int i, j, k, m, n;
503 surfaceType_t *surfaces[4096];
504 vec3_t mins, maxs;
505 int returnedFragments;
506 int returnedPoints;
507 vec3_t normals[MAX_VERTS_ON_POLY + 2];
508 float dists[MAX_VERTS_ON_POLY + 2];
509 vec3_t clipPoints[2][MAX_VERTS_ON_POLY];
510 int numClipPoints;
511 float *v;
512 srfBspSurface_t *cv;
513 glIndex_t *tri;
514 srfVert_t *dv;
515 vec3_t normal;
516 vec3_t projectionDir;
517 vec3_t v1, v2;
518 float radius;
519 vec3_t center; // center of original mark
520 int numPoints = 4; // Ridah, we were only ever passing in 4, so I made this local and used the parameter for the orientation
521 qboolean oldMapping = qfalse;
522
523 if (numPoints <= 0) {
524 return 0;
525 }
526
527 //increment view count for double check prevention
528 tr.viewCount++;
529
530 // RF, negative maxFragments means we want original mapping
531 if ( maxFragments < 0 ) {
532 maxFragments = -maxFragments;
533 oldMapping = qtrue;
534 }
535
536 VectorClear( center );
537 for ( i = 0 ; i < numPoints ; i++ ) {
538 VectorAdd( points[i], center, center );
539 }
540 VectorScale( center, 1.0 / numPoints, center );
541 //
542 radius = VectorNormalize2( projection, projectionDir ) / 2.0;
543 bestdist = 0;
544 VectorNegate( projectionDir, bestnormal );
545 // find all the brushes that are to be considered
546 ClearBounds( mins, maxs );
547 for ( i = 0 ; i < numPoints ; i++ ) {
548 vec3_t temp;
549
550 AddPointToBounds( points[i], mins, maxs );
551 VectorMA( points[i], 1 * ( 1 + oldMapping * radius * 4 ), projection, temp );
552 AddPointToBounds( temp, mins, maxs );
553 // make sure we get all the leafs (also the one(s) in front of the hit surface)
554 VectorMA( points[i], -20 * ( 1.0 + (float)oldMapping * ( radius / 20.0 ) * 4 ), projectionDir, temp );
555 AddPointToBounds( temp, mins, maxs );
556 }
557
558 if ( numPoints > MAX_VERTS_ON_POLY ) {
559 numPoints = MAX_VERTS_ON_POLY;
560 }
561 // create the bounding planes for the to be projected polygon
562 for ( i = 0 ; i < numPoints ; i++ ) {
563 VectorSubtract( points[( i + 1 ) % numPoints], points[i], v1 );
564 VectorAdd( points[i], projection, v2 );
565 VectorSubtract( points[i], v2, v2 );
566 CrossProduct( v1, v2, normals[i] );
567 VectorNormalize( normals[i] );
568 dists[i] = DotProduct( normals[i], points[i] );
569 }
570 // add near and far clipping planes for projection
571 VectorCopy( projectionDir, normals[numPoints] );
572 dists[numPoints] = DotProduct( normals[numPoints], points[0] ) - radius * ( 1 + oldMapping * 10 );
573 VectorCopy( projectionDir, normals[numPoints + 1] );
574 VectorInverse( normals[numPoints + 1] );
575 dists[numPoints + 1] = DotProduct( normals[numPoints + 1], points[0] ) - radius * ( 1 + oldMapping * 10 );
576 numPlanes = numPoints + 2;
577
578 numsurfaces = 0;
579 R_BoxSurfaces_r( tr.world->nodes, mins, maxs, surfaces, 4096, &numsurfaces, projectionDir );
580
581 returnedPoints = 0;
582 returnedFragments = 0;
583
584 // find the closest surface to center the decal there, and wrap around other surfaces
585 if ( !oldMapping ) {
586 VectorNegate( bestnormal, bestnormal );
587 }
588
589 for ( i = 0 ; i < numsurfaces ; i++ ) {
590
591 if ( *surfaces[i] == SF_GRID ) {
592
593 cv = (srfBspSurface_t *) surfaces[i];
594 for ( m = 0 ; m < cv->height - 1 ; m++ ) {
595 for ( n = 0 ; n < cv->width - 1 ; n++ ) {
596 // We triangulate the grid and chop all triangles within
597 // the bounding planes of the to be projected polygon.
598 // LOD is not taken into account, not such a big deal though.
599 //
600 // It's probably much nicer to chop the grid itself and deal
601 // with this grid as a normal SF_GRID surface so LOD will
602 // be applied. However the LOD of that chopped grid must
603 // be synced with the LOD of the original curve.
604 // One way to do this; the chopped grid shares vertices with
605 // the original curve. When LOD is applied to the original
606 // curve the unused vertices are flagged. Now the chopped curve
607 // should skip the flagged vertices. This still leaves the
608 // problems with the vertices at the chopped grid edges.
609 //
610 // To avoid issues when LOD applied to "hollow curves" (like
611 // the ones around many jump pads) we now just add a 2 unit
612 // offset to the triangle vertices.
613 // The offset is added in the vertex normal vector direction
614 // so all triangles will still fit together.
615 // The 2 unit offset should avoid pretty much all LOD problems.
616 vec3_t fNormal;
617
618 numClipPoints = 3;
619
620 dv = cv->verts + m * cv->width + n;
621
622 VectorCopy( dv[0].xyz, clipPoints[0][0] );
623 R_VaoUnpackNormal(fNormal, dv[0].normal);
624 VectorMA(clipPoints[0][0], MARKER_OFFSET, fNormal, clipPoints[0][0]);
625 VectorCopy( dv[cv->width].xyz, clipPoints[0][1] );
626 R_VaoUnpackNormal(fNormal, dv[cv->width].normal);
627 VectorMA(clipPoints[0][1], MARKER_OFFSET, fNormal, clipPoints[0][1]);
628 VectorCopy( dv[1].xyz, clipPoints[0][2] );
629 R_VaoUnpackNormal(fNormal, dv[1].normal);
630 VectorMA(clipPoints[0][2], MARKER_OFFSET, fNormal, clipPoints[0][2]);
631 // check the normal of this triangle
632 VectorSubtract( clipPoints[0][0], clipPoints[0][1], v1 );
633 VectorSubtract( clipPoints[0][2], clipPoints[0][1], v2 );
634 CrossProduct( v1, v2, normal );
635 VectorNormalize( normal );
636 if ( DotProduct( normal, projectionDir ) < -0.1 ) {
637 // add the fragments of this triangle
638 R_AddMarkFragments( numClipPoints, clipPoints,
639 numPlanes, normals, dists,
640 maxPoints, pointBuffer,
641 maxFragments, fragmentBuffer,
642 &returnedPoints, &returnedFragments, mins, maxs );
643
644 if ( returnedFragments == maxFragments ) {
645 return returnedFragments; // not enough space for more fragments
646 }
647 }
648
649 VectorCopy( dv[1].xyz, clipPoints[0][0] );
650 R_VaoUnpackNormal(fNormal, dv[1].normal);
651 VectorMA(clipPoints[0][0], MARKER_OFFSET, fNormal, clipPoints[0][0]);
652 VectorCopy( dv[cv->width].xyz, clipPoints[0][1] );
653 R_VaoUnpackNormal(fNormal, dv[cv->width].normal);
654 VectorMA(clipPoints[0][1], MARKER_OFFSET, fNormal, clipPoints[0][1]);
655 VectorCopy( dv[cv->width + 1].xyz, clipPoints[0][2] );
656 R_VaoUnpackNormal(fNormal, dv[cv->width + 1].normal);
657 VectorMA(clipPoints[0][2], MARKER_OFFSET, fNormal, clipPoints[0][2]);
658 // check the normal of this triangle
659 VectorSubtract( clipPoints[0][0], clipPoints[0][1], v1 );
660 VectorSubtract( clipPoints[0][2], clipPoints[0][1], v2 );
661 CrossProduct( v1, v2, normal );
662 VectorNormalize( normal );
663 if ( DotProduct( normal, projectionDir ) < -0.05 ) {
664 // add the fragments of this triangle
665 R_AddMarkFragments( numClipPoints, clipPoints,
666 numPlanes, normals, dists,
667 maxPoints, pointBuffer,
668 maxFragments, fragmentBuffer,
669 &returnedPoints, &returnedFragments, mins, maxs );
670
671 if ( returnedFragments == maxFragments ) {
672 return returnedFragments; // not enough space for more fragments
673 }
674 }
675 }
676 }
677 } else if ( *surfaces[i] == SF_FACE ) {
678 extern float VectorDistance( vec3_t v1, vec3_t v2 );
679 vec3_t axis[3];
680 float texCoordScale, dot;
681 vec3_t originalPoints[4];
682 vec3_t newCenter, delta;
683 int oldNumPoints;
684 float epsilon = 0.5;
685 // duplicated so we don't mess with the original clips for the curved surfaces
686 vec3_t lnormals[MAX_VERTS_ON_POLY + 2];
687 float ldists[MAX_VERTS_ON_POLY + 2];
688 vec3_t lmins, lmaxs;
689
690 srfBspSurface_t *surf = ( srfBspSurface_t * ) surfaces[i];
691
692 if ( !oldMapping ) {
693
694 // Ridah, create a new clip box such that this decal surface is mapped onto
695 // the current surface without distortion. To find the center of the new clip box,
696 // we project the center of the original impact center out along the projection vector,
697 // onto the current surface
698
699 // find the center of the new decal
700 dot = DotProduct( center, surf->cullPlane.normal );
701 dot -= surf->cullPlane.dist;
702 // check the normal of this face
703 if ( dot < -epsilon && DotProduct(surf->cullPlane.normal, projectionDir) >= 0.01 ) {
704 continue;
705 } else if ( fabs( dot ) > radius ) {
706 continue;
707 }
708 // if the impact point is behind the surface, subtract the projection, otherwise add it
709 VectorMA( center, -dot, bestnormal, newCenter );
710
711 // recalc dot from the offset position
712 dot = DotProduct( newCenter, surf->cullPlane.normal );
713 dot -= surf->cullPlane.dist;
714 VectorMA( newCenter, -dot, surf->cullPlane.normal, newCenter );
715
716 VectorMA( newCenter, MARKER_OFFSET, surf->cullPlane.normal, newCenter );
717
718 // create the texture axis
719 VectorNormalize2( surf->cullPlane.normal, axis[0] );
720 PerpendicularVector( axis[1], axis[0] );
721 RotatePointAroundVector( axis[2], axis[0], axis[1], (float)orientation );
722 CrossProduct( axis[0], axis[2], axis[1] );
723
724 texCoordScale = 0.5 * 1.0 / radius;
725
726 // create the full polygon
727 for ( j = 0 ; j < 3 ; j++ ) {
728 originalPoints[0][j] = newCenter[j] - radius * axis[1][j] - radius * axis[2][j];
729 originalPoints[1][j] = newCenter[j] + radius * axis[1][j] - radius * axis[2][j];
730 originalPoints[2][j] = newCenter[j] + radius * axis[1][j] + radius * axis[2][j];
731 originalPoints[3][j] = newCenter[j] - radius * axis[1][j] + radius * axis[2][j];
732 }
733
734 ClearBounds( lmins, lmaxs );
735
736 // create the bounding planes for the to be projected polygon
737 for ( j = 0 ; j < 4 ; j++ ) {
738 AddPointToBounds( originalPoints[j], lmins, lmaxs );
739
740 VectorSubtract( originalPoints[( j + 1 ) % numPoints], originalPoints[j], v1 );
741 VectorSubtract( originalPoints[j], surf->cullPlane.normal, v2 );
742 VectorSubtract( originalPoints[j], v2, v2 );
743 CrossProduct( v1, v2, lnormals[j] );
744 VectorNormalize( lnormals[j] );
745 ldists[j] = DotProduct( lnormals[j], originalPoints[j] );
746 }
747 numPlanes = numPoints;
748
749 // done.
750
751 for(k = 0, tri = surf->indexes; k < surf->numIndexes; k += 3, tri += 3)
752 {
753 for(j = 0; j < 3; j++)
754 {
755 v = surf->verts[tri[j]].xyz;
756 VectorMA(v, MARKER_OFFSET, surf->cullPlane.normal, clipPoints[0][j]);
757 }
758
759 oldNumPoints = returnedPoints;
760
761 // add the fragments of this face
762 R_AddMarkFragments( 3, clipPoints,
763 numPlanes, lnormals, ldists,
764 maxPoints, pointBuffer,
765 maxFragments, fragmentBuffer,
766 &returnedPoints, &returnedFragments, lmins, lmaxs );
767
768 if ( oldNumPoints != returnedPoints ) {
769 // flag this surface as already having computed ST's
770 fragmentBuffer[returnedFragments - 1].numPoints *= -1;
771
772 // Ridah, calculate ST's
773 for ( j = 0 ; j < ( returnedPoints - oldNumPoints ) ; j++ ) {
774 VectorSubtract( (float *)pointBuffer + 5 * ( oldNumPoints + j ), newCenter, delta );
775 *( (float *)pointBuffer + 5 * ( oldNumPoints + j ) + 3 ) = 0.5 + DotProduct( delta, axis[1] ) * texCoordScale;
776 *( (float *)pointBuffer + 5 * ( oldNumPoints + j ) + 4 ) = 0.5 + DotProduct( delta, axis[2] ) * texCoordScale;
777 }
778 }
779
780 if ( returnedFragments == maxFragments ) {
781 return returnedFragments; // not enough space for more fragments
782 }
783 }
784
785 } else { // old mapping
786
787 // check the normal of this face
788 //if (DotProduct(surf->cullPlane.normal, projectionDir) > 0.0) {
789 // continue;
790 //}
791
792 for(k = 0, tri = surf->indexes; k < surf->numIndexes; k += 3, tri += 3)
793 {
794 for(j = 0; j < 3; j++)
795 {
796 v = surf->verts[tri[j]].xyz;
797 VectorMA(v, MARKER_OFFSET, surf->cullPlane.normal, clipPoints[0][j]);
798 }
799 // add the fragments of this face
800 R_AddMarkFragments( 3, clipPoints,
801 numPlanes, normals, dists,
802 maxPoints, pointBuffer,
803 maxFragments, fragmentBuffer,
804 &returnedPoints, &returnedFragments, mins, maxs );
805 if ( returnedFragments == maxFragments ) {
806 return returnedFragments; // not enough space for more fragments
807 }
808 }
809
810 }
811
812 }
813 else if(*surfaces[i] == SF_TRIANGLES && r_marksOnTriangleMeshes->integer) {
814
815 srfBspSurface_t *surf = (srfBspSurface_t *) surfaces[i];
816
817 for(k = 0, tri = surf->indexes; k < surf->numIndexes; k += 3, tri += 3)
818 {
819 for(j = 0; j < 3; j++)
820 {
821 vec3_t fNormal;
822 v = surf->verts[tri[j]].xyz;
823 R_VaoUnpackNormal(fNormal, surf->verts[tri[j]].normal);
824 VectorMA(v, MARKER_OFFSET, fNormal, clipPoints[0][j]);
825 }
826
827 // add the fragments of this face
828 R_AddMarkFragments(3, clipPoints,
829 numPlanes, normals, dists,
830 maxPoints, pointBuffer,
831 maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs);
832 if(returnedFragments == maxFragments)
833 {
834 return returnedFragments; // not enough space for more fragments
835 }
836 }
837 }
838 }
839 return returnedFragments;
840 }
841
842