rewrote memory system entirely (hunk, cache, and zone are gone, memory pools replaced...
[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 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
89                         surf = r->ent->model->surfaces + r->surface;
90
91                         // skip decals on surfaces that aren't visible in this frame
92                         if (surf->visframe != r_framecount)
93                                 continue;
94
95                         softwaretransformforentity(r->ent);
96                         softwaretransform(r->org, org);
97                         softwaretransformdirection(r->dir, dir);
98
99                         // do not render if the view origin is behind the decal
100                         VectorSubtract(org, r_origin, v);
101                         if (DotProduct(dir, v) < 0)
102                                 continue;
103                 }
104                 else
105                 {
106                         surf = cl.worldmodel->surfaces + r->surface;
107
108                         // skip decals on surfaces that aren't visible in this frame
109                         if (surf->visframe != r_framecount)
110                                 continue;
111
112                         // do not render if the view origin is behind the decal
113                         VectorSubtract(r->org, r_origin, v);
114                         if (DotProduct(r->dir, v) < 0)
115                                 continue;
116
117                         VectorCopy(r->org, org);
118                         VectorCopy(r->dir, dir);
119                 }
120
121                 dist = -PlaneDiff(r->org, surf->plane);
122                 VectorMA(r->org, dist, surf->plane->normal, impact);
123
124                 ds = (int) (DotProduct(impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]) - surf->texturemins[0];
125                 dt = (int) (DotProduct(impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]) - surf->texturemins[1];
126
127                 if (ds < 0 || dt < 0 || ds > surf->extents[0] || dt > surf->extents[1])
128                 {
129                         // this should never happen
130                         continue;
131                 }
132
133                 if (fogenabled)
134                         ifog = 1 - exp(fogdensity/DotProduct(v,v));
135
136                 tex = &particletexture[r->tex][0];
137                 VectorVectors(dir, right, up);
138                 VectorScale(right, r->scale, right);
139                 VectorScale(up, r->scale, up);
140                 tvertex[0][0] = org[0] - right[0] - up[0];
141                 tvertex[0][1] = org[1] - right[1] - up[1];
142                 tvertex[0][2] = org[2] - right[2] - up[2];
143                 tvertex[0][3] = tex->s1;
144                 tvertex[0][4] = tex->t1;
145                 tvertex[1][0] = org[0] - right[0] + up[0];
146                 tvertex[1][1] = org[1] - right[1] + up[1];
147                 tvertex[1][2] = org[2] - right[2] + up[2];
148                 tvertex[1][3] = tex->s1;
149                 tvertex[1][4] = tex->t2;
150                 tvertex[2][0] = org[0] + right[0] + up[0];
151                 tvertex[2][1] = org[1] + right[1] + up[1];
152                 tvertex[2][2] = org[2] + right[2] + up[2];
153                 tvertex[2][3] = tex->s2;
154                 tvertex[2][4] = tex->t2;
155                 tvertex[3][0] = org[0] + right[0] - up[0];
156                 tvertex[3][1] = org[1] + right[1] - up[1];
157                 tvertex[3][2] = org[2] + right[2] - up[2];
158                 tvertex[3][3] = tex->s2;
159                 tvertex[3][4] = tex->t1;
160
161                 // lighting
162                 fr = fg = fb = 0.0f;
163
164                 if ((lightmap = surf->samples))
165                 {
166                         if (surf->styles[0] != 255)
167                         {
168                                 lightmap += ((dt >> 4) * ((surf->extents[0] >> 4) + 1) + (ds >> 4)) * 3;
169                                 fscale = d_lightstylevalue[surf->styles[0]] * (1.0f / 32768.0f);
170                                 fr += lightmap[0] * fscale;
171                                 fg += lightmap[1] * fscale;
172                                 fb += lightmap[2] * fscale;
173                                 if (surf->styles[1] != 255)
174                                 {
175                                         lightmapstep = (((surf->extents[0] >> 4) + 1) * ((surf->extents[1] >> 4) + 1)) * 3;
176                                         lightmap += lightmapstep;
177                                         fscale = d_lightstylevalue[surf->styles[1]] * (1.0f / 32768.0f);
178                                         fr += lightmap[0] * fscale;
179                                         fg += lightmap[1] * fscale;
180                                         fb += lightmap[2] * fscale;
181                                         if (surf->styles[2] != 255)
182                                         {
183                                                 lightmap += lightmapstep;
184                                                 fscale = d_lightstylevalue[surf->styles[2]] * (1.0f / 32768.0f);
185                                                 fr += lightmap[0] * fscale;
186                                                 fg += lightmap[1] * fscale;
187                                                 fb += lightmap[2] * fscale;
188                                                 if (surf->styles[3] != 255)
189                                                 {
190                                                         lightmap += lightmapstep;
191                                                         fscale = d_lightstylevalue[surf->styles[3]] * (1.0f / 32768.0f);
192                                                         fr += lightmap[0] * fscale;
193                                                         fg += lightmap[1] * fscale;
194                                                         fb += lightmap[2] * fscale;
195                                                 }
196                                         }
197                                 }
198                         }
199                 }
200
201                 if (surf->dlightframe == r_framecount)
202                 {
203                         for (j = 0;j < r_numdlights;j++)
204                         {
205                                 if (surf->dlightbits[j >> 5] & (1 << (j & 31)))
206                                 {
207                                         rd = &r_dlight[j];
208                                         VectorSubtract(r->org, rd->origin, v);
209                                         dist = DotProduct(v, v) + LIGHTOFFSET;
210                                         if (dist < rd->cullradius2)
211                                         {
212                                                 f = (1.0f / dist) - rd->lightsubtract;
213                                                 if (f > 0)
214                                                 {
215                                                         fr += f * rd->light[0];
216                                                         fg += f * rd->light[1];
217                                                         fb += f * rd->light[2];
218                                                 }
219                                         }
220                                 }
221                         }
222                 }
223
224                 // if the surface is transparent, render as transparent
225                 m.transparent = !(surf->flags & SURF_CLIPSOLID);
226                 m.cr = r->color[0] * fr;
227                 m.cg = r->color[1] * fg;
228                 m.cb = r->color[2] * fb;
229                 m.ca = r->color[3];
230
231                 if (fogenabled)
232                 {
233                         m.cr *= ifog;
234                         m.cg *= ifog;
235                         m.cb *= ifog;
236                 }
237
238                 R_Mesh_Draw(&m);
239         }
240
241         if (!fogenabled)
242                 return;
243
244         m.blendfunc2 = GL_ONE;
245         m.cr = fogcolor[0];
246         m.cg = fogcolor[1];
247         m.cb = fogcolor[2];
248
249         for (i = 0, r = r_refdef.decals;i < r_refdef.numdecals;i++, r++)
250         {
251                 if (r->ent)
252                 {
253                         if (r->ent->visframe != r_framecount)
254                                 continue;
255
256                         Mod_CheckLoaded(r->ent->model);
257
258                         surf = r->ent->model->surfaces + r->surface;
259
260                         // skip decals on surfaces that aren't visible in this frame
261                         if (surf->visframe != r_framecount)
262                                 continue;
263
264                         softwaretransformforentity(r->ent);
265                         softwaretransform(r->org, org);
266                         softwaretransformdirection(r->dir, dir);
267
268                         // do not render if the view origin is behind the decal
269                         VectorSubtract(org, r_origin, v);
270                         if (DotProduct(dir, v) < 0)
271                                 continue;
272                 }
273                 else
274                 {
275                         surf = cl.worldmodel->surfaces + r->surface;
276
277                         // skip decals on surfaces that aren't visible in this frame
278                         if (surf->visframe != r_framecount)
279                                 continue;
280
281                         // do not render if the view origin is behind the decal
282                         VectorSubtract(r->org, r_origin, v);
283                         if (DotProduct(r->dir, v) < 0)
284                                 continue;
285
286                         VectorCopy(r->org, org);
287                         VectorCopy(r->dir, dir);
288                 }
289
290                 dist = -PlaneDiff(r->org, surf->plane);
291                 VectorMA(r->org, dist, surf->plane->normal, impact);
292
293                 ds = (int) (DotProduct(impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]) - surf->texturemins[0];
294                 dt = (int) (DotProduct(impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]) - surf->texturemins[1];
295
296                 if (ds < 0 || dt < 0 || ds > surf->extents[0] || dt > surf->extents[1])
297                 {
298                         // this should never happen
299                         continue;
300                 }
301
302                 tex = &particletexture[r->tex][1];
303                 VectorVectors(dir, right, up);
304                 VectorScale(right, r->scale, right);
305                 VectorScale(up, r->scale, up);
306                 tvertex[0][0] = org[0] - right[0] - up[0];
307                 tvertex[0][1] = org[1] - right[1] - up[1];
308                 tvertex[0][2] = org[2] - right[2] - up[2];
309                 tvertex[0][3] = tex->s1;
310                 tvertex[0][4] = tex->t1;
311                 tvertex[1][0] = org[0] - right[0] + up[0];
312                 tvertex[1][1] = org[1] - right[1] + up[1];
313                 tvertex[1][2] = org[2] - right[2] + up[2];
314                 tvertex[1][3] = tex->s1;
315                 tvertex[1][4] = tex->t2;
316                 tvertex[2][0] = org[0] + right[0] + up[0];
317                 tvertex[2][1] = org[1] + right[1] + up[1];
318                 tvertex[2][2] = org[2] + right[2] + up[2];
319                 tvertex[2][3] = tex->s2;
320                 tvertex[2][4] = tex->t2;
321                 tvertex[3][0] = org[0] + right[0] - up[0];
322                 tvertex[3][1] = org[1] + right[1] - up[1];
323                 tvertex[3][2] = org[2] + right[2] - up[2];
324                 tvertex[3][3] = tex->s2;
325                 tvertex[3][4] = tex->t1;
326
327                 // if the surface is transparent, render as transparent
328                 m.transparent = !(surf->flags & SURF_CLIPSOLID);
329                 m.ca = r->color[3] * exp(fogdensity/DotProduct(v,v));
330
331                 if (m.ca >= (1.0f / 255.0f))
332                         R_Mesh_Draw(&m);
333         }
334 }
335