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 cvar_t r_drawdecals = {0, "r_drawdecals", "1"};
25 static void r_decals_start(void)
29 static void r_decals_shutdown(void)
33 static void r_decals_newmap(void)
37 void R_Decals_Init(void)
39 Cvar_RegisterVariable (&r_drawdecals);
41 R_RegisterModule("R_Decals", r_decals_start, r_decals_shutdown, r_decals_newmap);
45 static int decalindexarray[2*3] =
52 void R_DrawDecals (void)
55 int i, j, lightmapstep, ds, dt;
56 float fscale, fr, fg, fb, dist, f, fog, ifog, fogvec[3], impact[3], v[3], org[3], dir[3], right[3], up[3], tvxyz[4][4], tvst[4][2];
57 particletexture_t *tex, *texfog;
63 if (!r_drawdecals.integer)
69 Mod_CheckLoaded(cl.worldmodel);
71 // LordHavoc: this meshinfo must match up with R_Mesh_DrawDecal
72 // LordHavoc: the commented out lines are hardwired behavior in R_Mesh_DrawDecal
73 memset(&m, 0, sizeof(m));
74 m.blendfunc1 = GL_SRC_ALPHA;
75 m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
78 //m.index = decalindexarray;
79 m.vertex = &tvxyz[0][0];
80 //m.vertexstep = sizeof(float[4]);
81 m.tex[0] = R_GetTexture(particlefonttexture);
82 m.texcoords[0] = &tvst[0][0];
83 //m.texcoordstep[0] = sizeof(float[2]);
85 for (i = 0, r = r_refdef.decals;i < r_refdef.numdecals;i++, r++)
89 if (r->ent->visframe != r_framecount)
92 Mod_CheckLoaded(r->ent->model);
93 if (r->ent->model->type != mod_brush)
96 surf = r->ent->model->surfaces + r->surface;
98 // skip decals on surfaces that aren't visible in this frame
99 if (surf->visframe != r_framecount)
102 softwaretransformforentity(r->ent);
103 softwaretransform(r->org, org);
104 softwaretransformdirection(r->dir, dir);
106 // do not render if the view origin is behind the decal
107 VectorSubtract(org, r_origin, fogvec);
108 if (DotProduct(dir, fogvec) < 0)
113 surf = cl.worldmodel->surfaces + r->surface;
115 // skip decals on surfaces that aren't visible in this frame
116 if (surf->visframe != r_framecount)
119 // do not render if the view origin is behind the decal
120 VectorSubtract(r->org, r_origin, fogvec);
121 if (DotProduct(r->dir, fogvec) < 0)
124 VectorCopy(r->org, org);
125 VectorCopy(r->dir, dir);
128 dist = -PlaneDiff(r->org, surf->plane);
129 VectorMA(r->org, dist, surf->plane->normal, impact);
131 ds = (int) (DotProduct(impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]) - surf->texturemins[0];
132 dt = (int) (DotProduct(impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]) - surf->texturemins[1];
134 if (ds < 0 || dt < 0 || ds > surf->extents[0] || dt > surf->extents[1])
136 // this should never happen
140 tex = &particletexture[r->tex][0];
141 VectorVectors(dir, right, up);
142 VectorScale(right, r->scale, right);
143 VectorScale(up, r->scale, up);
144 tvxyz[0][0] = org[0] - right[0] - up[0];
145 tvxyz[0][1] = org[1] - right[1] - up[1];
146 tvxyz[0][2] = org[2] - right[2] - up[2];
147 tvxyz[1][0] = org[0] - right[0] + up[0];
148 tvxyz[1][1] = org[1] - right[1] + up[1];
149 tvxyz[1][2] = org[2] - right[2] + up[2];
150 tvxyz[2][0] = org[0] + right[0] + up[0];
151 tvxyz[2][1] = org[1] + right[1] + up[1];
152 tvxyz[2][2] = org[2] + right[2] + up[2];
153 tvxyz[3][0] = org[0] + right[0] - up[0];
154 tvxyz[3][1] = org[1] + right[1] - up[1];
155 tvxyz[3][2] = org[2] + right[2] - up[2];
156 tvst[0][0] = tex->s1;
157 tvst[0][1] = tex->t1;
158 tvst[1][0] = tex->s1;
159 tvst[1][1] = tex->t2;
160 tvst[2][0] = tex->s2;
161 tvst[2][1] = tex->t2;
162 tvst[3][0] = tex->s2;
163 tvst[3][1] = tex->t1;
168 if ((lightmap = surf->samples))
170 if (surf->styles[0] != 255)
172 lightmap += ((dt >> 4) * ((surf->extents[0] >> 4) + 1) + (ds >> 4)) * 3;
173 fscale = d_lightstylevalue[surf->styles[0]] * (1.0f / 32768.0f);
174 fr += lightmap[0] * fscale;
175 fg += lightmap[1] * fscale;
176 fb += lightmap[2] * fscale;
177 if (surf->styles[1] != 255)
179 lightmapstep = (((surf->extents[0] >> 4) + 1) * ((surf->extents[1] >> 4) + 1)) * 3;
180 lightmap += lightmapstep;
181 fscale = d_lightstylevalue[surf->styles[1]] * (1.0f / 32768.0f);
182 fr += lightmap[0] * fscale;
183 fg += lightmap[1] * fscale;
184 fb += lightmap[2] * fscale;
185 if (surf->styles[2] != 255)
187 lightmap += lightmapstep;
188 fscale = d_lightstylevalue[surf->styles[2]] * (1.0f / 32768.0f);
189 fr += lightmap[0] * fscale;
190 fg += lightmap[1] * fscale;
191 fb += lightmap[2] * fscale;
192 if (surf->styles[3] != 255)
194 lightmap += lightmapstep;
195 fscale = d_lightstylevalue[surf->styles[3]] * (1.0f / 32768.0f);
196 fr += lightmap[0] * fscale;
197 fg += lightmap[1] * fscale;
198 fb += lightmap[2] * fscale;
205 if (surf->dlightframe == r_framecount)
207 for (j = 0;j < r_numdlights;j++)
209 if (surf->dlightbits[j >> 5] & (1 << (j & 31)))
212 VectorSubtract(r->org, rd->origin, v);
213 dist = DotProduct(v, v) + LIGHTOFFSET;
214 if (dist < rd->cullradius2)
216 f = (1.0f / dist) - rd->lightsubtract;
219 fr += f * rd->light[0];
220 fg += f * rd->light[1];
221 fb += f * rd->light[2];
228 // if the surface is transparent, render as transparent
229 m.transparent = !(surf->flags & SURF_CLIPSOLID);
230 m.cr = r->color[0] * fr;
231 m.cg = r->color[1] * fg;
232 m.cb = r->color[2] * fb;
237 fog = exp(fogdensity/DotProduct(fogvec,fogvec));
238 texfog = &particletexture[r->tex][1];
239 if (fog >= (1.0f / 64.0f))
241 if (fog >= (1.0f - (1.0f / 64.0f)))
243 // fully fogged, just use the fog texture and render as alpha
248 tvst[0][0] = texfog->s1;
249 tvst[0][1] = texfog->t1;
250 tvst[1][0] = texfog->s1;
251 tvst[1][1] = texfog->t2;
252 tvst[2][0] = texfog->s2;
253 tvst[2][1] = texfog->t2;
254 tvst[3][0] = texfog->s2;
255 tvst[3][1] = texfog->t1;
256 R_Mesh_DrawDecal(&m);
260 // partially fogged, darken the first pass
265 if (tex->s1 == texfog->s1 && tex->t1 == texfog->t1)
267 // fog texture is the same as the base, just change the color
268 m.cr += fogcolor[0] * fog;
269 m.cg += fogcolor[1] * fog;
270 m.cb += fogcolor[2] * fog;
271 R_Mesh_DrawDecal(&m);
275 // render the first pass (alpha), then do additive fog
276 R_Mesh_DrawDecal(&m);
277 m.blendfunc2 = GL_ONE;
281 m.ca = r->color[3] * fog;
282 tvst[0][0] = texfog->s1;
283 tvst[0][1] = texfog->t1;
284 tvst[1][0] = texfog->s1;
285 tvst[1][1] = texfog->t2;
286 tvst[2][0] = texfog->s2;
287 tvst[2][1] = texfog->t2;
288 tvst[3][0] = texfog->s2;
289 tvst[3][1] = texfog->t1;
290 R_Mesh_DrawDecal(&m);
291 m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
296 R_Mesh_DrawDecal(&m);
299 R_Mesh_DrawDecal(&m);
304 void R_DrawDecals (void)
307 int i, j, lightmapstep, ds, dt;
308 float fscale, fr, fg, fb, dist, f, fog, ifog, impact[3], v[3], org[3], dir[3], right[3], up[3], tv[4][5];
309 particletexture_t *tex;
315 if (!r_drawdecals.integer)
320 Mod_CheckLoaded(cl.worldmodel);
322 memset(&m, 0, sizeof(m));
323 m.blendfunc1 = GL_SRC_ALPHA;
324 m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
327 m.index = decalindexarray;
328 m.vertex = &tv[0][0];
329 m.vertexstep = sizeof(float[5]);
330 m.tex[0] = R_GetTexture(particlefonttexture);
331 m.texcoords[0] = &tv[0][3];
332 m.texcoordstep[0] = sizeof(float[5]);
334 for (i = 0, r = r_refdef.decals;i < r_refdef.numdecals;i++, r++)
338 if (r->ent->visframe != r_framecount)
341 Mod_CheckLoaded(r->ent->model);
342 if (r->ent->model->type != mod_brush)
345 surf = r->ent->model->surfaces + r->surface;
347 // skip decals on surfaces that aren't visible in this frame
348 if (surf->visframe != r_framecount)
351 softwaretransformforentity(r->ent);
352 softwaretransform(r->org, org);
353 softwaretransformdirection(r->dir, dir);
355 // do not render if the view origin is behind the decal
356 VectorSubtract(org, r_origin, v);
357 if (DotProduct(dir, v) < 0)
362 surf = cl.worldmodel->surfaces + r->surface;
364 // skip decals on surfaces that aren't visible in this frame
365 if (surf->visframe != r_framecount)
368 // do not render if the view origin is behind the decal
369 VectorSubtract(r->org, r_origin, v);
370 if (DotProduct(r->dir, v) < 0)
373 VectorCopy(r->org, org);
374 VectorCopy(r->dir, dir);
377 dist = -PlaneDiff(r->org, surf->plane);
378 VectorMA(r->org, dist, surf->plane->normal, impact);
380 ds = (int) (DotProduct(impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]) - surf->texturemins[0];
381 dt = (int) (DotProduct(impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]) - surf->texturemins[1];
383 if (ds < 0 || dt < 0 || ds > surf->extents[0] || dt > surf->extents[1])
385 // this should never happen
391 ifog = 1 - exp(fogdensity/DotProduct(v,v));
392 ifog = bound(0, ifog, 1);
395 tex = &particletexture[r->tex][0];
396 VectorVectors(dir, right, up);
397 VectorScale(right, r->scale, right);
398 VectorScale(up, r->scale, up);
399 tv[0][0] = org[0] - right[0] - up[0];
400 tv[0][1] = org[1] - right[1] - up[1];
401 tv[0][2] = org[2] - right[2] - up[2];
404 tv[1][0] = org[0] - right[0] + up[0];
405 tv[1][1] = org[1] - right[1] + up[1];
406 tv[1][2] = org[2] - right[2] + up[2];
409 tv[2][0] = org[0] + right[0] + up[0];
410 tv[2][1] = org[1] + right[1] + up[1];
411 tv[2][2] = org[2] + right[2] + up[2];
414 tv[3][0] = org[0] + right[0] - up[0];
415 tv[3][1] = org[1] + right[1] - up[1];
416 tv[3][2] = org[2] + right[2] - up[2];
423 if ((lightmap = surf->samples))
425 if (surf->styles[0] != 255)
427 lightmap += ((dt >> 4) * ((surf->extents[0] >> 4) + 1) + (ds >> 4)) * 3;
428 fscale = d_lightstylevalue[surf->styles[0]] * (1.0f / 32768.0f);
429 fr += lightmap[0] * fscale;
430 fg += lightmap[1] * fscale;
431 fb += lightmap[2] * fscale;
432 if (surf->styles[1] != 255)
434 lightmapstep = (((surf->extents[0] >> 4) + 1) * ((surf->extents[1] >> 4) + 1)) * 3;
435 lightmap += lightmapstep;
436 fscale = d_lightstylevalue[surf->styles[1]] * (1.0f / 32768.0f);
437 fr += lightmap[0] * fscale;
438 fg += lightmap[1] * fscale;
439 fb += lightmap[2] * fscale;
440 if (surf->styles[2] != 255)
442 lightmap += lightmapstep;
443 fscale = d_lightstylevalue[surf->styles[2]] * (1.0f / 32768.0f);
444 fr += lightmap[0] * fscale;
445 fg += lightmap[1] * fscale;
446 fb += lightmap[2] * fscale;
447 if (surf->styles[3] != 255)
449 lightmap += lightmapstep;
450 fscale = d_lightstylevalue[surf->styles[3]] * (1.0f / 32768.0f);
451 fr += lightmap[0] * fscale;
452 fg += lightmap[1] * fscale;
453 fb += lightmap[2] * fscale;
460 if (surf->dlightframe == r_framecount)
462 for (j = 0;j < r_numdlights;j++)
464 if (surf->dlightbits[j >> 5] & (1 << (j & 31)))
467 VectorSubtract(r->org, rd->origin, v);
468 dist = DotProduct(v, v) + LIGHTOFFSET;
469 if (dist < rd->cullradius2)
471 f = (1.0f / dist) - rd->lightsubtract;
474 fr += f * rd->light[0];
475 fg += f * rd->light[1];
476 fb += f * rd->light[2];
483 // if the surface is transparent, render as transparent
484 m.transparent = !(surf->flags & SURF_CLIPSOLID);
485 m.cr = r->color[0] * fr;
486 m.cg = r->color[1] * fg;
487 m.cb = r->color[2] * fb;
497 R_Mesh_DrawDecal(&m);
503 m.blendfunc2 = GL_ONE;
508 for (i = 0, r = r_refdef.decals;i < r_refdef.numdecals;i++, r++)
512 if (r->ent->visframe != r_framecount)
515 Mod_CheckLoaded(r->ent->model);
517 surf = r->ent->model->surfaces + r->surface;
519 // skip decals on surfaces that aren't visible in this frame
520 if (surf->visframe != r_framecount)
523 softwaretransformforentity(r->ent);
524 softwaretransform(r->org, org);
525 softwaretransformdirection(r->dir, dir);
527 // do not render if the view origin is behind the decal
528 VectorSubtract(org, r_origin, v);
529 if (DotProduct(dir, v) < 0)
534 surf = cl.worldmodel->surfaces + r->surface;
536 // skip decals on surfaces that aren't visible in this frame
537 if (surf->visframe != r_framecount)
540 // do not render if the view origin is behind the decal
541 VectorSubtract(r->org, r_origin, v);
542 if (DotProduct(r->dir, v) < 0)
545 VectorCopy(r->org, org);
546 VectorCopy(r->dir, dir);
549 fog = exp(fogdensity/DotProduct(v,v));
550 fog = bound(0, fog, 1);
551 m.ca = r->color[3] * fog;
555 dist = -PlaneDiff(r->org, surf->plane);
556 VectorMA(r->org, dist, surf->plane->normal, impact);
558 ds = (int) (DotProduct(impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]) - surf->texturemins[0];
559 dt = (int) (DotProduct(impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]) - surf->texturemins[1];
561 if (ds < 0 || dt < 0 || ds > surf->extents[0] || dt > surf->extents[1])
563 // this should never happen
567 tex = &particletexture[r->tex][1];
568 VectorVectors(dir, right, up);
569 VectorScale(right, r->scale, right);
570 VectorScale(up, r->scale, up);
571 tv[0][0] = org[0] - right[0] - up[0];
572 tv[0][1] = org[1] - right[1] - up[1];
573 tv[0][2] = org[2] - right[2] - up[2];
576 tv[1][0] = org[0] - right[0] + up[0];
577 tv[1][1] = org[1] - right[1] + up[1];
578 tv[1][2] = org[2] - right[2] + up[2];
581 tv[2][0] = org[0] + right[0] + up[0];
582 tv[2][1] = org[1] + right[1] + up[1];
583 tv[2][2] = org[2] + right[2] + up[2];
586 tv[3][0] = org[0] + right[0] - up[0];
587 tv[3][1] = org[1] + right[1] - up[1];
588 tv[3][2] = org[2] + right[2] - up[2];
592 // if the surface is transparent, render as transparent
593 m.transparent = !(surf->flags & SURF_CLIPSOLID);
594 R_Mesh_DrawDecal(&m);