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
33 byte *lightmapaddress;
39 int currentdecal; // wraps around in decal array, replacing old ones when a new one is needed
41 cvar_t r_drawdecals = {"r_drawdecals", "1"};
42 cvar_t r_decals_lighting = {"r_decals_lighting", "1"};
46 decals = (decal_t *) qmalloc(MAX_DECALS * sizeof(decal_t));
47 memset(decals, 0, MAX_DECALS * sizeof(decal_t));
51 void r_decals_shutdown()
56 void r_decals_newmap()
58 memset(decals, 0, MAX_DECALS * sizeof(decal_t));
64 Cvar_RegisterVariable (&r_drawdecals);
65 Cvar_RegisterVariable (&r_decals_lighting);
67 R_RegisterModule("R_Decals", r_decals_start, r_decals_shutdown, r_decals_newmap);
70 // these are static globals only to avoid putting unnecessary things on the stack
71 static vec3_t decalorg;
72 static float decalbestdist;
73 static msurface_t *decalbestsurf;
74 static int decalbestlightmapofs;
75 void R_RecursiveDecalSurface (mnode_t *node)
77 // these are static because only one occurance of them need exist at once, so avoid putting them on the stack
78 static float ndist, dist;
79 static msurface_t *surf, *endsurf;
84 if (node->contents < 0)
87 ndist = PlaneDiff(decalorg, node->plane);
91 node = node->children[0];
96 node = node->children[1];
101 surf = cl.worldmodel->surfaces + node->firstsurface;
102 endsurf = surf + node->numsurfaces;
103 for (;surf < endsurf;surf++)
105 if (surf->flags & SURF_DRAWTILED)
106 continue; // no lightmaps
108 dist = PlaneDiff(decalorg, surf->plane);
109 if (surf->flags & SURF_PLANEBACK)
113 if (dist >= decalbestdist)
116 impact[0] = decalorg[0] - surf->plane->normal[0] * dist;
117 impact[1] = decalorg[1] - surf->plane->normal[1] * dist;
118 impact[2] = decalorg[2] - surf->plane->normal[2] * dist;
120 ds = (int) (DotProduct(impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]);
121 dt = (int) (DotProduct(impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]);
123 if (ds < surf->texturemins[0] || dt < surf->texturemins[1])
126 ds -= surf->texturemins[0];
127 dt -= surf->texturemins[1];
129 if (ds > surf->extents[0] || dt > surf->extents[1])
132 decalbestsurf = surf;
133 decalbestdist = dist;
134 decalbestlightmapofs = (dt >> 4) * ((surf->extents[0] >> 4) + 1) + (ds >> 4);
137 if (node->children[0]->contents >= 0)
139 if (node->children[1]->contents >= 0)
141 R_RecursiveDecalSurface (node->children[0]);
142 node = node->children[1];
147 node = node->children[0];
151 else if (node->children[1]->contents >= 0)
153 node = node->children[1];
158 void R_Decal(vec3_t org, rtexture_t *tex, float scale, int cred, int cgreen, int cblue, int alpha)
160 vec3_t center, right, up;
166 // find the best surface to place the decal on
167 decalbestsurf = NULL;
169 decalbestlightmapofs = 0;
170 VectorCopy(org, decalorg);
172 R_RecursiveDecalSurface (cl.worldmodel->nodes);
174 // abort if no suitable surface was found
175 if (decalbestsurf == NULL)
178 // grab a decal from the array and advance to the next decal to replace, wrapping to replace an old decal if necessary
179 decal = decals + currentdecal;
181 if (currentdecal >= MAX_DECALS)
184 VectorCopy(decalbestsurf->plane->normal, decal->direction);
186 if (decalbestsurf->flags & SURF_PLANEBACK)
187 VectorNegate(decal->direction, decal->direction);
188 VectorNegate(decal->direction, decal->direction);
189 // 0.25 to push it off the surface a bit
190 decalbestdist -= 0.25f;
191 decal->org[0] = center[0] = org[0] + decal->direction[0] * decalbestdist;
192 decal->org[1] = center[1] = org[1] + decal->direction[1] * decalbestdist;
193 decal->org[2] = center[2] = org[2] + decal->direction[2] * decalbestdist;
194 // set up the 4 corners
196 VectorVectors(decal->direction, right, up);
197 decal->vert[0][0] = center[0] - right[0] * scale - up[0] * scale; // texcoords 0 1
198 decal->vert[0][1] = center[1] - right[1] * scale - up[1] * scale;
199 decal->vert[0][2] = center[2] - right[2] * scale - up[2] * scale;
200 decal->vert[1][0] = center[0] - right[0] * scale + up[0] * scale; // texcoords 0 0
201 decal->vert[1][1] = center[1] - right[1] * scale + up[1] * scale;
202 decal->vert[1][2] = center[2] - right[2] * scale + up[2] * scale;
203 decal->vert[2][0] = center[0] + right[0] * scale + up[0] * scale; // texcoords 1 0
204 decal->vert[2][1] = center[1] + right[1] * scale + up[1] * scale;
205 decal->vert[2][2] = center[2] + right[2] * scale + up[2] * scale;
206 decal->vert[3][0] = center[0] + right[0] * scale - up[0] * scale; // texcoords 1 1
207 decal->vert[3][1] = center[1] + right[1] * scale - up[1] * scale;
208 decal->vert[3][2] = center[2] + right[2] * scale - up[2] * scale;
210 decal->color[0] = (byte) bound(0, cred, 255);
211 decal->color[1] = (byte) bound(0, cgreen, 255);
212 decal->color[2] = (byte) bound(0, cblue, 255);
213 decal->color[3] = (byte) bound(0, alpha, 255);
214 // store the surface information for lighting
215 decal->surface = decalbestsurf;
216 decal->lightmapstep = ((decalbestsurf->extents[0]>>4)+1) * ((decalbestsurf->extents[1]>>4)+1)*3; // LordHavoc: *3 for colored lighting
217 if (decalbestsurf->samples)
218 decal->lightmapaddress = decalbestsurf->samples + decalbestlightmapofs * 3; // LordHavoc: *3 for colored lighitng
220 decal->lightmapaddress = NULL;
223 void GL_DrawDecals (void)
226 int i, j, k, dynamiclight, bits, texnum;
227 float scale, fr, fg, fb, dist, rad, mindist;
233 if (!r_drawdecals.value)
236 dynamiclight = (int) r_dynamic.value != 0 && (int) r_decals_lighting.value != 0;
238 mindist = DotProduct(r_origin, vpn) + 4.0f;
242 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
244 glShadeModel(GL_FLAT);
245 glDepthMask(0); // disable zbuffer updates
246 glDisable(GL_ALPHA_TEST);
247 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
251 for (i = 0, p = decals;i < MAX_DECALS;i++, p++)
255 // skip decals on surfaces that aren't visible in this frame
256 if (p->surface->visframe != r_framecount)
259 // do not render if the decal is behind the view
260 if (DotProduct(p->org, vpn) < mindist)
263 // do not render if the view origin is behind the decal
264 VectorSubtract(p->org, r_origin, v);
265 if (DotProduct(p->direction, v) < 0)
268 // get the surface lighting
270 lightmap = p->lightmapaddress;
274 if (surf->styles[0] != 255)
276 scale = d_lightstylevalue[surf->styles[0]] * (1.0f / 256.0f);
277 fr += lightmap[0] * scale;
278 fg += lightmap[1] * scale;
279 fb += lightmap[2] * scale;
280 if (surf->styles[1] != 255)
282 lightmap += p->lightmapstep;
283 scale = d_lightstylevalue[surf->styles[1]] * (1.0f / 256.0f);
284 fr += lightmap[0] * scale;
285 fg += lightmap[1] * scale;
286 fb += lightmap[2] * scale;
287 if (surf->styles[2] != 255)
289 lightmap += p->lightmapstep;
290 scale = d_lightstylevalue[surf->styles[2]] * (1.0f / 256.0f);
291 fr += lightmap[0] * scale;
292 fg += lightmap[1] * scale;
293 fb += lightmap[2] * scale;
294 if (surf->styles[3] != 255)
296 lightmap += p->lightmapstep;
297 scale = d_lightstylevalue[surf->styles[3]] * (1.0f / 256.0f);
298 fr += lightmap[0] * scale;
299 fg += lightmap[1] * scale;
300 fb += lightmap[2] * scale;
306 for (j = 0;j < MAXLIGHTMAPS && surf->styles[j] != 255;j++)
308 scale = d_lightstylevalue[surf->styles[j]] * (1.0f / 256.0f);
309 fr += lightmap[0] * scale;
310 fg += lightmap[1] * scale;
311 fb += lightmap[2] * scale;
312 lightmap += p->lightmapstep;
319 if (surf->dlightframe == r_framecount)
321 for (j = 0;j < 8;j++)
323 bits = surf->dlightbits[j];
326 for (k = 0, dl = cl_dlights + j * 32;bits;k++, dl++)
331 VectorSubtract(p->org, dl->origin, v);
332 dist = DotProduct(v, v) + LIGHTOFFSET;
333 rad = dl->radius * dl->radius;
336 rad *= 128.0f / dist;
337 fr += rad * dl->color[0];
338 fg += rad * dl->color[1];
339 fb += rad * dl->color[2];
351 // apply color to lighting
352 ir = (int) (fr * p->color[0] * (1.0f / 128.0f));
353 ig = (int) (fg * p->color[1] * (1.0f / 128.0f));
354 ib = (int) (fb * p->color[2] * (1.0f / 128.0f));
355 // compute byte color
356 br = (byte) min(ir, 255);
357 bg = (byte) min(ig, 255);
358 bb = (byte) min(ib, 255);
360 // put into transpoly system for sorted drawing later
361 transpolybegin(R_GetTexture(p->tex), 0, R_GetTexture(p->tex), TPOLYTYPE_ALPHA);
362 transpolyvertub(p->vert[0][0], p->vert[0][1], p->vert[0][2], 0,1,br,bg,bb,ba);
363 transpolyvertub(p->vert[1][0], p->vert[1][1], p->vert[1][2], 0,0,br,bg,bb,ba);
364 transpolyvertub(p->vert[2][0], p->vert[2][1], p->vert[2][2], 1,0,br,bg,bb,ba);
365 transpolyvertub(p->vert[3][0], p->vert[3][1], p->vert[3][2], 1,1,br,bg,bb,ba);
371 j = R_GetTexture(p->tex);
376 glBindTexture(GL_TEXTURE_2D, texnum);
380 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));
382 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));
384 glVertex3fv(p->vert[0]);
386 glVertex3fv(p->vert[1]);
388 glVertex3fv(p->vert[2]);
390 glVertex3fv(p->vert[3]);
398 glDepthMask(1); // enable zbuffer updates
399 glDisable(GL_ALPHA_TEST);