]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - r_decals.c
coronas now scale with the light radius
[xonotic/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 /*
45 static int decalindexarray[2*3] =
46 {
47         0, 1, 2,
48         0, 2, 3,
49 };
50 */
51
52 void R_DrawDecals (void)
53 {
54         renderdecal_t *r;
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;
58         byte *lightmap;
59         msurface_t *surf;
60         rdlight_t *rd;
61         rmeshinfo_t m;
62
63         if (!r_drawdecals.integer)
64                 return;
65
66         fog = 0;
67         ifog = 1;
68
69         Mod_CheckLoaded(cl.worldmodel);
70
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;
76         //m.numtriangles = 2;
77         //m.numverts = 4;
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]);
84
85         for (i = 0, r = r_refdef.decals;i < r_refdef.numdecals;i++, r++)
86         {
87                 if (r->ent)
88                 {
89                         if (r->ent->visframe != r_framecount)
90                                 continue;
91
92                         Mod_CheckLoaded(r->ent->model);
93                         if (r->ent->model->type != mod_brush)
94                                 continue;
95
96                         surf = r->ent->model->surfaces + r->surface;
97
98                         // skip decals on surfaces that aren't visible in this frame
99                         if (surf->visframe != r_framecount)
100                                 continue;
101
102                         softwaretransformforentity(r->ent);
103                         softwaretransform(r->org, org);
104                         softwaretransformdirection(r->dir, dir);
105
106                         // do not render if the view origin is behind the decal
107                         VectorSubtract(org, r_origin, fogvec);
108                         if (DotProduct(dir, fogvec) < 0)
109                                 continue;
110                 }
111                 else
112                 {
113                         surf = cl.worldmodel->surfaces + r->surface;
114
115                         // skip decals on surfaces that aren't visible in this frame
116                         if (surf->visframe != r_framecount)
117                                 continue;
118
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)
122                                 continue;
123
124                         VectorCopy(r->org, org);
125                         VectorCopy(r->dir, dir);
126                 }
127
128                 dist = -PlaneDiff(r->org, surf->plane);
129                 VectorMA(r->org, dist, surf->plane->normal, impact);
130
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];
133
134                 if (ds < 0 || dt < 0 || ds > surf->extents[0] || dt > surf->extents[1])
135                 {
136                         // this should never happen
137                         continue;
138                 }
139
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;
164
165                 // lighting
166                 fr = fg = fb = 0.0f;
167
168                 if ((lightmap = surf->samples))
169                 {
170                         if (surf->styles[0] != 255)
171                         {
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)
178                                 {
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)
186                                         {
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)
193                                                 {
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;
199                                                 }
200                                         }
201                                 }
202                         }
203                 }
204
205                 if (surf->dlightframe == r_framecount)
206                 {
207                         for (j = 0;j < r_numdlights;j++)
208                         {
209                                 if (surf->dlightbits[j >> 5] & (1 << (j & 31)))
210                                 {
211                                         rd = &r_dlight[j];
212                                         VectorSubtract(r->org, rd->origin, v);
213                                         dist = DotProduct(v, v) + LIGHTOFFSET;
214                                         if (dist < rd->cullradius2)
215                                         {
216                                                 f = (1.0f / dist) - rd->lightsubtract;
217                                                 if (f > 0)
218                                                 {
219                                                         fr += f * rd->light[0];
220                                                         fg += f * rd->light[1];
221                                                         fb += f * rd->light[2];
222                                                 }
223                                         }
224                                 }
225                         }
226                 }
227
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;
233                 m.ca = r->color[3];
234
235                 if (fogenabled)
236                 {
237                         fog = exp(fogdensity/DotProduct(fogvec,fogvec));
238                         texfog = &particletexture[r->tex][1];
239                         if (fog >= (1.0f / 64.0f))
240                         {
241                                 if (fog >= (1.0f - (1.0f / 64.0f)))
242                                 {
243                                         // fully fogged, just use the fog texture and render as alpha
244                                         m.cr = fogcolor[0];
245                                         m.cg = fogcolor[1];
246                                         m.cb = fogcolor[2];
247                                         m.ca = r->color[3];
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);
257                                 }
258                                 else
259                                 {
260                                         // partially fogged, darken the first pass
261                                         ifog = 1 - fog;
262                                         m.cr *= ifog;
263                                         m.cg *= ifog;
264                                         m.cb *= ifog;
265                                         if (tex->s1 == texfog->s1 && tex->t1 == texfog->t1)
266                                         {
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);
272                                         }
273                                         else
274                                         {
275                                                 // render the first pass (alpha), then do additive fog
276                                                 R_Mesh_DrawDecal(&m);
277                                                 m.blendfunc2 = GL_ONE;
278                                                 m.cr = fogcolor[0];
279                                                 m.cg = fogcolor[1];
280                                                 m.cb = fogcolor[2];
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;
292                                         }
293                                 }
294                         }
295                         else
296                                 R_Mesh_DrawDecal(&m);
297                 }
298                 else
299                         R_Mesh_DrawDecal(&m);
300         }
301 }
302
303 /*
304 void R_DrawDecals (void)
305 {
306         renderdecal_t *r;
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;
310         byte *lightmap;
311         msurface_t *surf;
312         rdlight_t *rd;
313         rmeshinfo_t m;
314
315         if (!r_drawdecals.integer)
316                 return;
317
318         ifog = 1;
319
320         Mod_CheckLoaded(cl.worldmodel);
321
322         memset(&m, 0, sizeof(m));
323         m.blendfunc1 = GL_SRC_ALPHA;
324         m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
325         m.numtriangles = 2;
326         m.numverts = 4;
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]);
333
334         for (i = 0, r = r_refdef.decals;i < r_refdef.numdecals;i++, r++)
335         {
336                 if (r->ent)
337                 {
338                         if (r->ent->visframe != r_framecount)
339                                 continue;
340
341                         Mod_CheckLoaded(r->ent->model);
342                         if (r->ent->model->type != mod_brush)
343                                 continue;
344
345                         surf = r->ent->model->surfaces + r->surface;
346
347                         // skip decals on surfaces that aren't visible in this frame
348                         if (surf->visframe != r_framecount)
349                                 continue;
350
351                         softwaretransformforentity(r->ent);
352                         softwaretransform(r->org, org);
353                         softwaretransformdirection(r->dir, dir);
354
355                         // do not render if the view origin is behind the decal
356                         VectorSubtract(org, r_origin, v);
357                         if (DotProduct(dir, v) < 0)
358                                 continue;
359                 }
360                 else
361                 {
362                         surf = cl.worldmodel->surfaces + r->surface;
363
364                         // skip decals on surfaces that aren't visible in this frame
365                         if (surf->visframe != r_framecount)
366                                 continue;
367
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)
371                                 continue;
372
373                         VectorCopy(r->org, org);
374                         VectorCopy(r->dir, dir);
375                 }
376
377                 dist = -PlaneDiff(r->org, surf->plane);
378                 VectorMA(r->org, dist, surf->plane->normal, impact);
379
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];
382
383                 if (ds < 0 || dt < 0 || ds > surf->extents[0] || dt > surf->extents[1])
384                 {
385                         // this should never happen
386                         continue;
387                 }
388
389                 if (fogenabled)
390                 {
391                         ifog = 1 - exp(fogdensity/DotProduct(v,v));
392                         ifog = bound(0, ifog, 1);
393                 }
394
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];
402                 tv[0][3] = tex->s1;
403                 tv[0][4] = tex->t1;
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];
407                 tv[1][3] = tex->s1;
408                 tv[1][4] = tex->t2;
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];
412                 tv[2][3] = tex->s2;
413                 tv[2][4] = tex->t2;
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];
417                 tv[3][3] = tex->s2;
418                 tv[3][4] = tex->t1;
419
420                 // lighting
421                 fr = fg = fb = 0.0f;
422
423                 if ((lightmap = surf->samples))
424                 {
425                         if (surf->styles[0] != 255)
426                         {
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)
433                                 {
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)
441                                         {
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)
448                                                 {
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;
454                                                 }
455                                         }
456                                 }
457                         }
458                 }
459
460                 if (surf->dlightframe == r_framecount)
461                 {
462                         for (j = 0;j < r_numdlights;j++)
463                         {
464                                 if (surf->dlightbits[j >> 5] & (1 << (j & 31)))
465                                 {
466                                         rd = &r_dlight[j];
467                                         VectorSubtract(r->org, rd->origin, v);
468                                         dist = DotProduct(v, v) + LIGHTOFFSET;
469                                         if (dist < rd->cullradius2)
470                                         {
471                                                 f = (1.0f / dist) - rd->lightsubtract;
472                                                 if (f > 0)
473                                                 {
474                                                         fr += f * rd->light[0];
475                                                         fg += f * rd->light[1];
476                                                         fb += f * rd->light[2];
477                                                 }
478                                         }
479                                 }
480                         }
481                 }
482
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;
488                 m.ca = r->color[3];
489
490                 if (fogenabled)
491                 {
492                         m.cr *= ifog;
493                         m.cg *= ifog;
494                         m.cb *= ifog;
495                 }
496
497                 R_Mesh_DrawDecal(&m);
498         }
499
500         if (!fogenabled)
501                 return;
502
503         m.blendfunc2 = GL_ONE;
504         m.cr = fogcolor[0];
505         m.cg = fogcolor[1];
506         m.cb = fogcolor[2];
507
508         for (i = 0, r = r_refdef.decals;i < r_refdef.numdecals;i++, r++)
509         {
510                 if (r->ent)
511                 {
512                         if (r->ent->visframe != r_framecount)
513                                 continue;
514
515                         Mod_CheckLoaded(r->ent->model);
516
517                         surf = r->ent->model->surfaces + r->surface;
518
519                         // skip decals on surfaces that aren't visible in this frame
520                         if (surf->visframe != r_framecount)
521                                 continue;
522
523                         softwaretransformforentity(r->ent);
524                         softwaretransform(r->org, org);
525                         softwaretransformdirection(r->dir, dir);
526
527                         // do not render if the view origin is behind the decal
528                         VectorSubtract(org, r_origin, v);
529                         if (DotProduct(dir, v) < 0)
530                                 continue;
531                 }
532                 else
533                 {
534                         surf = cl.worldmodel->surfaces + r->surface;
535
536                         // skip decals on surfaces that aren't visible in this frame
537                         if (surf->visframe != r_framecount)
538                                 continue;
539
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)
543                                 continue;
544
545                         VectorCopy(r->org, org);
546                         VectorCopy(r->dir, dir);
547                 }
548
549                 fog = exp(fogdensity/DotProduct(v,v));
550                 fog = bound(0, fog, 1);
551                 m.ca = r->color[3] * fog;
552
553                 if (m.ca >= 0.01f)
554                 {
555                         dist = -PlaneDiff(r->org, surf->plane);
556                         VectorMA(r->org, dist, surf->plane->normal, impact);
557
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];
560
561                         if (ds < 0 || dt < 0 || ds > surf->extents[0] || dt > surf->extents[1])
562                         {
563                                 // this should never happen
564                                 continue;
565                         }
566
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];
574                         tv[0][3] = tex->s1;
575                         tv[0][4] = tex->t1;
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];
579                         tv[1][3] = tex->s1;
580                         tv[1][4] = tex->t2;
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];
584                         tv[2][3] = tex->s2;
585                         tv[2][4] = tex->t2;
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];
589                         tv[3][3] = tex->s2;
590                         tv[3][4] = tex->t1;
591
592                         // if the surface is transparent, render as transparent
593                         m.transparent = !(surf->flags & SURF_CLIPSOLID);
594                         R_Mesh_DrawDecal(&m);
595                 }
596         }
597 }
598 */