1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 //
21 // rf_decal.c
22 // FIXME TODO:
23 // - Clean up CG_SpawnDecal parms
24 // - could be re-worked so that decals are only added to the list when their owner surface is
25 // - r_decal_maxFragments r_decal_maxVerts?
26 //
27
28 #include "rf_local.h"
29
30 #define MAX_DECAL_VERTS 512
31 #define MAX_DECAL_FRAGMENTS 384
32
33 typedef struct refFragment_s {
34 int firstVert;
35 int numVerts;
36
37 vec3_t normal;
38
39 mBspSurface_t *surf;
40 } refFragment_t;
41
42 static mesh_t r_decalMesh;
43
44 /*
45 ==============================================================================
46
47 REFRESH FUNCTIONS
48
49 ==============================================================================
50 */
51
52 /*
53 ===============
54 R_AddDecalsToList
55 ===============
56 */
R_AddDecalsToList(void)57 void R_AddDecalsToList (void)
58 {
59 refDecal_t *d;
60 mQ3BspFog_t *fog;
61 mBspSurface_t *surf;
62 uint32 i, j;
63
64 if (!r_drawDecals->intVal)
65 return;
66
67 // Add decal meshes to list
68 for (i=0 ; i<ri.scn.numDecals ; i++) {
69 d = ri.scn.decalList[i];
70
71 // Check the surface visibility
72 fog = NULL;
73 if (d->numSurfaces) {
74 for (j=0 ; j<d->numSurfaces ; j++) {
75 surf = d->surfaces[j];
76 if (!R_CullSurface (surf)) {
77 if (!fog && surf->q3_fog)
78 fog = surf->q3_fog; // FIXME: test me!
79 break;
80 }
81 }
82 if (j == d->numSurfaces)
83 continue;
84 }
85
86 // Frustum cull
87 if (R_CullSphere (d->origin, d->radius, 31))
88 continue;
89
90 // Add to the list
91 R_AddMeshToList (d->poly.shader, d->poly.shaderTime, NULL, fog, MBT_DECAL, d);
92 ri.scn.drawnDecals++;
93 }
94 }
95
96
97 /*
98 ================
99 R_PushDecal
100 ================
101 */
R_PushDecal(meshBuffer_t * mb,meshFeatures_t features)102 void R_PushDecal (meshBuffer_t *mb, meshFeatures_t features)
103 {
104 refDecal_t *d;
105
106 d = (refDecal_t *)mb->mesh;
107 if (d->poly.numVerts > RB_MAX_VERTS)
108 return;
109
110 r_decalMesh.numIndexes = d->numIndexes;
111 r_decalMesh.indexArray = d->indexes;
112
113 r_decalMesh.numVerts = d->poly.numVerts;
114 r_decalMesh.colorArray = d->poly.colors;
115 r_decalMesh.coordArray = (vec2_t *)d->poly.texCoords;
116 r_decalMesh.normalsArray = (vec3_t *)d->normals;
117 r_decalMesh.vertexArray = (vec3_t *)d->poly.vertices;
118
119 RB_PushMesh (&r_decalMesh, features);
120 }
121
122
123 /*
124 ================
125 R_DecalOverflow
126 ================
127 */
R_DecalOverflow(meshBuffer_t * mb)128 qBool R_DecalOverflow (meshBuffer_t *mb)
129 {
130 refDecal_t *d;
131
132 d = (refDecal_t *)mb->mesh;
133 return RB_BackendOverflow (d->poly.numVerts, d->numIndexes);
134 }
135
136
137 /*
138 ================
139 R_DecalInit
140 ================
141 */
R_DecalInit(void)142 void R_DecalInit (void)
143 {
144 r_decalMesh.lmCoordArray = NULL;
145 r_decalMesh.sVectorsArray = NULL;
146 r_decalMesh.tVectorsArray = NULL;
147 r_decalMesh.trNeighborsArray = NULL;
148 r_decalMesh.trNormalsArray = NULL;
149 }
150
151 /*
152 ==============================================================================
153
154 FRAGMENT CLIPPING
155
156 ==============================================================================
157 */
158
159 static uint32 r_numFragmentVerts;
160 static vec3_t r_fragmentVerts[MAX_DECAL_VERTS];
161 static vec3_t r_fragmentNormals[MAX_DECAL_VERTS];
162
163 static uint32 r_numClippedFragments;
164 static refFragment_t r_clippedFragments[MAX_DECAL_FRAGMENTS];
165
166 static uint32 r_fragmentFrame = 0;
167 static cBspPlane_t r_fragmentPlanes[6];
168
169 static vec3_t r_decalOrigin;
170 static vec3_t r_decalNormal;
171 static float r_decalRadius;
172
173 /*
174 ==============================================================================
175
176 QUAKE II FRAGMENT CLIPPING
177
178 ==============================================================================
179 */
180
181 /*
182 =================
183 R_Q2BSP_ClipPoly
184 =================
185 */
R_Q2BSP_ClipPoly(int nump,vec4_t vecs,int stage,refFragment_t * fr)186 static void R_Q2BSP_ClipPoly (int nump, vec4_t vecs, int stage, refFragment_t *fr)
187 {
188 cBspPlane_t *plane;
189 qBool front, back;
190 vec4_t newv[MAX_DECAL_VERTS];
191 int sides[MAX_DECAL_VERTS];
192 float dists[MAX_DECAL_VERTS];
193 float *v, d;
194 int newc, i, j;
195
196 if (nump > MAX_DECAL_VERTS - 2) {
197 Com_Printf (PRNT_ERROR, "R_Q2BSP_ClipPoly: nump > MAX_DECAL_VERTS - 2");
198 return;
199 }
200
201 if (stage == 6) {
202 // Fully clipped
203 if (nump > 2) {
204 fr->numVerts = nump;
205 fr->firstVert = r_numFragmentVerts;
206
207 if (r_numFragmentVerts+nump >= MAX_DECAL_VERTS)
208 nump = MAX_DECAL_VERTS - r_numFragmentVerts;
209
210 for (i=0, v=vecs ; i<nump ; i++, v+=4) {
211 Vec3Copy (fr->normal, r_fragmentNormals[r_numFragmentVerts + i]);
212 Vec3Copy (v, r_fragmentVerts[r_numFragmentVerts + i]);
213 }
214
215 r_numFragmentVerts += nump;
216 }
217
218 return;
219 }
220
221 front = back = qFalse;
222 plane = &r_fragmentPlanes[stage];
223 for (i=0, v=vecs ; i<nump ; i++ , v+=4) {
224 d = PlaneDiff (v, plane);
225 if (d > LARGE_EPSILON) {
226 front = qTrue;
227 sides[i] = SIDE_FRONT;
228 }
229 else if (d < -LARGE_EPSILON) {
230 back = qTrue;
231 sides[i] = SIDE_BACK;
232 }
233 else
234 sides[i] = SIDE_ON;
235
236 dists[i] = d;
237 }
238
239 if (!front)
240 return;
241
242 // Clip it
243 sides[i] = sides[0];
244 dists[i] = dists[0];
245 Vec3Copy (vecs, (vecs + (i * 4)));
246 newc = 0;
247
248 for (i=0, v=vecs ; i<nump ; i++, v+=4) {
249 switch (sides[i]) {
250 case SIDE_FRONT:
251 Vec3Copy (v, newv[newc]);
252 newc++;
253 break;
254 case SIDE_BACK:
255 break;
256 case SIDE_ON:
257 Vec3Copy (v, newv[newc]);
258 newc++;
259 break;
260 }
261
262 if (sides[i] == SIDE_ON
263 || sides[i+1] == SIDE_ON
264 || sides[i+1] == sides[i])
265 continue;
266
267 d = dists[i] / (dists[i] - dists[i+1]);
268 for (j=0 ; j<3 ; j++)
269 newv[newc][j] = v[j] + d * (v[j+4] - v[j]);
270 newc++;
271 }
272
273 // Continue
274 R_Q2BSP_ClipPoly (newc, newv[0], stage+1, fr);
275 }
276
277
278 /*
279 =================
280 R_Q2BSP_PlanarClipFragment
281 =================
282 */
R_Q2BSP_PlanarClipFragment(mBspNode_t * node,mBspSurface_t * surf)283 static void R_Q2BSP_PlanarClipFragment (mBspNode_t *node, mBspSurface_t *surf)
284 {
285 int i;
286 float *v, *v2, *v3;
287 refFragment_t *fr;
288 vec4_t verts[MAX_DECAL_VERTS];
289
290 v = surf->mesh->vertexArray[0];
291
292 // Copy vertex data and clip to each triangle
293 for (i=0; i<surf->mesh->numVerts-2 ; i++) {
294 fr = &r_clippedFragments[r_numClippedFragments];
295 fr->numVerts = 0;
296 fr->surf = surf;
297 Vec3Copy (surf->mesh->normalsArray[i], fr->normal);
298
299 v2 = surf->mesh->vertexArray[0] + (i+1) * 3;
300 v3 = surf->mesh->vertexArray[0] + (i+2) * 3;
301
302 Vec3Copy (v , verts[0]);
303 Vec3Copy (v2, verts[1]);
304 Vec3Copy (v3, verts[2]);
305
306 R_Q2BSP_ClipPoly (3, verts[0], 0, fr);
307 if (fr->numVerts && (r_numFragmentVerts >= MAX_DECAL_VERTS || ++r_numClippedFragments >= MAX_DECAL_FRAGMENTS))
308 return;
309 }
310 }
311
312
313 /*
314 =================
315 R_Q2BSP_FragmentNode
316 =================
317 */
R_Q2BSP_FragmentNode(mBspNode_t * node)318 static void R_Q2BSP_FragmentNode (mBspNode_t *node)
319 {
320 float dist;
321 mBspLeaf_t *leaf;
322 mBspSurface_t *surf, **mark;
323
324 mark0:
325 if (r_numFragmentVerts >= MAX_DECAL_VERTS || r_numClippedFragments >= MAX_DECAL_FRAGMENTS)
326 return; // Already reached the limit somewhere else
327
328 if (node->c.q2_contents != -1) {
329 if (node->c.q2_contents == CONTENTS_SOLID)
330 return;
331
332 // Leaf
333 leaf = (mBspLeaf_t *)node;
334 if (!leaf->q2_firstDecalSurface)
335 return;
336
337 mark = leaf->q2_firstDecalSurface;
338 do {
339 if (r_numFragmentVerts >= MAX_DECAL_VERTS || r_numClippedFragments >= MAX_DECAL_FRAGMENTS)
340 return;
341
342 surf = *mark++;
343 if (!surf)
344 continue;
345
346 if (surf->fragmentFrame == r_fragmentFrame)
347 continue; // Already touched
348 surf->fragmentFrame = r_fragmentFrame;
349
350 if (surf->q2_numEdges < 3)
351 continue; // Bogus face
352
353 if (surf->q2_flags & SURF_PLANEBACK) {
354 if (DotProduct(r_decalNormal, surf->q2_plane->normal) > -0.5f)
355 continue; // Greater than 60 degrees
356 }
357 else {
358 if (DotProduct(r_decalNormal, surf->q2_plane->normal) < 0.5f)
359 continue; // Greater than 60 degrees
360 }
361
362 // Clip
363 R_Q2BSP_PlanarClipFragment (node, surf);
364 } while (*mark);
365
366 return;
367 }
368
369 dist = PlaneDiff (r_decalOrigin, node->c.plane);
370 if (dist > r_decalRadius) {
371 node = node->children[0];
372 goto mark0;
373 }
374 if (dist < -r_decalRadius) {
375 node = node->children[1];
376 goto mark0;
377 }
378
379 R_Q2BSP_FragmentNode (node->children[0]);
380 R_Q2BSP_FragmentNode (node->children[1]);
381 }
382
383 /*
384 ==============================================================================
385
386 QUAKE III FRAGMENT CLIPPING
387
388 ==============================================================================
389 */
390
391 /*
392 =================
393 R_Q3BSP_WindingClipFragment
394
395 This function operates on windings (convex polygons without
396 any points inside) like triangles, quads, etc. The output is
397 a convex fragment (polygon, trifan) which the result of clipping
398 the input winding by six fragment planes.
399 =================
400 */
R_Q3BSP_WindingClipFragment(vec3_t * wVerts,int numVerts,refFragment_t * fr)401 static void R_Q3BSP_WindingClipFragment (vec3_t *wVerts, int numVerts, refFragment_t *fr)
402 {
403 int i, j;
404 int stage, newc, numv;
405 cBspPlane_t *plane;
406 qBool front;
407 float *v, *nextv, d;
408 float dists[MAX_DECAL_VERTS+1];
409 int sides[MAX_DECAL_VERTS+1];
410 vec3_t *verts, *newverts, newv[2][MAX_DECAL_VERTS];
411
412 numv = numVerts;
413 verts = wVerts;
414
415 for (stage=0, plane=r_fragmentPlanes ; stage<6 ; stage++, plane++) {
416 for (i=0, v=verts[0], front=qFalse ; i<numv ; i++, v+=3) {
417 d = PlaneDiff (v, plane);
418
419 if (d > LARGE_EPSILON) {
420 front = qTrue;
421 sides[i] = SIDE_FRONT;
422 }
423 else if (d < -LARGE_EPSILON) {
424 sides[i] = SIDE_BACK;
425 }
426 else {
427 front = qTrue;
428 sides[i] = SIDE_ON;
429 }
430 dists[i] = d;
431 }
432
433 if (!front)
434 return;
435
436 // Clip it
437 sides[i] = sides[0];
438 dists[i] = dists[0];
439
440 newc = 0;
441 newverts = newv[stage & 1];
442
443 for (i=0, v=verts[0] ; i<numv ; i++, v+=3) {
444 switch (sides[i]) {
445 case SIDE_FRONT:
446 if (newc == MAX_DECAL_VERTS)
447 return;
448 Vec3Copy (v, newverts[newc]);
449 newc++;
450 break;
451
452 case SIDE_BACK:
453 break;
454
455 case SIDE_ON:
456 if (newc == MAX_DECAL_VERTS)
457 return;
458 Vec3Copy (v, newverts[newc]);
459 newc++;
460 break;
461 }
462
463 if (sides[i] == SIDE_ON
464 || sides[i+1] == SIDE_ON
465 || sides[i+1] == sides[i])
466 continue;
467 if (newc == MAX_DECAL_VERTS)
468 return;
469
470 d = dists[i] / (dists[i] - dists[i+1]);
471 nextv = (i == numv - 1) ? verts[0] : v + 3;
472 for (j=0 ; j<3 ; j++)
473 newverts[newc][j] = v[j] + d * (nextv[j] - v[j]);
474
475 newc++;
476 }
477
478 if (newc <= 2)
479 return;
480
481 // Continue with new verts
482 numv = newc;
483 verts = newverts;
484 }
485
486 // Fully clipped
487 if (r_numFragmentVerts + numv > MAX_DECAL_VERTS)
488 return;
489
490 fr->numVerts = numv;
491 fr->firstVert = r_numFragmentVerts;
492
493 for (i=0, v=verts[0] ; i<numv ; i++, v+=3) {
494 Vec3Copy (fr->normal, r_fragmentNormals[r_numFragmentVerts + i]);
495 Vec3Copy (v, r_fragmentVerts[r_numFragmentVerts + i]);
496 }
497 r_numFragmentVerts += numv;
498 }
499
500
501 /*
502 =================
503 R_Q3BSP_PlanarSurfClipFragment
504
505 NOTE: one might want to combine this function with
506 R_Q3BSP_WindingClipFragment for special cases like trifans (q1 and
507 q2 polys) or tristrips for ultra-fast clipping, providing there's
508 enough stack space (depending on MAX_DECAL_VERTS value).
509 =================
510 */
R_Q3BSP_PlanarSurfClipFragment(mBspSurface_t * surf,mBspNode_t * node)511 static void R_Q3BSP_PlanarSurfClipFragment (mBspSurface_t *surf, mBspNode_t *node)
512 {
513 int i;
514 mesh_t *mesh;
515 index_t *index;
516 vec3_t *normals, *verts, tri[3];
517 refFragment_t *fr;
518
519 if (DotProduct (r_decalNormal, surf->q3_origin) < 0.5)
520 return; // Greater than 60 degrees
521
522 mesh = surf->mesh;
523
524 // Clip each triangle individually
525 index = mesh->indexArray;
526 normals = mesh->normalsArray;
527 verts = mesh->vertexArray;
528 for (i=0 ; i<mesh->numIndexes ; i+=3, index+=3) {
529 fr = &r_clippedFragments[r_numClippedFragments];
530 fr->numVerts = 0;
531 fr->surf = surf;
532
533 Vec3Copy (normals[index[0]], fr->normal);
534
535 Vec3Copy (verts[index[0]], tri[0]);
536 Vec3Copy (verts[index[1]], tri[1]);
537 Vec3Copy (verts[index[2]], tri[2]);
538
539 R_Q3BSP_WindingClipFragment (tri, 3, fr);
540 if (fr->numVerts && (r_numFragmentVerts == MAX_DECAL_VERTS || ++r_numClippedFragments == MAX_DECAL_FRAGMENTS))
541 return;
542 }
543 }
544
545
546 /*
547 =================
548 R_Q3BSP_PatchSurfClipFragment
549 =================
550 */
R_Q3BSP_PatchSurfClipFragment(mBspSurface_t * surf,mBspNode_t * node)551 static void R_Q3BSP_PatchSurfClipFragment (mBspSurface_t *surf, mBspNode_t *node)
552 {
553 int i;
554 mesh_t *mesh;
555 index_t *index;
556 vec3_t *normals, *verts, tri[3];
557 vec3_t dir1, dir2, snorm;
558 refFragment_t *fr;
559
560 mesh = surf->mesh;
561
562 // Clip each triangle individually
563 index = mesh->indexArray;
564 normals = mesh->normalsArray;
565 verts = mesh->vertexArray;
566 for (i=0 ; i<mesh->numIndexes ; i+=3, index+=3) {
567 fr = &r_clippedFragments[r_numClippedFragments];
568 fr->numVerts = 0;
569 fr->surf = surf;
570
571 Vec3Copy (normals[index[0]], fr->normal);
572
573 Vec3Copy (verts[index[0]], tri[0]);
574 Vec3Copy (verts[index[1]], tri[1]);
575 Vec3Copy (verts[index[2]], tri[2]);
576
577 // Calculate two mostly perpendicular edge directions
578 Vec3Subtract (tri[0], tri[1], dir1);
579 Vec3Subtract (tri[2], tri[1], dir2);
580
581 // We have two edge directions, we can calculate a third vector from
582 // them, which is the direction of the triangle normal
583 CrossProduct (dir1, dir2, snorm);
584
585 // We multiply 0.5 by length of snorm to avoid normalizing
586 if (DotProduct(r_decalNormal, snorm) < 0.5f * Vec3Length(snorm))
587 continue; // Greater than 60 degrees
588
589 R_Q3BSP_WindingClipFragment (tri, 3, fr);
590 if (fr->numVerts && (r_numFragmentVerts == MAX_DECAL_VERTS || ++r_numClippedFragments == MAX_DECAL_FRAGMENTS))
591 return;
592 }
593 }
594
595
596 /*
597 =================
598 R_Q3BSP_FragmentNode
599 =================
600 */
R_Q3BSP_FragmentNode(void)601 static void R_Q3BSP_FragmentNode (void)
602 {
603 int stackdepth = 0;
604 float dist;
605 mBspNode_t *node, *localStack[2048];
606 mBspLeaf_t *leaf;
607 mBspSurface_t *surf, **mark;
608
609 node = ri.scn.worldModel->bspModel.nodes;
610 for (stackdepth=0 ; ; ) {
611 if (node->c.plane == NULL) {
612 leaf = (mBspLeaf_t *)node;
613 if (!leaf->q3_firstFragmentSurface)
614 goto nextNodeOnStack;
615
616 mark = leaf->q3_firstFragmentSurface;
617 do {
618 if (r_numFragmentVerts == MAX_DECAL_VERTS || r_numClippedFragments == MAX_DECAL_FRAGMENTS)
619 return; // Already reached the limit
620
621 surf = *mark++;
622 if (surf->fragmentFrame == r_fragmentFrame)
623 continue;
624 surf->fragmentFrame = r_fragmentFrame;
625
626 if (surf->q3_faceType == FACETYPE_PLANAR)
627 R_Q3BSP_PlanarSurfClipFragment (surf, node);
628 else
629 R_Q3BSP_PatchSurfClipFragment (surf, node);
630 } while (*mark);
631
632 if (r_numFragmentVerts == MAX_DECAL_VERTS || r_numClippedFragments == MAX_DECAL_FRAGMENTS)
633 return; // Already reached the limit
634
635 nextNodeOnStack:
636 if (!stackdepth)
637 break;
638 node = localStack[--stackdepth];
639 continue;
640 }
641
642 dist = PlaneDiff (r_decalOrigin, node->c.plane);
643 if (dist > r_decalRadius) {
644 node = node->children[0];
645 continue;
646 }
647
648 if (dist >= -r_decalRadius && (stackdepth < sizeof (localStack) / sizeof (mBspNode_t *)))
649 localStack[stackdepth++] = node->children[0];
650 node = node->children[1];
651 }
652 }
653
654 // ===========================================================================
655
656 /*
657 =================
658 R_GetClippedFragments
659 =================
660 */
R_GetClippedFragments(vec3_t origin,float radius,vec3_t axis[3])661 static uint32 R_GetClippedFragments (vec3_t origin, float radius, vec3_t axis[3])
662 {
663 int i;
664 float d;
665
666 if (ri.def.rdFlags & RDF_NOWORLDMODEL)
667 return 0;
668 if (!ri.scn.worldModel->bspModel.nodes)
669 return 0;
670
671 r_fragmentFrame++;
672
673 // Store data
674 Vec3Copy (origin, r_decalOrigin);
675 Vec3Copy (axis[0], r_decalNormal);
676 r_decalRadius = radius;
677
678 // Initialize fragments
679 r_numFragmentVerts = 0;
680 r_numClippedFragments = 0;
681
682 // Calculate clipping planes
683 for (i=0 ; i<3; i++) {
684 d = DotProduct (origin, axis[i]);
685
686 Vec3Copy (axis[i], r_fragmentPlanes[i*2].normal);
687 r_fragmentPlanes[i*2].dist = d - radius;
688 r_fragmentPlanes[i*2].type = PlaneTypeForNormal (r_fragmentPlanes[i*2].normal);
689
690 Vec3Negate (axis[i], r_fragmentPlanes[i*2+1].normal);
691 r_fragmentPlanes[i*2+1].dist = -d - radius;
692 r_fragmentPlanes[i*2+1].type = PlaneTypeForNormal (r_fragmentPlanes[i*2+1].normal);
693 }
694
695 if (ri.scn.worldModel->type == MODEL_Q3BSP)
696 R_Q3BSP_FragmentNode ();
697 else
698 R_Q2BSP_FragmentNode (ri.scn.worldModel->bspModel.nodes);
699
700 return r_numClippedFragments;
701 }
702
703 /*
704 ==============================================================================
705
706 EXPORT FUNCTIONS
707
708 ==============================================================================
709 */
710
711 /*
712 ===============
713 R_CreateDecal
714 ===============
715 */
R_CreateDecal(refDecal_t * d,vec3_t origin,vec3_t direction,float angle,float size)716 qBool R_CreateDecal (refDecal_t *d, vec3_t origin, vec3_t direction, float angle, float size)
717 {
718 vec3_t *clipNormals, *clipVerts;
719 refFragment_t *fr, *clipFragments;
720 vec3_t axis[3];
721 uint32 numFragments, i, k;
722 byte *buffer;
723 uint32 totalIndexes;
724 index_t *outIndexes;
725 uint32 totalVerts;
726 float *outNormals;
727 float *outVerts;
728 float *outCoords;
729 uint32 totalSurfaces;
730 mBspSurface_t **outSurfs;
731 vec3_t mins, maxs;
732 vec3_t temp;
733 int j;
734
735 if (!d)
736 return qFalse;
737
738 // See if there's room and it's valid
739 if (!size || Vec3Compare (direction, vec3Origin)) {
740 Com_DevPrintf (PRNT_WARNING, "WARNING: attempted to create a decal with an invalid %s\n", !size ? "size" : "direction");
741 return qFalse;
742 }
743
744 // Negativity check
745 if (size < 0)
746 size *= -1;
747
748 // Calculate orientation matrix
749 VectorNormalizef (direction, axis[0]);
750 PerpendicularVector (axis[0], axis[1]);
751 RotatePointAroundVector (axis[2], axis[0], axis[1], angle);
752 CrossProduct (axis[0], axis[2], axis[1]);
753
754 // Clip it
755 clipNormals = r_fragmentNormals;
756 clipVerts = r_fragmentVerts;
757 clipFragments = r_clippedFragments;
758 numFragments = R_GetClippedFragments (origin, size, axis);
759 if (!numFragments)
760 return qFalse; // No valid fragments
761
762 // Find the total allocation size
763 totalIndexes = 0;
764 totalVerts = 0;
765 totalSurfaces = 0;
766 for (i=0, fr=clipFragments ; i<numFragments ; fr++, i++) {
767 totalIndexes += (fr->numVerts - 2) * 3;
768 totalVerts += fr->numVerts;
769
770 // NULL out duplicate surfaces to save redundant cull attempts
771 if (fr->surf) {
772 for (k=i+1 ; k<numFragments ; k++) {
773 if (clipFragments[k].surf == fr->surf)
774 clipFragments[k].surf = NULL;
775 }
776
777 totalSurfaces++;
778 }
779 }
780 assert (totalIndexes && totalVerts);
781
782 // Store values
783 Vec3Copy (origin, d->origin);
784 d->numIndexes = totalIndexes;
785 d->poly.numVerts = totalVerts;
786 d->numSurfaces = totalSurfaces;
787
788 // Allocate space
789 buffer = Mem_PoolAlloc ((d->poly.numVerts * sizeof (vec3_t) * 2)
790 + (d->numIndexes * sizeof (index_t))
791 + (d->poly.numVerts * sizeof (vec2_t))
792 + (d->poly.numVerts * sizeof (bvec4_t))
793 + (d->numSurfaces * sizeof (struct mBspSurface_s *)), ri.decalSysPool, 0);
794 outVerts = (float *)buffer;
795 d->poly.vertices = (vec3_t *)buffer;
796
797 buffer += d->poly.numVerts * sizeof (vec3_t);
798 outNormals = (float *)buffer;
799 d->normals = (vec3_t *)buffer;
800
801 buffer += d->poly.numVerts * sizeof (vec3_t);
802 outIndexes = d->indexes = (int *)buffer;
803
804 buffer += d->numIndexes * sizeof (index_t);
805 outCoords = (float *)buffer;
806 d->poly.texCoords = (vec2_t *)buffer;
807
808 buffer += d->poly.numVerts * sizeof (vec2_t);
809 d->poly.colors = (bvec4_t *)buffer;
810
811 buffer += d->poly.numVerts * sizeof (bvec4_t);
812 d->surfaces = outSurfs = (struct mBspSurface_s **)buffer;
813
814 // Store vertex data
815 ClearBounds (mins, maxs);
816 totalVerts = 0;
817 totalIndexes = 0;
818
819 size = 0.5f / size;
820 Vec3Scale (axis[1], size, axis[1]);
821 Vec3Scale (axis[2], size, axis[2]);
822 for (i=0, fr=clipFragments ; i<numFragments ; fr++, i++) {
823 if (fr->surf)
824 *outSurfs++ = fr->surf;
825
826 // Indexes
827 outIndexes = d->indexes + totalIndexes;
828 totalIndexes += (fr->numVerts - 2) * 3;
829 for (j=2 ; j<fr->numVerts ; j++) {
830 outIndexes[0] = totalVerts;
831 outIndexes[1] = totalVerts + j - 1;
832 outIndexes[2] = totalVerts + j;
833
834 outIndexes += 3;
835 }
836
837 for (j=0 ; j<fr->numVerts ; j++) {
838 // Vertices
839 outVerts[0] = clipVerts[fr->firstVert+j][0];
840 outVerts[1] = clipVerts[fr->firstVert+j][1];
841 outVerts[2] = clipVerts[fr->firstVert+j][2];
842
843 // Normals
844 outNormals[0] = clipNormals[fr->firstVert+j][0];
845 outNormals[1] = clipNormals[fr->firstVert+j][1];
846 outNormals[2] = clipNormals[fr->firstVert+j][2];
847
848 // Bounds
849 AddPointToBounds (outVerts, mins, maxs);
850
851 // Coords
852 Vec3Subtract (outVerts, origin, temp);
853 outCoords[0] = DotProduct (temp, axis[1]) + 0.5f;
854 outCoords[1] = DotProduct (temp, axis[2]) + 0.5f;
855
856 outVerts += 3;
857 outNormals += 3;
858 outCoords += 2;
859 }
860
861 totalVerts += fr->numVerts;
862 }
863
864 // Calculate radius
865 d->radius = RadiusFromBounds (mins, maxs);
866 assert (d->radius);
867 return qTrue;
868 }
869
870
871 /*
872 ===============
873 R_FreeDecal
874
875 Releases decal memory for index and vertex data.
876 ===============
877 */
R_FreeDecal(refDecal_t * d)878 qBool R_FreeDecal (refDecal_t *d)
879 {
880 if (!d || !d->poly.vertices)
881 return qFalse;
882
883 Mem_Free (d->poly.vertices);
884 d->poly.vertices = NULL;
885 return qTrue;
886 }
887