1 /*
2 ===========================================================================
3
4 Return to Castle Wolfenstein multiplayer 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 multiplayer GPL Source Code (RTCW MP Source Code).
8
9 RTCW MP 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 MP 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 MP Source Code. If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the RTCW MP 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 MP 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
454 // add the fragments of this face
455 R_AddMarkFragments( 3, clipPoints,
456 numPlanes, normals, dists,
457 maxPoints, pointBuffer,
458 maxFragments, fragmentBuffer,
459 &returnedPoints, &returnedFragments, mins, maxs );
460 if ( returnedFragments == maxFragments ) {
461 return returnedFragments; // not enough space for more fragments
462 }
463 }
464 }
465 else if(*surfaces[i] == SF_TRIANGLES && r_marksOnTriangleMeshes->integer) {
466
467 srfBspSurface_t *surf = (srfBspSurface_t *) surfaces[i];
468
469 for(k = 0, tri = surf->indexes; k < surf->numIndexes; k += 3, tri += 3)
470 {
471 for(j = 0; j < 3; j++)
472 {
473 vec3_t fNormal;
474 v = surf->verts[tri[j]].xyz;
475 R_VaoUnpackNormal(fNormal, surf->verts[tri[j]].normal);
476 VectorMA(v, MARKER_OFFSET, fNormal, clipPoints[0][j]);
477 }
478
479 // add the fragments of this face
480 R_AddMarkFragments(3, clipPoints,
481 numPlanes, normals, dists,
482 maxPoints, pointBuffer,
483 maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs);
484 if(returnedFragments == maxFragments)
485 {
486 return returnedFragments; // not enough space for more fragments
487 }
488 }
489 }
490 }
491 return returnedFragments;
492 }
493
494 /*
495 =================
496 R_MarkFragments
497
498 =================
499 */
R_MarkFragments(int orientation,const vec3_t * points,const vec3_t projection,int maxPoints,vec3_t pointBuffer,int maxFragments,markFragment_t * fragmentBuffer)500 int R_MarkFragments( int orientation, const vec3_t *points, const vec3_t projection,
501 int maxPoints, vec3_t pointBuffer, int maxFragments, markFragment_t *fragmentBuffer ) {
502 int numsurfaces, numPlanes;
503 int i, j, k, m, n;
504 surfaceType_t *surfaces[4096];
505 vec3_t mins, maxs;
506 int returnedFragments;
507 int returnedPoints;
508 vec3_t normals[MAX_VERTS_ON_POLY + 2];
509 float dists[MAX_VERTS_ON_POLY + 2];
510 vec3_t clipPoints[2][MAX_VERTS_ON_POLY];
511 int numClipPoints;
512 float *v;
513 srfBspSurface_t *cv;
514 glIndex_t *tri;
515 srfVert_t *dv;
516 vec3_t normal;
517 vec3_t projectionDir;
518 vec3_t v1, v2;
519 float radius;
520 vec3_t center; // center of original mark
521 int numPoints = 4; // Ridah, we were only ever passing in 4, so I made this local and used the parameter for the orientation
522 qboolean oldMapping = qfalse;
523
524 if (numPoints <= 0) {
525 return 0;
526 }
527
528 //increment view count for double check prevention
529 tr.viewCount++;
530
531 // RF, negative maxFragments means we want original mapping
532 if ( maxFragments < 0 ) {
533 maxFragments = -maxFragments;
534 //return R_OldMarkFragments( numPoints, points, projection, maxPoints, pointBuffer, maxFragments, fragmentBuffer );
535 oldMapping = qtrue;
536 }
537
538 VectorClear( center );
539 for ( i = 0 ; i < numPoints ; i++ ) {
540 VectorAdd( points[i], center, center );
541 }
542 VectorScale( center, 1.0 / numPoints, center );
543 //
544 radius = VectorNormalize2( projection, projectionDir ) / 2.0;
545 bestdist = 0;
546 VectorNegate( projectionDir, bestnormal );
547 // find all the brushes that are to be considered
548 ClearBounds( mins, maxs );
549 for ( i = 0 ; i < numPoints ; i++ ) {
550 vec3_t temp;
551
552 AddPointToBounds( points[i], mins, maxs );
553 VectorMA( points[i], 1 * ( 1 + oldMapping * radius * 4 ), projection, temp );
554 AddPointToBounds( temp, mins, maxs );
555 // make sure we get all the leafs (also the one(s) in front of the hit surface)
556 VectorMA( points[i], -20 * ( 1.0 + (float)oldMapping * ( radius / 20.0 ) * 4 ), projectionDir, temp );
557 AddPointToBounds( temp, mins, maxs );
558 }
559
560 if ( numPoints > MAX_VERTS_ON_POLY ) {
561 numPoints = MAX_VERTS_ON_POLY;
562 }
563 // create the bounding planes for the to be projected polygon
564 for ( i = 0 ; i < numPoints ; i++ ) {
565 VectorSubtract( points[( i + 1 ) % numPoints], points[i], v1 );
566 VectorAdd( points[i], projection, v2 );
567 VectorSubtract( points[i], v2, v2 );
568 CrossProduct( v1, v2, normals[i] );
569 VectorNormalize( normals[i] );
570 dists[i] = DotProduct( normals[i], points[i] );
571 }
572 // add near and far clipping planes for projection
573 VectorCopy( projectionDir, normals[numPoints] );
574 dists[numPoints] = DotProduct( normals[numPoints], points[0] ) - radius * ( 1 + oldMapping * 10 );
575 VectorCopy( projectionDir, normals[numPoints + 1] );
576 VectorInverse( normals[numPoints + 1] );
577 dists[numPoints + 1] = DotProduct( normals[numPoints + 1], points[0] ) - radius * ( 1 + oldMapping * 10 );
578 numPlanes = numPoints + 2;
579
580 numsurfaces = 0;
581 R_BoxSurfaces_r( tr.world->nodes, mins, maxs, surfaces, 4096, &numsurfaces, projectionDir );
582 //assert(numsurfaces <= 64);
583 //assert(numsurfaces != 64);
584
585 returnedPoints = 0;
586 returnedFragments = 0;
587
588 // find the closest surface to center the decal there, and wrap around other surfaces
589 if ( !oldMapping ) {
590 /*
591 for ( i = 0 ; i < numsurfaces ; i++ ) {
592 if (*surfaces[i] == SF_FACE) {
593 surf = ( srfBspSurface_t * ) surfaces[i];
594 // Ridah, check if this is the closest surface
595 dot = DotProduct( center, surf->cullPlane.normal );
596 dot -= surf->plane.dist;
597 if (!bestdist) {
598 if (dot < 0)
599 bestdist = fabs(dot) + 1000; // avoid this surface, since the point is behind it
600 else
601 bestdist = dot;
602 VectorCopy( surf->cullPlane.normal, bestnormal );
603 VectorMA( center, -dot, surf->cullPlane.normal, bestCenter );
604 } else if (dot >= 0 && dot < bestdist) {
605 bestdist = dot;
606 VectorCopy( surf->cullPlane.normal, bestnormal );
607 VectorMA( center, -dot, surf->cullPlane.normal, bestCenter );
608 }
609 }
610 }
611 // bestCenter is now the real center
612 VectorCopy( bestCenter, center );
613 Com_Printf("bestnormal: %1.1f %1.1f %1.1f \n", bestnormal[0], bestnormal[1], bestnormal[2] );
614 */
615 VectorNegate( bestnormal, bestnormal );
616 }
617
618 for ( i = 0 ; i < numsurfaces ; i++ ) {
619
620 if ( *surfaces[i] == SF_GRID ) {
621
622 cv = (srfBspSurface_t *) surfaces[i];
623 for ( m = 0 ; m < cv->height - 1 ; m++ ) {
624 for ( n = 0 ; n < cv->width - 1 ; n++ ) {
625 // We triangulate the grid and chop all triangles within
626 // the bounding planes of the to be projected polygon.
627 // LOD is not taken into account, not such a big deal though.
628 //
629 // It's probably much nicer to chop the grid itself and deal
630 // with this grid as a normal SF_GRID surface so LOD will
631 // be applied. However the LOD of that chopped grid must
632 // be synced with the LOD of the original curve.
633 // One way to do this; the chopped grid shares vertices with
634 // the original curve. When LOD is applied to the original
635 // curve the unused vertices are flagged. Now the chopped curve
636 // should skip the flagged vertices. This still leaves the
637 // problems with the vertices at the chopped grid edges.
638 //
639 // To avoid issues when LOD applied to "hollow curves" (like
640 // the ones around many jump pads) we now just add a 2 unit
641 // offset to the triangle vertices.
642 // The offset is added in the vertex normal vector direction
643 // so all triangles will still fit together.
644 // The 2 unit offset should avoid pretty much all LOD problems.
645 vec3_t fNormal;
646
647 numClipPoints = 3;
648
649 dv = cv->verts + m * cv->width + n;
650
651 VectorCopy( dv[0].xyz, clipPoints[0][0] );
652 R_VaoUnpackNormal(fNormal, dv[0].normal);
653 VectorMA(clipPoints[0][0], MARKER_OFFSET, fNormal, clipPoints[0][0]);
654 VectorCopy( dv[cv->width].xyz, clipPoints[0][1] );
655 R_VaoUnpackNormal(fNormal, dv[cv->width].normal);
656 VectorMA(clipPoints[0][1], MARKER_OFFSET, fNormal, clipPoints[0][1]);
657 VectorCopy( dv[1].xyz, clipPoints[0][2] );
658 R_VaoUnpackNormal(fNormal, dv[1].normal);
659 VectorMA(clipPoints[0][2], MARKER_OFFSET, fNormal, clipPoints[0][2]);
660 // check the normal of this triangle
661 VectorSubtract( clipPoints[0][0], clipPoints[0][1], v1 );
662 VectorSubtract( clipPoints[0][2], clipPoints[0][1], v2 );
663 CrossProduct( v1, v2, normal );
664 VectorNormalize( normal );
665 if ( DotProduct( normal, projectionDir ) < -0.1 ) {
666 // add the fragments of this triangle
667 R_AddMarkFragments( numClipPoints, clipPoints,
668 numPlanes, normals, dists,
669 maxPoints, pointBuffer,
670 maxFragments, fragmentBuffer,
671 &returnedPoints, &returnedFragments, mins, maxs );
672
673 if ( returnedFragments == maxFragments ) {
674 return returnedFragments; // not enough space for more fragments
675 }
676 }
677
678 VectorCopy( dv[1].xyz, clipPoints[0][0] );
679 R_VaoUnpackNormal(fNormal, dv[1].normal);
680 VectorMA(clipPoints[0][0], MARKER_OFFSET, fNormal, clipPoints[0][0]);
681 VectorCopy( dv[cv->width].xyz, clipPoints[0][1] );
682 R_VaoUnpackNormal(fNormal, dv[cv->width].normal);
683 VectorMA(clipPoints[0][1], MARKER_OFFSET, fNormal, clipPoints[0][1]);
684 VectorCopy( dv[cv->width + 1].xyz, clipPoints[0][2] );
685 R_VaoUnpackNormal(fNormal, dv[cv->width + 1].normal);
686 VectorMA(clipPoints[0][2], MARKER_OFFSET, fNormal, clipPoints[0][2]);
687 // check the normal of this triangle
688 VectorSubtract( clipPoints[0][0], clipPoints[0][1], v1 );
689 VectorSubtract( clipPoints[0][2], clipPoints[0][1], v2 );
690 CrossProduct( v1, v2, normal );
691 VectorNormalize( normal );
692 if ( DotProduct( normal, projectionDir ) < -0.05 ) {
693 // add the fragments of this triangle
694 R_AddMarkFragments( numClipPoints, clipPoints,
695 numPlanes, normals, dists,
696 maxPoints, pointBuffer,
697 maxFragments, fragmentBuffer,
698 &returnedPoints, &returnedFragments, mins, maxs );
699
700 if ( returnedFragments == maxFragments ) {
701 return returnedFragments; // not enough space for more fragments
702 }
703 }
704 }
705 }
706 } else if ( *surfaces[i] == SF_FACE ) {
707 extern float VectorDistance( vec3_t v1, vec3_t v2 );
708 vec3_t axis[3];
709 float texCoordScale, dot;
710 vec3_t originalPoints[4];
711 vec3_t newCenter, delta;
712 int oldNumPoints;
713 float epsilon = 0.5;
714 // duplicated so we don't mess with the original clips for the curved surfaces
715 vec3_t lnormals[MAX_VERTS_ON_POLY + 2];
716 float ldists[MAX_VERTS_ON_POLY + 2];
717 vec3_t lmins, lmaxs;
718
719 srfBspSurface_t *surf = ( srfBspSurface_t * ) surfaces[i];
720
721 if ( !oldMapping ) {
722
723 // Ridah, create a new clip box such that this decal surface is mapped onto
724 // the current surface without distortion. To find the center of the new clip box,
725 // we project the center of the original impact center out along the projection vector,
726 // onto the current surface
727
728 // find the center of the new decal
729 dot = DotProduct( center, surf->cullPlane.normal );
730 dot -= surf->cullPlane.dist;
731 // check the normal of this face
732 if ( dot < -epsilon && DotProduct(surf->cullPlane.normal, projectionDir) >= 0.01 ) {
733 continue;
734 } else if ( fabs( dot ) > radius ) {
735 continue;
736 }
737 // if the impact point is behind the surface, subtract the projection, otherwise add it
738 VectorMA( center, -dot, bestnormal, newCenter );
739
740 // recalc dot from the offset position
741 dot = DotProduct( newCenter, surf->cullPlane.normal );
742 dot -= surf->cullPlane.dist;
743 VectorMA( newCenter, -dot, surf->cullPlane.normal, newCenter );
744
745 VectorMA( newCenter, MARKER_OFFSET, surf->cullPlane.normal, newCenter );
746
747 // create the texture axis
748 VectorNormalize2( surf->cullPlane.normal, axis[0] );
749 PerpendicularVector( axis[1], axis[0] );
750 RotatePointAroundVector( axis[2], axis[0], axis[1], (float)orientation );
751 CrossProduct( axis[0], axis[2], axis[1] );
752
753 texCoordScale = 0.5 * 1.0 / radius;
754
755 // create the full polygon
756 for ( j = 0 ; j < 3 ; j++ ) {
757 originalPoints[0][j] = newCenter[j] - radius * axis[1][j] - radius * axis[2][j];
758 originalPoints[1][j] = newCenter[j] + radius * axis[1][j] - radius * axis[2][j];
759 originalPoints[2][j] = newCenter[j] + radius * axis[1][j] + radius * axis[2][j];
760 originalPoints[3][j] = newCenter[j] - radius * axis[1][j] + radius * axis[2][j];
761 }
762
763 ClearBounds( lmins, lmaxs );
764
765 // create the bounding planes for the to be projected polygon
766 for ( j = 0 ; j < 4 ; j++ ) {
767 AddPointToBounds( originalPoints[j], lmins, lmaxs );
768
769 VectorSubtract( originalPoints[( j + 1 ) % numPoints], originalPoints[j], v1 );
770 VectorSubtract( originalPoints[j], surf->cullPlane.normal, v2 );
771 VectorSubtract( originalPoints[j], v2, v2 );
772 CrossProduct( v1, v2, lnormals[j] );
773 VectorNormalize( lnormals[j] );
774 ldists[j] = DotProduct( lnormals[j], originalPoints[j] );
775 }
776 numPlanes = numPoints;
777
778 // done.
779
780 for(k = 0, tri = surf->indexes; k < surf->numIndexes; k += 3, tri += 3)
781 {
782 for(j = 0; j < 3; j++)
783 {
784 v = surf->verts[tri[j]].xyz;
785 VectorMA(v, MARKER_OFFSET, surf->cullPlane.normal, clipPoints[0][j]);
786 }
787
788 oldNumPoints = returnedPoints;
789
790 // add the fragments of this face
791 R_AddMarkFragments( 3, clipPoints,
792 numPlanes, lnormals, ldists,
793 maxPoints, pointBuffer,
794 maxFragments, fragmentBuffer,
795 &returnedPoints, &returnedFragments, lmins, lmaxs );
796
797 if ( oldNumPoints != returnedPoints ) {
798 // flag this surface as already having computed ST's
799 fragmentBuffer[returnedFragments - 1].numPoints *= -1;
800
801 // Ridah, calculate ST's
802 for ( j = 0 ; j < ( returnedPoints - oldNumPoints ) ; j++ ) {
803 VectorSubtract( (float *)pointBuffer + 5 * ( oldNumPoints + j ), newCenter, delta );
804 *( (float *)pointBuffer + 5 * ( oldNumPoints + j ) + 3 ) = 0.5 + DotProduct( delta, axis[1] ) * texCoordScale;
805 *( (float *)pointBuffer + 5 * ( oldNumPoints + j ) + 4 ) = 0.5 + DotProduct( delta, axis[2] ) * texCoordScale;
806 }
807 }
808
809 if ( returnedFragments == maxFragments ) {
810 return returnedFragments; // not enough space for more fragments
811 }
812 }
813
814 } else { // old mapping
815
816 // check the normal of this face
817 //if (DotProduct(surf->cullPlane.normal, projectionDir) > 0.0) {
818 // continue;
819 //}
820
821 for(k = 0, tri = surf->indexes; k < surf->numIndexes; k += 3, tri += 3)
822 {
823 for(j = 0; j < 3; j++)
824 {
825 v = surf->verts[tri[j]].xyz;
826 VectorMA(v, MARKER_OFFSET, surf->cullPlane.normal, clipPoints[0][j]);
827 }
828 // add the fragments of this face
829 R_AddMarkFragments( 3, clipPoints,
830 numPlanes, normals, dists,
831 maxPoints, pointBuffer,
832 maxFragments, fragmentBuffer,
833 &returnedPoints, &returnedFragments, mins, maxs );
834 if ( returnedFragments == maxFragments ) {
835 return returnedFragments; // not enough space for more fragments
836 }
837 }
838
839 }
840
841 }
842 else if(*surfaces[i] == SF_TRIANGLES && r_marksOnTriangleMeshes->integer) {
843
844 srfBspSurface_t *surf = (srfBspSurface_t *) surfaces[i];
845
846 for(k = 0, tri = surf->indexes; k < surf->numIndexes; k += 3, tri += 3)
847 {
848 for(j = 0; j < 3; j++)
849 {
850 vec3_t fNormal;
851 v = surf->verts[tri[j]].xyz;
852 R_VaoUnpackNormal(fNormal, surf->verts[tri[j]].normal);
853 VectorMA(v, MARKER_OFFSET, fNormal, clipPoints[0][j]);
854 }
855
856 // add the fragments of this face
857 R_AddMarkFragments(3, clipPoints,
858 numPlanes, normals, dists,
859 maxPoints, pointBuffer,
860 maxFragments, fragmentBuffer, &returnedPoints, &returnedFragments, mins, maxs);
861 if(returnedFragments == maxFragments)
862 {
863 return returnedFragments; // not enough space for more fragments
864 }
865 }
866 }
867 }
868 return returnedFragments;
869 }
870
871