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