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