1 /*
2 Copyright (C) 2001-2002 Charles Hollemeersch
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 Adds decal support...
21 Decals are similar to particles currently...
22 The code to generate them is based on the article "Applying decals to arbitrary surfaces"
23 by "Eric Lengyel" in "Game Programming Gems 2"
24 */
25
26 #include "quakedef.h"
27 #include "r_local.h"
28
29 #define MAX_DECALS 1024 // default max # of decals at one
30 // time
31 #define ABSOLUTE_MIN_DECALS 0 // no fewer than this no matter what's
32 // on the command line
33
34
35 decal_t *active_decals, *free_decals;
36
37 decal_t *decals;
38 int r_numdecals;
39
40 void DecalClipLeaf(decal_t *dec, mleaf_t *leaf);
41 void DecalWalkBsp_R(decal_t *dec, mnode_t *node);
42 int DecalClipPolygonAgainstPlane(plane_t *plane, int vertexCount, vec3_t *vertex, vec3_t *newVertex);
43 int DecalClipPolygon(int vertexCount, vec3_t *vertices, vec3_t *newVertex);
44
45 /*
46 ===============
47 R_InitDecals
48 ===============
49 */
R_InitDecals(void)50 void R_InitDecals (void)
51 {
52 int i;
53
54 i = COM_CheckParm ("-decals");
55
56 if (i)
57 {
58 r_numdecals = (int)(Q_atoi(com_argv[i+1]));
59 if (r_numdecals < ABSOLUTE_MIN_DECALS)
60 r_numdecals = ABSOLUTE_MIN_DECALS;
61 }
62 else
63 {
64 r_numdecals = MAX_DECALS;
65 }
66
67 decals = (decal_t *)
68 Hunk_AllocName (r_numdecals * sizeof(decal_t), "decals");
69 }
70
71 /*
72 ===============
73 R_ClearDecals
74 ===============
75 */
R_ClearDecals(void)76 void R_ClearDecals (void)
77 {
78 int i;
79
80 free_decals = &decals[0];
81 active_decals = NULL;
82
83 for (i=0 ;i<r_numdecals ; i++)
84 decals[i].next = &decals[i+1];
85 decals[r_numdecals-1].next = NULL;
86 }
87
88 static plane_t leftPlane, rightPlane, bottomPlane, topPlane, backPlane, frontPlane;
89
R_SpawnDecal(vec3_t center,vec3_t normal,vec3_t tangent,ParticleEffect_t * effect)90 void R_SpawnDecal(vec3_t center, vec3_t normal, vec3_t tangent, ParticleEffect_t *effect)
91 {
92
93 float width, height, depth, d;
94 vec3_t binormal;
95 decal_t *dec;
96 float one_over_w, one_over_h;
97 int a;
98 vec3_t test = {0.5, 0.5, 0.5};
99 vec3_t t;
100
101 //allocate decal
102 if (!free_decals)
103 return;
104 dec = free_decals;
105 free_decals = dec->next;
106 dec->next = active_decals;
107 active_decals = dec;
108
109 //VectorNormalize(tangent);
110
111 VectorNormalize(test);
112 CrossProduct(normal,test,tangent);
113
114 //Con_Printf("StartDecail\n");
115 VectorCopy(center, dec->origin);
116 VectorCopy(tangent, dec->tangent);
117 VectorCopy(normal, dec->normal);
118
119 VectorNormalize(tangent);
120 VectorNormalize(normal);
121 CrossProduct(normal, tangent, binormal);
122 VectorNormalize(binormal);
123
124 width = RandomMinMax(effect->sizemin, effect->sizemax);
125 height = width;
126 depth = width*0.5;
127 dec->radius = max(max(width,height),depth);
128 dec->texture = effect->texture;
129 dec->lifetime = RandomMinMax(effect->lifemin, effect->lifemax);
130 dec->die = cl.time + dec->lifetime;
131
132 dec->startcolor[0] = RandomMinMax(effect->startcolormin[0], effect->startcolormax[0]);
133 dec->startcolor[1] = RandomMinMax(effect->startcolormin[1], effect->startcolormax[1]);
134 dec->startcolor[2] = RandomMinMax(effect->startcolormin[2], effect->startcolormax[2]);
135 dec->endcolor[0] = RandomMinMax(effect->endcolormin[0], effect->endcolormax[0]);
136 dec->endcolor[1] = RandomMinMax(effect->endcolormin[1], effect->endcolormax[1]);
137 dec->endcolor[2] = RandomMinMax(effect->endcolormin[2], effect->endcolormax[2]);
138
139 dec->srcblend = effect->srcblend;
140 dec->dstblend = effect->dstblend;
141
142 /*
143 -= Hack: don't clip decal just draw a quad =-
144
145 VectorScale(binormal,10,binormal);
146 VectorScale(tangent,10,tangent);
147 VectorCopy(center,dec->vertexArray[0]);
148 VectorAdd(center,tangent,t);
149 VectorCopy(t,dec->vertexArray[1]);
150 VectorAdd(t,binormal,t);
151 VectorCopy(t,dec->vertexArray[2]);
152 VectorAdd(center,binormal,t);
153 VectorCopy(t,dec->vertexArray[3]);
154
155 dec->vertexCount = 4;
156 dec->triangleCount = 2;
157
158 dec->triangleArray[0][0] = 0;
159 dec->triangleArray[0][1] = 1;
160 dec->triangleArray[0][2] = 2;
161
162 dec->triangleArray[1][0] = 0;
163 dec->triangleArray[1][1] = 2;
164 dec->triangleArray[1][2] = 3;
165 */
166
167 // Calculate boundary planes
168 d = DotProduct(center, tangent);
169 VectorCopy(tangent,leftPlane.normal);
170 leftPlane.dist = -(width * 0.5 - d);
171 VectorInverse(tangent);
172 VectorCopy(tangent,rightPlane.normal);
173 VectorInverse(tangent);
174 rightPlane.dist = -(width * 0.5 + d);
175
176 d = DotProduct(center, binormal);
177 VectorCopy(binormal,bottomPlane.normal);
178 bottomPlane.dist = -(height * 0.5 - d);
179 VectorInverse(binormal);
180 VectorCopy(binormal,topPlane.normal);
181 VectorInverse(binormal);
182 topPlane.dist = -(height * 0.5 + d);
183
184 d = DotProduct(center, normal);
185 VectorCopy(normal,backPlane.normal);
186 backPlane.dist = -(depth - d);
187 VectorInverse(normal);
188 VectorCopy(normal,frontPlane.normal);
189 VectorInverse(normal);
190 frontPlane.dist = -(depth + d);
191
192 // Begin with empty mesh
193 dec->vertexCount = 0;
194 dec->triangleCount = 0;
195
196 //Clip decal to bsp
197 DecalWalkBsp_R(dec, cl.worldmodel->nodes);
198
199 //This happens when a decal is to far from any surface or the surface is to steeply sloped
200 if (dec->triangleCount == 0) {
201 //deallocate decal
202 active_decals = dec->next;
203 dec->next = free_decals;
204 free_decals = dec;
205 return;
206 }
207
208 //Assign texture mapping coordinates
209 one_over_w = 1.0F / width;
210 one_over_h = 1.0F / height;
211 for (a = 0; a < dec->vertexCount; a++)
212 {
213 float s, t;
214 vec3_t v;
215 VectorSubtract(dec->vertexArray[a],center,v);
216 s = DotProduct(v, tangent) * one_over_w + 0.5F;
217 t = DotProduct(v, binormal) * one_over_h + 0.5F;
218 dec->texcoordArray[a][0] = s;
219 dec->texcoordArray[a][1] = t;
220 }
221 }
222
DecalWalkBsp_R(decal_t * dec,mnode_t * node)223 void DecalWalkBsp_R(decal_t *dec, mnode_t *node)
224 {
225 mplane_t *plane;
226 float dist;
227 mleaf_t *leaf;
228
229 if (node->contents < 0) {
230
231 //we are in a leaf
232 leaf = (mleaf_t *)node;
233 DecalClipLeaf(dec, leaf);
234 return;
235 }
236
237 plane = node->plane;
238 dist = DotProduct (dec->origin, plane->normal) - plane->dist;
239
240 if (dist > dec->radius)
241 {
242 DecalWalkBsp_R (dec, node->children[0]);
243 return;
244 }
245 if (dist < -dec->radius)
246 {
247 DecalWalkBsp_R (dec, node->children[1]);
248 return;
249 }
250
251 DecalWalkBsp_R (dec, node->children[0]);
252 DecalWalkBsp_R (dec, node->children[1]);
253 }
254
DecalAddPolygon(decal_t * dec,int vertcount,vec3_t * vertices)255 qboolean DecalAddPolygon(decal_t *dec, int vertcount, vec3_t *vertices)
256 {
257 int *triangle;
258 int count;
259 int a, b;
260 float f;
261
262 //Con_Printf("AddPolygon %i %i\n",vertcount, dec->vertexCount);
263 count = dec->vertexCount;
264 if (count + vertcount >= MAX_DECAL_VERTICES)
265 return false;
266
267 if (dec->triangleCount + vertcount-2 >= MAX_DECAL_TRIANGLES)
268 return false;
269
270 // Add polygon as a triangle fan
271 triangle = &dec->triangleArray[dec->triangleCount][0];
272 for (a = 2; a < vertcount; a++)
273 {
274 dec->triangleArray[dec->triangleCount][0] = count;
275 dec->triangleArray[dec->triangleCount][1] = (count + a - 1);
276 dec->triangleArray[dec->triangleCount][2] = (count + a );
277 dec->triangleCount++;
278 }
279
280 // Assign vertex colors
281 for (b = 0; b < vertcount; b++)
282 {
283 VectorCopy(vertices[b],dec->vertexArray[count]);
284 count++;
285 }
286
287 dec->vertexCount = count;
288 return true;
289 }
290
291 const float decalEpsilon = 0.001;
292
DecalClipLeaf(decal_t * dec,mleaf_t * leaf)293 void DecalClipLeaf(decal_t *dec, mleaf_t *leaf)
294 {
295 int a;
296 vec3_t newVertex[64], t1, t2, t3;
297 int c;
298 msurface_t **surf;
299
300 //Con_Printf("Clipleaf\n");
301 c = leaf->nummarksurfaces;
302 surf = leaf->firstmarksurface;
303
304 //for all surfaces in the leaf
305 for (c=0; c<leaf->nummarksurfaces; c++, surf++) {
306
307 glpoly_t *poly;
308 int i,count;
309 float *v;
310
311 poly = (*surf)->polys;
312
313 v = (float *)(&globalVertexTable[poly->firstvertex]);
314 for (i=0 ; i<poly->numverts ; i++, v+= VERTEXSIZE)
315 {
316 newVertex[i][0] = v[0];
317 newVertex[i][1] = v[1];
318 newVertex[i][2] = v[2];
319 }
320
321 VectorCopy((*surf)->plane->normal,t3);
322
323 if ((*surf)->flags & SURF_PLANEBACK) {
324 VectorInverse(t3);
325 }
326
327
328 //avoid backfacing and ortogonal facing faces to recieve decal parts
329 if (DotProduct(dec->normal, t3) > decalEpsilon)
330 {
331 count = DecalClipPolygon(poly->numverts, newVertex, newVertex);
332 if ((count != 0) && (!DecalAddPolygon(dec, count, newVertex))) break;
333 }
334 }
335 }
336
DecalClipPolygon(int vertexCount,vec3_t * vertices,vec3_t * newVertex)337 int DecalClipPolygon(int vertexCount, vec3_t *vertices, vec3_t *newVertex)
338 {
339 vec3_t tempVertex[64];
340
341 // Clip against all six planes
342 int count = DecalClipPolygonAgainstPlane(&leftPlane, vertexCount, vertices, tempVertex);
343 if (count != 0)
344 {
345 count = DecalClipPolygonAgainstPlane(&rightPlane, count, tempVertex, newVertex);
346 if (count != 0)
347 {
348 count = DecalClipPolygonAgainstPlane(&bottomPlane, count, newVertex, tempVertex);
349 if (count != 0)
350 {
351 count = DecalClipPolygonAgainstPlane(&topPlane, count, tempVertex, newVertex);
352 if (count != 0)
353 {
354 count = DecalClipPolygonAgainstPlane(&backPlane, count, newVertex, tempVertex);
355 if (count != 0)
356 {
357 count = DecalClipPolygonAgainstPlane(&frontPlane, count, tempVertex, newVertex);
358 }
359 }
360 }
361 }
362 }
363
364 return count;
365 }
366
DecalClipPolygonAgainstPlane(plane_t * plane,int vertexCount,vec3_t * vertex,vec3_t * newVertex)367 int DecalClipPolygonAgainstPlane(plane_t *plane, int vertexCount, vec3_t *vertex, vec3_t *newVertex)
368 {
369 qboolean negative[65];
370 int a, count, b, c;
371 float sect, t;
372 vec3_t v, v1, v2;
373
374 // Classify vertices
375 int negativeCount = 0;
376 for (a = 0; a < vertexCount; a++)
377 {
378 qboolean neg = ((DotProduct(plane->normal, vertex[a]) - plane->dist) < 0.0);
379 negative[a] = neg;
380 negativeCount += neg;
381 }
382
383 // Discard this polygon if it's completely culled
384 if (negativeCount == vertexCount) {
385 return (0);
386 }
387
388 count = 0;
389 for (b = 0; b < vertexCount; b++)
390 {
391 // c is the index of the previous vertex
392 c = (b != 0) ? b - 1 : vertexCount - 1;
393
394 if (negative[b])
395 {
396 if (!negative[c])
397 {
398 // Current vertex is on negative side of plane,
399 // but previous vertex is on positive side.
400 VectorCopy(vertex[c],v1);
401 VectorCopy(vertex[b],v2);
402
403 t = (DotProduct(plane->normal, v1) - plane->dist) / (
404 plane->normal[0] * (v1[0] - v2[0])
405 + plane->normal[1] * (v1[1] - v2[1])
406 + plane->normal[2] * (v1[2] - v2[2]));
407
408 VectorScale(v1,(1.0 - t),newVertex[count]);
409 VectorMA(newVertex[count],t,v2,newVertex[count]);
410
411 count++;
412 }
413 }
414 else
415 {
416 if (negative[c])
417 {
418 // Current vertex is on positive side of plane,
419 // but previous vertex is on negative side.
420 VectorCopy(vertex[b],v1);
421 VectorCopy(vertex[c],v2);
422
423 t = (DotProduct(plane->normal, v1) - plane->dist) / (
424 plane->normal[0] * (v1[0] - v2[0])
425 + plane->normal[1] * (v1[1] - v2[1])
426 + plane->normal[2] * (v1[2] - v2[2]));
427
428
429 VectorScale(v1,(1.0 - t),newVertex[count]);
430 VectorMA(newVertex[count],t,v2,newVertex[count]);
431
432 count++;
433 }
434
435 // Include current vertex
436 VectorCopy(vertex[b],newVertex[count]);
437 count++;
438 }
439 }
440
441 // Return number of vertices in clipped polygon
442 return count;
443 }
444
445 /*
446 ===============
447 R_DrawDecails
448 ===============
449 */
450 extern cvar_t sv_gravity;
451
R_DrawDecals(void)452 void R_DrawDecals (void)
453 {
454 decal_t *p, *kill;
455 int i;
456 float blend, blend1;
457
458 glFogfv(GL_FOG_COLOR, color_black);
459 glEnable (GL_BLEND);
460 glEnable(GL_ALPHA_TEST);
461 glAlphaFunc(GL_GREATER,0.000);
462 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
463 glDepthMask(0);
464 glEnable(GL_POLYGON_OFFSET_FILL);
465 glPolygonOffset(-1,-1);
466
467 for ( ;; )
468 {
469 kill = active_decals;
470 if (kill && kill->die < cl.time)
471 {
472 active_decals = kill->next;
473 kill->next = free_decals;
474 free_decals = kill;
475 continue;
476 }
477 break;
478 }
479
480 for (p=active_decals ; p ; p=p->next)
481 {
482 for ( ;; )
483 {
484 kill = p->next;
485 //XYZ
486 if (kill && (kill->die < cl.time))
487 {
488 p->next = kill->next;
489 kill->next = free_decals;
490 free_decals = kill;
491 continue;
492 }
493 break;
494 }
495
496 GL_Bind(p->texture);
497 glBlendFunc (p->srcblend, p->dstblend);
498
499
500
501 //calculate color based on life ...
502 blend = (p->die-cl.time)/p->lifetime;
503 blend1 = 1-blend;
504 for (i=0; i<3; i++) {
505 p->color[i] = p->startcolor[i] * blend + p->endcolor[i] * blend1;
506 }
507
508 if ((p->die - cl.time) < 0.5) {
509 float scale = 2*(p->die - cl.time);
510 glColor4f((p->color[0]*scale), (p->color[1]*scale), (p->color[2]*scale), scale);
511 } else {
512 glColor3fv(&p->color[0]);
513 }
514
515
516 //Con_Printf("Drawdec %i\n",p->triangleCount);
517 for (i=0; i<p->triangleCount; i++) {
518 int i1, i2, i3;
519 i1 = p->triangleArray[i][0];
520 i2 = p->triangleArray[i][1];
521 i3 = p->triangleArray[i][2];
522
523 glBegin(GL_TRIANGLES);
524 glTexCoord2fv(&p->texcoordArray[i1][0]);
525 glVertex3fv(&p->vertexArray[i1][0]);
526
527 glTexCoord2fv(&p->texcoordArray[i2][0]);
528 glVertex3fv(&p->vertexArray[i2][0]);
529
530 glTexCoord2fv(&p->texcoordArray[i3][0]);
531 glVertex3fv(&p->vertexArray[i3][0]);
532 glEnd();
533 }
534
535
536 }
537 glDisable(GL_POLYGON_OFFSET_FILL);
538 glEnable(GL_DEPTH_TEST);
539 glDepthMask(1);
540 glDisable (GL_BLEND);
541 glDisable(GL_ALPHA_TEST);
542 glAlphaFunc(GL_GREATER,0.666);
543 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
544 glFogfv(GL_FOG_COLOR, fog_color);
545 }
546
547