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