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