]> icculus.org git repositories - divverent/darkplaces.git/blob - r_decals.c
rewrote RecursiveHullCheck, no longer gets stuck on angle changes, and is generally...
[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 #define MAX_DECALS 2048
24
25 typedef struct decal_s
26 {
27         vec3_t          org;
28         vec3_t          direction;
29         vec2_t          texcoord[4];
30         vec3_t          vert[4];
31         byte            color[4];
32         rtexture_t      *tex;
33         msurface_t      *surface;
34         byte            *lightmapaddress;
35         int                     lightmapstep;
36 }
37 decal_t;
38
39 decal_t *decals;
40 int currentdecal; // wraps around in decal array, replacing old ones when a new one is needed
41
42 cvar_t r_drawdecals = {0, "r_drawdecals", "1"};
43 cvar_t r_decals_lighting = {0, "r_decals_lighting", "1"};
44
45 void r_decals_start(void)
46 {
47         decals = (decal_t *) qmalloc(MAX_DECALS * sizeof(decal_t));
48         memset(decals, 0, MAX_DECALS * sizeof(decal_t));
49         currentdecal = 0;
50 }
51
52 void r_decals_shutdown(void)
53 {
54         qfree(decals);
55 }
56
57 void r_decals_newmap(void)
58 {
59         memset(decals, 0, MAX_DECALS * sizeof(decal_t));
60         currentdecal = 0;
61 }
62
63 void R_Decals_Init(void)
64 {
65         Cvar_RegisterVariable (&r_drawdecals);
66         Cvar_RegisterVariable (&r_decals_lighting);
67
68         R_RegisterModule("R_Decals", r_decals_start, r_decals_shutdown, r_decals_newmap);
69 }
70
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)
77 {
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;
81         static vec3_t impact;
82         static int ds, dt;
83
84 loc0:
85         if (node->contents < 0)
86                 return;
87
88         ndist = PlaneDiff(decalorg, node->plane);
89
90         if (ndist > 16)
91         {
92                 node = node->children[0];
93                 goto loc0;
94         }
95         if (ndist < -16)
96         {
97                 node = node->children[1];
98                 goto loc0;
99         }
100
101 // mark the polygons
102         surf = cl.worldmodel->surfaces + node->firstsurface;
103         endsurf = surf + node->numsurfaces;
104         for (;surf < endsurf;surf++)
105         {
106                 if (surf->flags & SURF_DRAWTILED)
107                         continue;       // no lightmaps
108
109                 dist = PlaneDiff(decalorg, surf->plane);
110                 if (surf->flags & SURF_PLANEBACK)
111                         dist = -dist;
112                 if (dist < 0)
113                         continue;
114                 if (dist >= decalbestdist)
115                         continue;
116
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;
120
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]);
123
124                 if (ds < surf->texturemins[0] || dt < surf->texturemins[1])
125                         continue;
126                 
127                 ds -= surf->texturemins[0];
128                 dt -= surf->texturemins[1];
129                 
130                 if (ds > surf->extents[0] || dt > surf->extents[1])
131                         continue;
132
133                 decalbestsurf = surf;
134                 decalbestdist = dist;
135                 decalbestlightmapofs = (dt >> 4) * ((surf->extents[0] >> 4) + 1) + (ds >> 4);
136         }
137
138         if (node->children[0]->contents >= 0)
139         {
140                 if (node->children[1]->contents >= 0)
141                 {
142                         R_RecursiveDecalSurface (node->children[0]);
143                         node = node->children[1];
144                         goto loc0;
145                 }
146                 else
147                 {
148                         node = node->children[0];
149                         goto loc0;
150                 }
151         }
152         else if (node->children[1]->contents >= 0)
153         {
154                 node = node->children[1];
155                 goto loc0;
156         }
157 }
158
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)
160 {
161         vec3_t center, right, up;
162         decal_t *decal;
163
164         if (alpha < 1)
165                 return;
166
167         // find the best surface to place the decal on
168         decalbestsurf = NULL;
169         decalbestdist = 16;
170         decalbestlightmapofs = 0;
171         VectorCopy(org, decalorg);
172
173         R_RecursiveDecalSurface (cl.worldmodel->nodes);
174
175         // abort if no suitable surface was found
176         if (decalbestsurf == NULL)
177                 return;
178
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;
181         currentdecal++;
182         if (currentdecal >= MAX_DECALS)
183                 currentdecal = 0;
184         decal->tex = tex;
185         VectorCopy(decalbestsurf->plane->normal, decal->direction);
186         // reverse 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
196         scale *= 0.5f;
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;
218         // store the color
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
228         else
229                 decal->lightmapaddress = NULL;
230 }
231
232 void GL_DrawDecals (void)
233 {
234         decal_t *p;
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;
237         byte *lightmap;
238         vec3_t v;
239         msurface_t *surf;
240         dlight_t *dl;
241
242         if (!r_drawdecals.value)
243                 return;
244
245         dynamiclight = (int) r_dynamic.value != 0 && (int) r_decals_lighting.value != 0;
246
247         mindist = DotProduct(r_origin, vpn) + 4.0f;
248
249         if (r_render.value)
250         {
251                 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
252                 glEnable(GL_BLEND);
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);
257         }
258         texnum = -1;
259
260         for (i = 0, p = decals;i < MAX_DECALS;i++, p++)
261         {
262                 if (p->tex == NULL)
263                         break;
264                 // skip decals on surfaces that aren't visible in this frame
265                 if (p->surface->visframe != r_framecount)
266                         continue;
267
268                 // do not render if the decal is behind the view
269                 if (DotProduct(p->org, vpn) < mindist)
270                         continue;
271
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)
275                         continue;
276
277                 // get the surface lighting
278                 surf = p->surface;
279                 lightmap = p->lightmapaddress;
280                 // dynamic lighting
281                 lit = false;
282                 if (dynamiclight)
283                 {
284                         fr = fg = fb = 0.0f;
285                         if (surf->dlightframe == r_framecount)
286                         {
287                                 for (j = 0;j < 8;j++)
288                                 {
289                                         bits = surf->dlightbits[j];
290                                         if (bits)
291                                         {
292                                                 for (k = 0, dl = cl_dlights + j * 32;bits;k++, dl++)
293                                                 {
294                                                         if (bits & (1 << k))
295                                                         {
296                                                                 bits -= 1 << k;
297                                                                 VectorSubtract(p->org, dl->origin, v);
298                                                                 dist = DotProduct(v, v) + LIGHTOFFSET;
299                                                                 rad = dl->radius * dl->radius;
300                                                                 if (dist < rad)
301                                                                 {
302                                                                         rad *= 128.0f / dist;
303                                                                         fr += rad * dl->color[0];
304                                                                         fg += rad * dl->color[1];
305                                                                         fb += rad * dl->color[2];
306                                                                         lit = true;
307                                                                 }
308                                                         }
309                                                 }
310                                         }
311                                 }
312                         }
313                 }
314                 if (lit)
315                 {
316 #if SLOWMATH
317                         ir = fr * 256.0f;
318                         ig = fg * 256.0f;
319                         ib = fb * 256.0f;
320 #else
321                         fr += 8388608.0f;
322                         fg += 8388608.0f;
323                         fb += 8388608.0f;
324                         ir = (*((long *)&fr) & 0x7FFFFF) << 8;
325                         ig = (*((long *)&fg) & 0x7FFFFF) << 8;
326                         ib = (*((long *)&fb) & 0x7FFFFF) << 8;
327 #endif
328                 }
329                 else
330                         ir = ig = ib = 0;
331 #if 1
332                 if (lightmap)
333                 {
334                         if (surf->styles[0] != 255)
335                         {
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)
341                                 {
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)
348                                         {
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)
355                                                 {
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;
361                                                 }
362                                         }
363                                 }
364                         }
365                 }
366 #else
367                 fr = fg = fb = 0.0f;
368                 if (lightmap)
369                 {
370                         if (surf->styles[0] != 255)
371                         {
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)
377                                 {
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)
384                                         {
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)
391                                                 {
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;
397                                                 }
398                                         }
399                                 }
400                         }
401                         /*
402                         for (j = 0;j < MAXLIGHTMAPS && surf->styles[j] != 255;j++)
403                         {
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;
409                         }
410                         */
411                 }
412 #endif
413                 /*
414                 {
415                         int ir, ig, ib;
416                         byte br, bg, bb, ba;
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);
425                         ba = p->color[3];
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);
432                         transpolyend();
433                 }
434                 */
435                 if (r_render.value)
436                 {
437                         j = R_GetTexture(p->tex);
438                         if (texnum != j)
439                         {
440                                 glEnd();
441                                 texnum = j;
442                                 glBindTexture(GL_TEXTURE_2D, texnum);
443                                 glBegin(GL_QUADS);
444                         }
445                         /*
446                         if (lighthalf)
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));
448                         else
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));
450                         */
451                         if (lighthalf)
452                         {
453                                 cr = (ir * p->color[0]) >> 16;
454                                 cg = (ig * p->color[1]) >> 16;
455                                 cb = (ib * p->color[2]) >> 16;
456                         }
457                         else
458                         {
459                                 cr = (ir * p->color[0]) >> 15;
460                                 cg = (ig * p->color[1]) >> 15;
461                                 cb = (ib * p->color[2]) >> 15;
462                         }
463                         cr = min(cr, 255);
464                         cg = min(cg, 255);
465                         cb = min(cb, 255);
466                         glColor4ub(cr, cg, cb, p->color[3]);
467
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]);
476                 }
477         }
478
479         if (r_render.value)
480         {
481                 glEnd();
482
483                 glDepthMask(1); // enable zbuffer updates
484                 glDisable(GL_ALPHA_TEST);
485         }
486 }