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 // r_light.c
21
22 #include "quakedef.h"
23 #include "r_local.h"
24
25 extern int coloredlights;
26
27 /*
28 ==================
29 R_AnimateLight
30 ==================
31 */
R_AnimateLight(void)32 void R_AnimateLight(void)
33 {
34 int j, k;
35
36 /* light animations
37 * 'm' is normal light, 'a' is no light, 'z' is double bright */
38 int i = (int)(cl.time * 10);
39
40 for (j = 0; j < MAX_LIGHTSTYLES; j++)
41 {
42 if (!cl_lightstyle[j].length)
43 {
44 d_lightstylevalue[j] = 256;
45 continue;
46 }
47 k = i % cl_lightstyle[j].length;
48 k = cl_lightstyle[j].map[k] - 'a';
49 k = k * 22;
50 d_lightstylevalue[j] = k;
51 }
52 }
53
54
55 /*
56 =============================================================================
57
58 DYNAMIC LIGHTS
59
60 =============================================================================
61 */
62
63 /*
64 =============
65 R_MarkLights
66 =============
67 */
R_MarkLights(dlight_t * light,int num,mnode_t * node)68 void R_MarkLights (dlight_t *light, int num, mnode_t *node) //qbism- adapted from MH tute - increased dlights
69 {
70 mplane_t *splitplane;
71 float dist;
72 msurface_t *surf;
73 int i;
74
75 start:
76 if (node->contents < 0)
77 return;
78
79 splitplane = node->plane;
80 dist = DotProduct (light->origin, splitplane->normal) - splitplane->dist;
81
82 if (dist > light->radius)
83 {
84 node = node->children[0];
85 goto start;
86 }
87
88 if (dist < -light->radius)
89 {
90 node = node->children[1];
91 goto start;
92 }
93
94 /* mark the surfaces */
95 surf = cl.worldmodel->surfaces + node->firstsurface;
96
97 for (i = 0; i < node->numsurfaces; i++, surf++)
98 {
99 if (surf->dlightframe != r_framecount)
100 {
101 memset (surf->dlightbits, 0, sizeof (surf->dlightbits));
102 surf->dlightframe = r_framecount;
103 }
104
105 surf->dlightbits[num >> 5] |= 1 << (num & 31);
106 }
107
108 R_MarkLights (light, num, node->children[0]);
109 R_MarkLights (light, num, node->children[1]);
110 }
111
112
113 /*
114 =============
115 R_PushDlights
116 =============
117 */
R_PushDlights(mnode_t * headnode)118 void R_PushDlights(mnode_t *headnode) /* qbism- from MH tute - increased dlights */
119 {
120 int i;
121 dlight_t *l = cl_dlights;
122
123 for (i = 0; i < MAX_DLIGHTS; i++, l++)
124 {
125 if (l->die < cl.time || (l->radius <= 0))
126 continue;
127
128 R_MarkLights(l, i, headnode);
129 }
130 }
131
132
133 /*
134 =============================================================================
135
136 LIGHT SAMPLING
137
138 =============================================================================
139 */
140
RecursiveLightPoint(mnode_t * node,vec3_t start,vec3_t end)141 int RecursiveLightPoint(mnode_t *node, vec3_t start, vec3_t end)
142 {
143 int r;
144 float front, back, frac;
145 int side;
146 mplane_t *plane;
147 vec3_t mid;
148 msurface_t *surf;
149 int s, t, ds, dt;
150 int i;
151 mtexinfo_t *tex;
152 byte *lightmap;
153 unsigned scale;
154 int maps;
155
156 restart:
157 if (node->contents < 0)
158 return -1; // didn't hit anything
159
160 // calculate mid point
161
162 plane = node->plane;
163 switch (plane->type) {
164 case PLANE_X:
165 case PLANE_Y:
166 case PLANE_Z:
167 front = start[plane->type - PLANE_X] - plane->dist;
168 back = end[plane->type - PLANE_X] - plane->dist;
169 break;
170 default:
171 front = DotProduct(start, plane->normal) - plane->dist;
172 back = DotProduct(end, plane->normal) - plane->dist;
173 break;
174 }
175 side = front < 0;
176
177 if ((back < 0) == side) {
178 /* Completely on one side - tail recursion optimization */
179 node = node->children[side];
180 goto restart;
181 }
182
183 frac = front / (front - back);
184 mid[0] = start[0] + (end[0] - start[0]) * frac;
185 mid[1] = start[1] + (end[1] - start[1]) * frac;
186 mid[2] = start[2] + (end[2] - start[2]) * frac;
187
188 // go down front side
189 r = RecursiveLightPoint(node->children[side], start, mid);
190 if (r >= 0)
191 return r; // hit something
192
193 if ((back < 0) == side)
194 return -1; // didn't hit anuthing
195
196 // check for impact on this node
197
198 surf = cl.worldmodel->surfaces + node->firstsurface;
199 for (i = 0; i < node->numsurfaces; i++, surf++) {
200 if (surf->flags & SURF_DRAWTILED)
201 continue; // no lightmaps
202
203 tex = surf->texinfo;
204
205 s = DotProduct(mid, tex->vecs[0]) + tex->vecs[0][3];
206 t = DotProduct(mid, tex->vecs[1]) + tex->vecs[1][3];;
207
208 if (s < surf->texturemins[0] || t < surf->texturemins[1])
209 continue;
210
211 ds = s - surf->texturemins[0];
212 dt = t - surf->texturemins[1];
213
214 if (ds > surf->extents[0] || dt > surf->extents[1])
215 continue;
216
217 if (!surf->samples)
218 return 0;
219
220 ds >>= 4;
221 dt >>= 4;
222
223 /* FIXME: does this account properly for dynamic lights? e.g. rocket */
224 lightmap = surf->samples;
225 r = 0;
226 if (lightmap) {
227 lightmap += dt * ((surf->extents[0] >> 4) + 1) + ds;
228 for (maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255;
229 maps++) {
230 scale = d_lightstylevalue[surf->styles[maps]];
231 r += *lightmap * scale;
232 if (coloredlights)
233 lightmap += ((surf->extents[0] >> 4) + 1) * ((surf->extents[1] >> 4) + 1) * 3;
234 else
235 lightmap += ((surf->extents[0] >> 4) + 1) * ((surf->extents[1] >> 4) + 1); /* colored lighting change */
236
237 }
238 r >>= 8;
239 }
240
241 return r;
242 }
243
244 /* Go down back side */
245 return RecursiveLightPoint(node->children[!side], mid, end);
246 }
247
248
249 mplane_t *lightplane;
250 vec3_t lightspot;
251 // LordHavoc: .lit support begin
252 // LordHavoc: original code replaced entirely
253
RecursiveLightPointRGB(vec3_t color,mnode_t * node,vec3_t start,vec3_t end)254 int RecursiveLightPointRGB(vec3_t color, mnode_t *node, vec3_t start, vec3_t end)
255 {
256 float front, back, frac;
257 vec3_t mid;
258
259 loc0:
260 if (node->contents < 0)
261 return false; // didn't hit anything
262
263 // calculate mid point
264 if (node->plane->type < 3)
265 {
266 front = start[node->plane->type] - node->plane->dist;
267 back = end[node->plane->type] - node->plane->dist;
268 }
269 else
270 {
271 front = DotProduct(start, node->plane->normal) - node->plane->dist;
272 back = DotProduct(end, node->plane->normal) - node->plane->dist;
273 }
274
275 // LordHavoc: optimized recursion
276 if ((back < 0) == (front < 0))
277 // return RecursiveLightPointRGB (color, node->children[front < 0], start, end);
278 {
279 node = node->children[front < 0];
280 goto loc0;
281 }
282
283 frac = front / (front-back);
284 mid[0] = start[0] + (end[0] - start[0])*frac;
285 mid[1] = start[1] + (end[1] - start[1])*frac;
286 mid[2] = start[2] + (end[2] - start[2])*frac;
287
288 // go down front side
289 if (RecursiveLightPointRGB (color, node->children[front < 0], start, mid))
290 return true; // hit something
291 else
292 {
293 int i, ds, dt;
294 msurface_t *surf;
295 // check for impact on this node
296 VectorCopy (mid, lightspot);
297 lightplane = node->plane;
298
299 surf = cl.worldmodel->surfaces + node->firstsurface;
300 for (i = 0;i < node->numsurfaces;i++, surf++)
301 {
302 if (surf->flags & SURF_DRAWTILED)
303 continue; // no lightmaps
304
305 ds = (int) ((float) DotProduct (mid, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]);
306 dt = (int) ((float) DotProduct (mid, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]);
307
308 if (ds < surf->texturemins[0] || dt < surf->texturemins[1])
309 continue;
310
311 ds -= surf->texturemins[0];
312 dt -= surf->texturemins[1];
313
314 if (ds > surf->extents[0] || dt > surf->extents[1])
315 continue;
316
317 if (surf->samples)
318 {
319 // LordHavoc: enhanced to interpolate lighting
320 byte *lightmap;
321 int maps, line3, dsfrac = ds & 15, dtfrac = dt & 15, r00 = 0, g00 = 0, b00 = 0, r01 = 0, g01 = 0, b01 = 0, r10 = 0, g10 = 0, b10 = 0, r11 = 0, g11 = 0, b11 = 0;
322 float scale;
323 line3 = ((surf->extents[0]>>4)+1)*3;
324
325 lightmap = surf->samples + ((dt>>4) * ((surf->extents[0]>>4)+1) + (ds>>4))*3; // LordHavoc: *3 for color
326
327 for (maps = 0;maps < MAXLIGHTMAPS && surf->styles[maps] != 255;maps++)
328 {
329 scale = (float) d_lightstylevalue[surf->styles[maps]] * 1.0 / 256.0;
330 r00 += (float) lightmap[ 0] * scale;g00 += (float) lightmap[ 1] * scale;b00 += (float) lightmap[2] * scale;
331 r01 += (float) lightmap[ 3] * scale;g01 += (float) lightmap[ 4] * scale;b01 += (float) lightmap[5] * scale;
332 r10 += (float) lightmap[line3+0] * scale;g10 += (float) lightmap[line3+1] * scale;b10 += (float) lightmap[line3+2] * scale;
333 r11 += (float) lightmap[line3+3] * scale;g11 += (float) lightmap[line3+4] * scale;b11 += (float) lightmap[line3+5] * scale;
334 lightmap += ((surf->extents[0]>>4)+1) * ((surf->extents[1]>>4)+1)*3; // LordHavoc: *3 for colored lighting
335 }
336
337 color[0] += (float) ((int) ((((((((r11-r10) * dsfrac) >> 4) + r10)-((((r01-r00) * dsfrac) >> 4) + r00)) * dtfrac) >> 4) + ((((r01-r00) * dsfrac) >> 4) + r00)));
338 color[1] += (float) ((int) ((((((((g11-g10) * dsfrac) >> 4) + g10)-((((g01-g00) * dsfrac) >> 4) + g00)) * dtfrac) >> 4) + ((((g01-g00) * dsfrac) >> 4) + g00)));
339 color[2] += (float) ((int) ((((((((b11-b10) * dsfrac) >> 4) + b10)-((((b01-b00) * dsfrac) >> 4) + b00)) * dtfrac) >> 4) + ((((b01-b00) * dsfrac) >> 4) + b00)));
340 }
341 return true; // success
342 }
343
344 // go down back side
345 return RecursiveLightPointRGB (color, node->children[front >= 0], mid, end);
346 }
347 }
348
349
350 /*
351 * FIXME - check what the callers do, but I don't think this will check the
352 * light value of a bmodel below the point. Models could easily be standing on
353 * a func_plat or similar...
354 */
355
356 vec3_t lightcolor; // for colored lighting
357 extern int coloredlights;
358
R_LightPoint(vec3_t p)359 int R_LightPoint(vec3_t p)
360 {
361 vec3_t end;
362 int r;
363
364 if (!cl.worldmodel->lightdata){
365 lightcolor[0] = lightcolor[1] = lightcolor[2] = 255;
366 return 255;
367 }
368
369
370
371
372 if (coloredlights)
373 {
374 end[0] = p[0];
375 end[1] = p[1];
376 end[2] = p[2] - (8192 + 2);
377 lightcolor[0] = lightcolor[1] = lightcolor[2] = 0;
378 r = RecursiveLightPointRGB(lightcolor, cl.worldmodel->nodes, p, end);
379 return ((lightcolor[0] + lightcolor[1] + lightcolor[2]) * (1.0f / 3.0f));
380 }
381 else
382 {
383 end[0] = p[0];
384 end[1] = p[1];
385 end[2] = p[2] - (8192 + 2);
386
387
388 r = RecursiveLightPoint(cl.worldmodel->nodes, p, end);
389
390 if (r == -1)
391 r = 0;
392
393 if (r < r_refdef.ambientlight)
394 r = r_refdef.ambientlight;
395
396 return r;
397 }
398
399 }
400