]> icculus.org git repositories - divverent/darkplaces.git/blob - r_decals.c
more thorough checking of 'this should never happen' cases
[divverent/darkplaces.git] / r_decals.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
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
21 #include "quakedef.h"
22
23 cvar_t r_drawdecals = {0, "r_drawdecals", "1"};
24
25 static void r_decals_start(void)
26 {
27 }
28
29 static void r_decals_shutdown(void)
30 {
31 }
32
33 static void r_decals_newmap(void)
34 {
35 }
36
37 void R_Decals_Init(void)
38 {
39         Cvar_RegisterVariable (&r_drawdecals);
40
41         R_RegisterModule("R_Decals", r_decals_start, r_decals_shutdown, r_decals_newmap);
42 }
43
44 static int decalindexarray[2*3] =
45 {
46         0, 1, 2,
47         0, 2, 3,
48 };
49
50 void R_DrawDecals (void)
51 {
52         renderdecal_t *r;
53         int i, j, lightmapstep, ds, dt;
54         float fscale, fr, fg, fb, dist, f, ifog, impact[3], v[3], org[3], dir[3], right[3], up[3], tvertex[4][5];
55         particletexture_t *tex;
56         byte *lightmap;
57         msurface_t *surf;
58         rdlight_t *rd;
59         rmeshinfo_t m;
60
61         if (!r_drawdecals.integer)
62                 return;
63
64         ifog = 1;
65
66         Mod_CheckLoaded(cl.worldmodel);
67
68         memset(&m, 0, sizeof(m));
69         m.blendfunc1 = GL_SRC_ALPHA;
70         m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
71         m.numtriangles = 2;
72         m.numverts = 4;
73         m.index = decalindexarray;
74         m.vertex = &tvertex[0][0];
75         m.vertexstep = sizeof(float[5]);
76         m.tex[0] = R_GetTexture(particlefonttexture);
77         m.texcoords[0] = &tvertex[0][3];
78         m.texcoordstep[0] = sizeof(float[5]);
79
80         for (i = 0, r = r_refdef.decals;i < r_refdef.numdecals;i++, r++)
81         {
82                 if (r->ent)
83                 {
84                         if (r->ent->visframe != r_framecount)
85                                 continue;
86
87                         Mod_CheckLoaded(r->ent->model);
88                         if (r->ent->model->type != mod_brush)
89                                 continue;
90
91                         surf = r->ent->model->surfaces + r->surface;
92
93                         // skip decals on surfaces that aren't visible in this frame
94                         if (surf->visframe != r_framecount)
95                                 continue;
96
97                         softwaretransformforentity(r->ent);
98                         softwaretransform(r->org, org);
99                         softwaretransformdirection(r->dir, dir);
100
101                         // do not render if the view origin is behind the decal
102                         VectorSubtract(org, r_origin, v);
103                         if (DotProduct(dir, v) < 0)
104                                 continue;
105                 }
106                 else
107                 {
108                         surf = cl.worldmodel->surfaces + r->surface;
109
110                         // skip decals on surfaces that aren't visible in this frame
111                         if (surf->visframe != r_framecount)
112                                 continue;
113
114                         // do not render if the view origin is behind the decal
115                         VectorSubtract(r->org, r_origin, v);
116                         if (DotProduct(r->dir, v) < 0)
117                                 continue;
118
119                         VectorCopy(r->org, org);
120                         VectorCopy(r->dir, dir);
121                 }
122
123                 dist = -PlaneDiff(r->org, surf->plane);
124                 VectorMA(r->org, dist, surf->plane->normal, impact);
125
126                 ds = (int) (DotProduct(impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]) - surf->texturemins[0];
127                 dt = (int) (DotProduct(impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]) - surf->texturemins[1];
128
129                 if (ds < 0 || dt < 0 || ds > surf->extents[0] || dt > surf->extents[1])
130                 {
131                         // this should never happen
132                         continue;
133                 }
134
135                 if (fogenabled)
136                         ifog = 1 - exp(fogdensity/DotProduct(v,v));
137
138                 tex = &particletexture[r->tex][0];
139                 VectorVectors(dir, right, up);
140                 VectorScale(right, r->scale, right);
141                 VectorScale(up, r->scale, up);
142                 tvertex[0][0] = org[0] - right[0] - up[0];
143                 tvertex[0][1] = org[1] - right[1] - up[1];
144                 tvertex[0][2] = org[2] - right[2] - up[2];
145                 tvertex[0][3] = tex->s1;
146                 tvertex[0][4] = tex->t1;
147                 tvertex[1][0] = org[0] - right[0] + up[0];
148                 tvertex[1][1] = org[1] - right[1] + up[1];
149                 tvertex[1][2] = org[2] - right[2] + up[2];
150                 tvertex[1][3] = tex->s1;
151                 tvertex[1][4] = tex->t2;
152                 tvertex[2][0] = org[0] + right[0] + up[0];
153                 tvertex[2][1] = org[1] + right[1] + up[1];
154                 tvertex[2][2] = org[2] + right[2] + up[2];
155                 tvertex[2][3] = tex->s2;
156                 tvertex[2][4] = tex->t2;
157                 tvertex[3][0] = org[0] + right[0] - up[0];
158                 tvertex[3][1] = org[1] + right[1] - up[1];
159                 tvertex[3][2] = org[2] + right[2] - up[2];
160                 tvertex[3][3] = tex->s2;
161                 tvertex[3][4] = tex->t1;
162
163                 // lighting
164                 fr = fg = fb = 0.0f;
165
166                 if ((lightmap = surf->samples))
167                 {
168                         if (surf->styles[0] != 255)
169                         {
170                                 lightmap += ((dt >> 4) * ((surf->extents[0] >> 4) + 1) + (ds >> 4)) * 3;
171                                 fscale = d_lightstylevalue[surf->styles[0]] * (1.0f / 32768.0f);
172                                 fr += lightmap[0] * fscale;
173                                 fg += lightmap[1] * fscale;
174                                 fb += lightmap[2] * fscale;
175                                 if (surf->styles[1] != 255)
176                                 {
177                                         lightmapstep = (((surf->extents[0] >> 4) + 1) * ((surf->extents[1] >> 4) + 1)) * 3;
178                                         lightmap += lightmapstep;
179                                         fscale = d_lightstylevalue[surf->styles[1]] * (1.0f / 32768.0f);
180                                         fr += lightmap[0] * fscale;
181                                         fg += lightmap[1] * fscale;
182                                         fb += lightmap[2] * fscale;
183                                         if (surf->styles[2] != 255)
184                                         {
185                                                 lightmap += lightmapstep;
186                                                 fscale = d_lightstylevalue[surf->styles[2]] * (1.0f / 32768.0f);
187                                                 fr += lightmap[0] * fscale;
188                                                 fg += lightmap[1] * fscale;
189                                                 fb += lightmap[2] * fscale;
190                                                 if (surf->styles[3] != 255)
191                                                 {
192                                                         lightmap += lightmapstep;
193                                                         fscale = d_lightstylevalue[surf->styles[3]] * (1.0f / 32768.0f);
194                                                         fr += lightmap[0] * fscale;
195                                                         fg += lightmap[1] * fscale;
196                                                         fb += lightmap[2] * fscale;
197                                                 }
198                                         }
199                                 }
200                         }
201                 }
202
203                 if (surf->dlightframe == r_framecount)
204                 {
205                         for (j = 0;j < r_numdlights;j++)
206                         {
207                                 if (surf->dlightbits[j >> 5] & (1 << (j & 31)))
208                                 {
209                                         rd = &r_dlight[j];
210                                         VectorSubtract(r->org, rd->origin, v);
211                                         dist = DotProduct(v, v) + LIGHTOFFSET;
212                                         if (dist < rd->cullradius2)
213                                         {
214                                                 f = (1.0f / dist) - rd->lightsubtract;
215                                                 if (f > 0)
216                                                 {
217                                                         fr += f * rd->light[0];
218                                                         fg += f * rd->light[1];
219                                                         fb += f * rd->light[2];
220                                                 }
221                                         }
222                                 }
223                         }
224                 }
225
226                 // if the surface is transparent, render as transparent
227                 m.transparent = !(surf->flags & SURF_CLIPSOLID);
228                 m.cr = r->color[0] * fr;
229                 m.cg = r->color[1] * fg;
230                 m.cb = r->color[2] * fb;
231                 m.ca = r->color[3];
232
233                 if (fogenabled)
234                 {
235                         m.cr *= ifog;
236                         m.cg *= ifog;
237                         m.cb *= ifog;
238                 }
239
240                 R_Mesh_Draw(&m);
241         }
242
243         if (!fogenabled)
244                 return;
245
246         m.blendfunc2 = GL_ONE;
247         m.cr = fogcolor[0];
248         m.cg = fogcolor[1];
249         m.cb = fogcolor[2];
250
251         for (i = 0, r = r_refdef.decals;i < r_refdef.numdecals;i++, r++)
252         {
253                 if (r->ent)
254                 {
255                         if (r->ent->visframe != r_framecount)
256                                 continue;
257
258                         Mod_CheckLoaded(r->ent->model);
259
260                         surf = r->ent->model->surfaces + r->surface;
261
262                         // skip decals on surfaces that aren't visible in this frame
263                         if (surf->visframe != r_framecount)
264                                 continue;
265
266                         softwaretransformforentity(r->ent);
267                         softwaretransform(r->org, org);
268                         softwaretransformdirection(r->dir, dir);
269
270                         // do not render if the view origin is behind the decal
271                         VectorSubtract(org, r_origin, v);
272                         if (DotProduct(dir, v) < 0)
273                                 continue;
274                 }
275                 else
276                 {
277                         surf = cl.worldmodel->surfaces + r->surface;
278
279                         // skip decals on surfaces that aren't visible in this frame
280                         if (surf->visframe != r_framecount)
281                                 continue;
282
283                         // do not render if the view origin is behind the decal
284                         VectorSubtract(r->org, r_origin, v);
285                         if (DotProduct(r->dir, v) < 0)
286                                 continue;
287
288                         VectorCopy(r->org, org);
289                         VectorCopy(r->dir, dir);
290                 }
291
292                 m.ca = r->color[3] * exp(fogdensity/DotProduct(v,v));
293
294                 if (m.ca >= 0.01f)
295                 {
296                         dist = -PlaneDiff(r->org, surf->plane);
297                         VectorMA(r->org, dist, surf->plane->normal, impact);
298
299                         ds = (int) (DotProduct(impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]) - surf->texturemins[0];
300                         dt = (int) (DotProduct(impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]) - surf->texturemins[1];
301
302                         if (ds < 0 || dt < 0 || ds > surf->extents[0] || dt > surf->extents[1])
303                         {
304                                 // this should never happen
305                                 continue;
306                         }
307
308                         tex = &particletexture[r->tex][1];
309                         VectorVectors(dir, right, up);
310                         VectorScale(right, r->scale, right);
311                         VectorScale(up, r->scale, up);
312                         tvertex[0][0] = org[0] - right[0] - up[0];
313                         tvertex[0][1] = org[1] - right[1] - up[1];
314                         tvertex[0][2] = org[2] - right[2] - up[2];
315                         tvertex[0][3] = tex->s1;
316                         tvertex[0][4] = tex->t1;
317                         tvertex[1][0] = org[0] - right[0] + up[0];
318                         tvertex[1][1] = org[1] - right[1] + up[1];
319                         tvertex[1][2] = org[2] - right[2] + up[2];
320                         tvertex[1][3] = tex->s1;
321                         tvertex[1][4] = tex->t2;
322                         tvertex[2][0] = org[0] + right[0] + up[0];
323                         tvertex[2][1] = org[1] + right[1] + up[1];
324                         tvertex[2][2] = org[2] + right[2] + up[2];
325                         tvertex[2][3] = tex->s2;
326                         tvertex[2][4] = tex->t2;
327                         tvertex[3][0] = org[0] + right[0] - up[0];
328                         tvertex[3][1] = org[1] + right[1] - up[1];
329                         tvertex[3][2] = org[2] + right[2] - up[2];
330                         tvertex[3][3] = tex->s2;
331                         tvertex[3][4] = tex->t1;
332
333                         // if the surface is transparent, render as transparent
334                         m.transparent = !(surf->flags & SURF_CLIPSOLID);
335                         R_Mesh_Draw(&m);
336                 }
337         }
338 }
339