2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
23 #define MAX_DECALS 2048
25 typedef struct decal_s
34 byte *lightmapaddress;
40 int currentdecal; // wraps around in decal array, replacing old ones when a new one is needed
42 cvar_t r_drawdecals = {0, "r_drawdecals", "1"};
43 cvar_t r_decals_lighting = {0, "r_decals_lighting", "1"};
45 void r_decals_start(void)
47 decals = (decal_t *) qmalloc(MAX_DECALS * sizeof(decal_t));
48 memset(decals, 0, MAX_DECALS * sizeof(decal_t));
52 void r_decals_shutdown(void)
57 void r_decals_newmap(void)
59 memset(decals, 0, MAX_DECALS * sizeof(decal_t));
63 void R_Decals_Init(void)
65 Cvar_RegisterVariable (&r_drawdecals);
66 Cvar_RegisterVariable (&r_decals_lighting);
68 R_RegisterModule("R_Decals", r_decals_start, r_decals_shutdown, r_decals_newmap);
71 // these are static globals only to avoid putting unnecessary things on the stack
72 static vec3_t decalorg;
73 static float decalbestdist;
74 static msurface_t *decalbestsurf;
75 static int decalbestlightmapofs;
76 void R_RecursiveDecalSurface (mnode_t *node)
78 // these are static because only one occurance of them need exist at once, so avoid putting them on the stack
79 static float ndist, dist;
80 static msurface_t *surf, *endsurf;
85 if (node->contents < 0)
88 ndist = PlaneDiff(decalorg, node->plane);
92 node = node->children[0];
97 node = node->children[1];
102 surf = cl.worldmodel->surfaces + node->firstsurface;
103 endsurf = surf + node->numsurfaces;
104 for (;surf < endsurf;surf++)
106 if (surf->flags & SURF_DRAWTILED)
107 continue; // no lightmaps
109 dist = PlaneDiff(decalorg, surf->plane);
110 if (surf->flags & SURF_PLANEBACK)
114 if (dist >= decalbestdist)
117 impact[0] = decalorg[0] - surf->plane->normal[0] * dist;
118 impact[1] = decalorg[1] - surf->plane->normal[1] * dist;
119 impact[2] = decalorg[2] - surf->plane->normal[2] * dist;
121 ds = (int) (DotProduct(impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]);
122 dt = (int) (DotProduct(impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]);
124 if (ds < surf->texturemins[0] || dt < surf->texturemins[1])
127 ds -= surf->texturemins[0];
128 dt -= surf->texturemins[1];
130 if (ds > surf->extents[0] || dt > surf->extents[1])
133 decalbestsurf = surf;
134 decalbestdist = dist;
135 decalbestlightmapofs = (dt >> 4) * ((surf->extents[0] >> 4) + 1) + (ds >> 4);
138 if (node->children[0]->contents >= 0)
140 if (node->children[1]->contents >= 0)
142 R_RecursiveDecalSurface (node->children[0]);
143 node = node->children[1];
148 node = node->children[0];
152 else if (node->children[1]->contents >= 0)
154 node = node->children[1];
159 void R_Decal(vec3_t org, rtexture_t *tex, float s1, float t1, float s2, float t2, float scale, int cred, int cgreen, int cblue, int alpha)
161 vec3_t center, right, up;
167 // find the best surface to place the decal on
168 decalbestsurf = NULL;
170 decalbestlightmapofs = 0;
171 VectorCopy(org, decalorg);
173 R_RecursiveDecalSurface (cl.worldmodel->nodes);
175 // abort if no suitable surface was found
176 if (decalbestsurf == NULL)
179 // grab a decal from the array and advance to the next decal to replace, wrapping to replace an old decal if necessary
180 decal = decals + currentdecal;
182 if (currentdecal >= MAX_DECALS)
185 VectorCopy(decalbestsurf->plane->normal, decal->direction);
187 if (decalbestsurf->flags & SURF_PLANEBACK)
188 VectorNegate(decal->direction, decal->direction);
189 VectorNegate(decal->direction, decal->direction);
190 // 0.25 to push it off the surface a bit
191 decalbestdist -= 0.25f;
192 decal->org[0] = center[0] = org[0] + decal->direction[0] * decalbestdist;
193 decal->org[1] = center[1] = org[1] + decal->direction[1] * decalbestdist;
194 decal->org[2] = center[2] = org[2] + decal->direction[2] * decalbestdist;
195 // set up the 4 corners
197 VectorVectors(decal->direction, right, up);
198 decal->texcoord[0][0] = s1;
199 decal->texcoord[0][1] = t1;
200 decal->vert[0][0] = center[0] - right[0] * scale - up[0] * scale;
201 decal->vert[0][1] = center[1] - right[1] * scale - up[1] * scale;
202 decal->vert[0][2] = center[2] - right[2] * scale - up[2] * scale;
203 decal->texcoord[1][0] = s1;
204 decal->texcoord[1][1] = t2;
205 decal->vert[1][0] = center[0] - right[0] * scale + up[0] * scale;
206 decal->vert[1][1] = center[1] - right[1] * scale + up[1] * scale;
207 decal->vert[1][2] = center[2] - right[2] * scale + up[2] * scale;
208 decal->texcoord[2][0] = s2;
209 decal->texcoord[2][1] = t2;
210 decal->vert[2][0] = center[0] + right[0] * scale + up[0] * scale;
211 decal->vert[2][1] = center[1] + right[1] * scale + up[1] * scale;
212 decal->vert[2][2] = center[2] + right[2] * scale + up[2] * scale;
213 decal->texcoord[3][0] = s2;
214 decal->texcoord[3][1] = t1;
215 decal->vert[3][0] = center[0] + right[0] * scale - up[0] * scale;
216 decal->vert[3][1] = center[1] + right[1] * scale - up[1] * scale;
217 decal->vert[3][2] = center[2] + right[2] * scale - up[2] * scale;
219 decal->color[0] = (byte) bound(0, cred, 255);
220 decal->color[1] = (byte) bound(0, cgreen, 255);
221 decal->color[2] = (byte) bound(0, cblue, 255);
222 decal->color[3] = (byte) bound(0, alpha, 255);
223 // store the surface information for lighting
224 decal->surface = decalbestsurf;
225 decal->lightmapstep = ((decalbestsurf->extents[0]>>4)+1) * ((decalbestsurf->extents[1]>>4)+1)*3; // LordHavoc: *3 for colored lighting
226 if (decalbestsurf->samples)
227 decal->lightmapaddress = decalbestsurf->samples + decalbestlightmapofs * 3; // LordHavoc: *3 for colored lighitng
229 decal->lightmapaddress = NULL;
232 void GL_DrawDecals (void)
235 int i, j, k, dynamiclight, bits, texnum, iscale, ir, ig, ib, lit, cr, cg, cb;
236 float /*fscale, */fr, fg, fb, dist, rad, mindist;
242 if (!r_drawdecals.value)
245 dynamiclight = (int) r_dynamic.value != 0 && (int) r_decals_lighting.value != 0;
247 mindist = DotProduct(r_origin, vpn) + 4.0f;
251 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
253 // glShadeModel(GL_FLAT);
254 glDepthMask(0); // disable zbuffer updates
255 glDisable(GL_ALPHA_TEST);
256 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
260 for (i = 0, p = decals;i < MAX_DECALS;i++, p++)
264 // skip decals on surfaces that aren't visible in this frame
265 if (p->surface->visframe != r_framecount)
268 // do not render if the decal is behind the view
269 if (DotProduct(p->org, vpn) < mindist)
272 // do not render if the view origin is behind the decal
273 VectorSubtract(p->org, r_origin, v);
274 if (DotProduct(p->direction, v) < 0)
277 // get the surface lighting
279 lightmap = p->lightmapaddress;
285 if (surf->dlightframe == r_framecount)
287 for (j = 0;j < 8;j++)
289 bits = surf->dlightbits[j];
292 for (k = 0, dl = cl_dlights + j * 32;bits;k++, dl++)
297 VectorSubtract(p->org, dl->origin, v);
298 dist = DotProduct(v, v) + LIGHTOFFSET;
299 rad = dl->radius * dl->radius;
302 rad *= 128.0f / dist;
303 fr += rad * dl->color[0];
304 fg += rad * dl->color[1];
305 fb += rad * dl->color[2];
324 ir = (*((long *)&fr) & 0x7FFFFF) << 8;
325 ig = (*((long *)&fg) & 0x7FFFFF) << 8;
326 ib = (*((long *)&fb) & 0x7FFFFF) << 8;
334 if (surf->styles[0] != 255)
336 iscale = d_lightstylevalue[surf->styles[0]];
337 ir += lightmap[0] * iscale;
338 ig += lightmap[1] * iscale;
339 ib += lightmap[2] * iscale;
340 if (surf->styles[1] != 255)
342 lightmap += p->lightmapstep;
343 iscale = d_lightstylevalue[surf->styles[1]];
344 ir += lightmap[0] * iscale;
345 ig += lightmap[1] * iscale;
346 ib += lightmap[2] * iscale;
347 if (surf->styles[2] != 255)
349 lightmap += p->lightmapstep;
350 iscale = d_lightstylevalue[surf->styles[2]];
351 ir += lightmap[0] * iscale;
352 ig += lightmap[1] * iscale;
353 ib += lightmap[2] * iscale;
354 if (surf->styles[3] != 255)
356 lightmap += p->lightmapstep;
357 iscale = d_lightstylevalue[surf->styles[3]];
358 ir += lightmap[0] * iscale;
359 ig += lightmap[1] * iscale;
360 ib += lightmap[2] * iscale;
370 if (surf->styles[0] != 255)
372 fscale = d_lightstylevalue[surf->styles[0]] * (1.0f / 256.0f);
373 fr += lightmap[0] * fscale;
374 fg += lightmap[1] * fscale;
375 fb += lightmap[2] * fscale;
376 if (surf->styles[1] != 255)
378 lightmap += p->lightmapstep;
379 fscale = d_lightstylevalue[surf->styles[1]] * (1.0f / 256.0f);
380 fr += lightmap[0] * fscale;
381 fg += lightmap[1] * fscale;
382 fb += lightmap[2] * fscale;
383 if (surf->styles[2] != 255)
385 lightmap += p->lightmapstep;
386 fscale = d_lightstylevalue[surf->styles[2]] * (1.0f / 256.0f);
387 fr += lightmap[0] * fscale;
388 fg += lightmap[1] * fscale;
389 fb += lightmap[2] * fscale;
390 if (surf->styles[3] != 255)
392 lightmap += p->lightmapstep;
393 fscale = d_lightstylevalue[surf->styles[3]] * (1.0f / 256.0f);
394 fr += lightmap[0] * fscale;
395 fg += lightmap[1] * fscale;
396 fb += lightmap[2] * fscale;
402 for (j = 0;j < MAXLIGHTMAPS && surf->styles[j] != 255;j++)
404 fscale = d_lightstylevalue[surf->styles[j]] * (1.0f / 256.0f);
405 fr += lightmap[0] * fscale;
406 fg += lightmap[1] * fscale;
407 fb += lightmap[2] * fscale;
408 lightmap += p->lightmapstep;
417 // apply color to lighting
418 ir = (int) (fr * p->color[0] * (1.0f / 128.0f));
419 ig = (int) (fg * p->color[1] * (1.0f / 128.0f));
420 ib = (int) (fb * p->color[2] * (1.0f / 128.0f));
421 // compute byte color
422 br = (byte) min(ir, 255);
423 bg = (byte) min(ig, 255);
424 bb = (byte) min(ib, 255);
426 // put into transpoly system for sorted drawing later
427 transpolybegin(R_GetTexture(p->tex), 0, R_GetTexture(p->tex), TPOLYTYPE_ALPHA);
428 transpolyvertub(p->vert[0][0], p->vert[0][1], p->vert[0][2], 0,1,br,bg,bb,ba);
429 transpolyvertub(p->vert[1][0], p->vert[1][1], p->vert[1][2], 0,0,br,bg,bb,ba);
430 transpolyvertub(p->vert[2][0], p->vert[2][1], p->vert[2][2], 1,0,br,bg,bb,ba);
431 transpolyvertub(p->vert[3][0], p->vert[3][1], p->vert[3][2], 1,1,br,bg,bb,ba);
437 j = R_GetTexture(p->tex);
442 glBindTexture(GL_TEXTURE_2D, texnum);
447 glColor4f(fr * p->color[0] * (1.0f / 255.0f / 256.0f), fg * p->color[1] * (1.0f / 255.0f / 256.0f), fb * p->color[2] * (1.0f / 255.0f / 256.0f), p->color[3] * (1.0f / 255.0f));
449 glColor4f(fr * p->color[0] * (1.0f / 255.0f / 128.0f), fg * p->color[1] * (1.0f / 255.0f / 128.0f), fb * p->color[2] * (1.0f / 255.0f / 128.0f), p->color[3] * (1.0f / 255.0f));
453 cr = (ir * p->color[0]) >> 16;
454 cg = (ig * p->color[1]) >> 16;
455 cb = (ib * p->color[2]) >> 16;
459 cr = (ir * p->color[0]) >> 15;
460 cg = (ig * p->color[1]) >> 15;
461 cb = (ib * p->color[2]) >> 15;
466 glColor4ub(cr, cg, cb, p->color[3]);
468 glTexCoord2f(p->texcoord[0][0], p->texcoord[0][1]);
469 glVertex3fv(p->vert[0]);
470 glTexCoord2f(p->texcoord[1][0], p->texcoord[1][1]);
471 glVertex3fv(p->vert[1]);
472 glTexCoord2f(p->texcoord[2][0], p->texcoord[2][1]);
473 glVertex3fv(p->vert[2]);
474 glTexCoord2f(p->texcoord[3][0], p->texcoord[3][1]);
475 glVertex3fv(p->vert[3]);
483 glDepthMask(1); // enable zbuffer updates
484 glDisable(GL_ALPHA_TEST);