Implemented r_ambient (mainly for sake of Nehahra's insanely dark maps).
[divverent/darkplaces.git] / r_light.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 // r_light.c
21
22 #include "quakedef.h"
23
24 cvar_t r_lightmodels = {"r_lightmodels", "1"};
25
26 void rlight_init()
27 {
28         Cvar_RegisterVariable(&r_lightmodels);
29 }
30
31 int     r_dlightframecount;
32
33 /*
34 ==================
35 R_AnimateLight
36 ==================
37 */
38 void R_AnimateLight (void)
39 {
40         int                     i,j,k;
41         
42 //
43 // light animations
44 // 'm' is normal light, 'a' is no light, 'z' is double bright
45         i = (int)(cl.time*10);
46         for (j=0 ; j<MAX_LIGHTSTYLES ; j++)
47         {
48                 if (!cl_lightstyle[j].length)
49                 {
50                         d_lightstylevalue[j] = 256;
51                         continue;
52                 }
53                 k = i % cl_lightstyle[j].length;
54                 k = cl_lightstyle[j].map[k] - 'a';
55                 k = k*22;
56                 d_lightstylevalue[j] = k;
57         }       
58 }
59
60 /*
61 =============================================================================
62
63 DYNAMIC LIGHTS
64
65 =============================================================================
66 */
67
68 /*
69 =============
70 R_MarkLights
71 =============
72 */
73 void R_MarkLights (vec3_t lightorigin, dlight_t *light, int bit, int bitindex, mnode_t *node)
74 {
75         float           dist, l, maxdist;
76         msurface_t      *surf;
77         int                     i, j, s, t;
78         vec3_t          impact;
79         
80 loc0:
81         if (node->contents < 0)
82                 return;
83
84         dist = DotProduct (lightorigin, node->plane->normal) - node->plane->dist;
85         
86         if (dist > light->radius)
87         {
88                 if (node->children[0]->contents >= 0) // LordHavoc: save some time by not pushing another stack frame
89                 {
90                         node = node->children[0];
91                         goto loc0;
92                 }
93                 return;
94         }
95         if (dist < -light->radius)
96         {
97                 if (node->children[1]->contents >= 0) // LordHavoc: save some time by not pushing another stack frame
98                 {
99                         node = node->children[1];
100                         goto loc0;
101                 }
102                 return;
103         }
104
105         maxdist = light->radius*light->radius;
106
107 // mark the polygons
108         surf = cl.worldmodel->surfaces + node->firstsurface;
109         for (i=0 ; i<node->numsurfaces ; i++, surf++)
110         {
111                 if (surf->flags & SURF_DRAWTURB) // water
112                 {
113                         if (surf->dlightframe != r_dlightframecount) // not dynamic until now
114                         {
115                                 surf->dlightbits[0] = surf->dlightbits[1] = surf->dlightbits[2] = surf->dlightbits[3] = surf->dlightbits[4] = surf->dlightbits[5] = surf->dlightbits[6] = surf->dlightbits[7] = 0;
116                                 surf->dlightframe = r_dlightframecount;
117                         }
118                         surf->dlightbits[bitindex] |= bit;
119                 }
120                 // LordHavoc: MAJOR dynamic light speedup here, eliminates marking of surfaces that are too far away from light, thus preventing unnecessary uploads
121                 else /*if (r_dynamicbothsides.value || (((surf->flags & SURF_PLANEBACK) && (dist < -BACKFACE_EPSILON)) || (!(surf->flags & SURF_PLANEBACK) && (dist > BACKFACE_EPSILON))))*/
122                 {
123                         // passed the plane side check
124                         for (j=0 ; j<3 ; j++)
125                                 impact[j] = lightorigin[j] - surf->plane->normal[j]*dist;
126
127                         // clamp center of light to corner and check brightness
128                         l = DotProduct (impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3] - surf->texturemins[0];
129                         s = l+0.5;if (s < 0) s = 0;else if (s > surf->extents[0]) s = surf->extents[0];
130                         s = l - s;
131                         l = DotProduct (impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3] - surf->texturemins[1];
132                         t = l+0.5;if (t < 0) t = 0;else if (t > surf->extents[1]) t = surf->extents[1];
133                         t = l - t;
134                         // compare to minimum light
135                         if ((s*s+t*t+dist*dist) < maxdist)
136                         {
137                                 if (surf->dlightframe != r_dlightframecount) // not dynamic until now
138                                 {
139                                         surf->dlightbits[0] = surf->dlightbits[1] = surf->dlightbits[2] = surf->dlightbits[3] = surf->dlightbits[4] = surf->dlightbits[5] = surf->dlightbits[6] = surf->dlightbits[7] = 0;
140                                         surf->dlightframe = r_dlightframecount;
141                                 }
142                                 surf->dlightbits[bitindex] |= bit;
143                         }
144                 }
145         }
146
147         if (node->children[0]->contents >= 0)
148         {
149                 if (node->children[1]->contents >= 0)
150                 {
151                         R_MarkLights (lightorigin, light, bit, bitindex, node->children[0]);
152                         node = node->children[1];
153                         goto loc0;
154                 }
155                 else
156                 {
157                         node = node->children[0];
158                         goto loc0;
159                 }
160         }
161         else if (node->children[1]->contents >= 0)
162         {
163                 node = node->children[1];
164                 goto loc0;
165         }
166 }
167
168
169 /*
170 =============
171 R_PushDlights
172 =============
173 */
174 void R_PushDlights (void)
175 {
176         int             i;
177         dlight_t        *l;
178
179         r_dlightframecount = r_framecount + 1;  // because the count hasn't advanced yet for this frame
180
181         if (/*gl_flashblend.value ||*/ !r_dynamic.value)
182                 return;
183
184         l = cl_dlights;
185
186         for (i=0 ; i<MAX_DLIGHTS ; i++, l++)
187         {
188                 if (l->die < cl.time || !l->radius)
189                         continue;
190                 R_MarkLights (l->origin, l, 1<<(i&31), i >> 5, cl.worldmodel->nodes );
191         }
192 }
193
194
195 /*
196 =============================================================================
197
198 LIGHT SAMPLING
199
200 =============================================================================
201 */
202
203 mplane_t                *lightplane;
204 vec3_t                  lightspot;
205
206 extern cvar_t r_ambient;
207
208 int RecursiveLightPoint (vec3_t color, mnode_t *node, vec3_t start, vec3_t end)
209 {
210         float           front, back, frac;
211         vec3_t          mid;
212
213 loc0:
214         if (node->contents < 0)
215                 return false;           // didn't hit anything
216         
217 // calculate mid point
218         front = PlaneDiff (start, node->plane);
219         back = PlaneDiff (end, node->plane);
220
221         // LordHavoc: optimized recursion
222         if ((back < 0) == (front < 0))
223 //              return RecursiveLightPoint (color, node->children[front < 0], start, end);
224         {
225                 node = node->children[front < 0];
226                 goto loc0;
227         }
228         
229         frac = front / (front-back);
230         mid[0] = start[0] + (end[0] - start[0])*frac;
231         mid[1] = start[1] + (end[1] - start[1])*frac;
232         mid[2] = start[2] + (end[2] - start[2])*frac;
233         
234 // go down front side
235         if (RecursiveLightPoint (color, node->children[front < 0], start, mid))
236                 return true;    // hit something
237         else
238         {
239                 int i, ds, dt;
240                 msurface_t *surf;
241         // check for impact on this node
242                 VectorCopy (mid, lightspot);
243                 lightplane = node->plane;
244
245                 surf = cl.worldmodel->surfaces + node->firstsurface;
246                 for (i = 0;i < node->numsurfaces;i++, surf++)
247                 {
248                         if (surf->flags & SURF_DRAWTILED)
249                                 continue;       // no lightmaps
250
251                         ds = (int) ((float) DotProduct (mid, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]);
252                         dt = (int) ((float) DotProduct (mid, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]);
253
254                         if (ds < surf->texturemins[0] || dt < surf->texturemins[1])
255                                 continue;
256                         
257                         ds -= surf->texturemins[0];
258                         dt -= surf->texturemins[1];
259                         
260                         if (ds > surf->extents[0] || dt > surf->extents[1])
261                                 continue;
262
263                         if (surf->samples)
264                         {
265                                 byte *lightmap;
266                                 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;
267                                 float scale;
268                                 line3 = ((surf->extents[0]>>4)+1)*3;
269
270                                 lightmap = surf->samples + ((dt>>4) * ((surf->extents[0]>>4)+1) + (ds>>4))*3; // LordHavoc: *3 for color
271
272                                 for (maps = 0;maps < MAXLIGHTMAPS && surf->styles[maps] != 255;maps++)
273                                 {
274                                         scale = (float) d_lightstylevalue[surf->styles[maps]] * 1.0 / 256.0;
275                                         r00 += (float) lightmap[      0] * scale;g00 += (float) lightmap[      1] * scale;b00 += (float) lightmap[2] * scale;
276                                         r01 += (float) lightmap[      3] * scale;g01 += (float) lightmap[      4] * scale;b01 += (float) lightmap[5] * scale;
277                                         r10 += (float) lightmap[line3+0] * scale;g10 += (float) lightmap[line3+1] * scale;b10 += (float) lightmap[line3+2] * scale;
278                                         r11 += (float) lightmap[line3+3] * scale;g11 += (float) lightmap[line3+4] * scale;b11 += (float) lightmap[line3+5] * scale;
279                                         lightmap += ((surf->extents[0]>>4)+1) * ((surf->extents[1]>>4)+1)*3; // LordHavoc: *3 for colored lighting
280                                 }
281
282                                 color[0] += (float) ((int) ((((((((r11-r10) * dsfrac) >> 4) + r10)-((((r01-r00) * dsfrac) >> 4) + r00)) * dtfrac) >> 4) + ((((r01-r00) * dsfrac) >> 4) + r00)));
283                                 color[1] += (float) ((int) ((((((((g11-g10) * dsfrac) >> 4) + g10)-((((g01-g00) * dsfrac) >> 4) + g00)) * dtfrac) >> 4) + ((((g01-g00) * dsfrac) >> 4) + g00)));
284                                 color[2] += (float) ((int) ((((((((b11-b10) * dsfrac) >> 4) + b10)-((((b01-b00) * dsfrac) >> 4) + b00)) * dtfrac) >> 4) + ((((b01-b00) * dsfrac) >> 4) + b00)));
285                         }
286                         return true; // success
287                 }
288
289         // go down back side
290                 return RecursiveLightPoint (color, node->children[front >= 0], mid, end);
291         }
292 }
293
294 void R_LightPoint (vec3_t color, vec3_t p)
295 {
296         vec3_t          end;
297         
298         if (r_fullbright.value || !cl.worldmodel->lightdata)
299         {
300                 color[0] = color[1] = color[2] = 255;
301                 return;
302         }
303         
304         end[0] = p[0];
305         end[1] = p[1];
306         end[2] = p[2] - 2048;
307
308         color[0] = color[1] = color[2] = r_ambient.value * 2.0f;
309         RecursiveLightPoint (color, cl.worldmodel->nodes, p, end);
310 }
311
312 // LordHavoc: R_DynamicLightPoint - acumulates the dynamic lighting
313 void R_DynamicLightPoint(vec3_t color, vec3_t org, int *dlightbits)
314 {
315         int             i;
316         vec3_t  dist;
317         float   brightness, r, f;
318
319         if (/*gl_flashblend.value ||*/ !r_dynamic.value || (!dlightbits[0] && !dlightbits[1] && !dlightbits[2] && !dlightbits[3] && !dlightbits[4] && !dlightbits[5] && !dlightbits[6] && !dlightbits[7]))
320                 return;
321
322         for (i=0 ; i<MAX_DLIGHTS ; i++)
323         {
324                 if (!((1 << (i&31)) & dlightbits[i>>5]))
325                         continue;
326                 if (cl_dlights[i].die < cl.time || !cl_dlights[i].radius)
327                         continue;
328                 VectorSubtract (org, cl_dlights[i].origin, dist);
329                 if ((f = DotProduct(dist, dist) + 64.0) < (r = cl_dlights[i].radius*cl_dlights[i].radius))
330                 {
331                         brightness = r * 16.0 / f;
332                         if (cl_dlights[i].dark)
333                                 brightness = -brightness;
334                         color[0] += brightness * cl_dlights[i].color[0];
335                         color[1] += brightness * cl_dlights[i].color[1];
336                         color[2] += brightness * cl_dlights[i].color[2];
337                 }
338         }
339 }
340
341 // same as above but no bitmask to check
342 void R_DynamicLightPointNoMask(vec3_t color, vec3_t org)
343 {
344         int             i;
345         vec3_t  dist;
346         float   brightness, r, f;
347
348         if (/*gl_flashblend.value ||*/ !r_dynamic.value)
349                 return;
350
351         for (i=0 ; i<MAX_DLIGHTS ; i++)
352         {
353                 if (cl_dlights[i].die < cl.time || !cl_dlights[i].radius)
354                         continue;
355                 VectorSubtract (org, cl_dlights[i].origin, dist);
356                 if ((f = DotProduct(dist, dist) + 64.0) < (r = cl_dlights[i].radius*cl_dlights[i].radius))
357                 {
358                         brightness = r * 16.0 / f;
359                         if (cl_dlights[i].dark)
360                                 brightness = -brightness;
361                         color[0] += brightness * cl_dlights[i].color[0];
362                         color[1] += brightness * cl_dlights[i].color[1];
363                         color[2] += brightness * cl_dlights[i].color[2];
364                 }
365         }
366 }
367
368 void R_CompleteLightPoint (vec3_t color, vec3_t p)
369 {
370         R_LightPoint(color, p);
371         R_DynamicLightPointNoMask(color, p);
372 }
373
374 extern float *aliasvert;
375 extern float *aliasvertnorm;
376 extern byte *aliasvertcolor;
377 extern vec_t shadecolor[];
378 extern float modelalpha;
379 extern qboolean lighthalf;
380 void R_LightModel(int numverts, vec3_t center)
381 {
382         int i, j, nearlights = 0;
383         vec3_t dist;
384         float t, t1, t2, t3, *avn;
385         byte r,g,b,a, *avc;
386         struct
387         {
388                 vec3_t color;
389                 vec3_t origin;
390         } nearlight[MAX_DLIGHTS];
391         if (!lighthalf)
392         {
393                 shadecolor[0] *= 2.0f;
394                 shadecolor[1] *= 2.0f;
395                 shadecolor[2] *= 2.0f;
396         }
397         avc = aliasvertcolor;
398         avn = aliasvertnorm;
399         a = (byte) bound((int) 0, (int) (modelalpha * 255.0f), (int) 255);
400         if (currententity->effects & EF_FULLBRIGHT)
401         {
402                 if (lighthalf)
403                 {
404                         r = (byte) ((float) (128.0f * currententity->colormod[0]));
405                         g = (byte) ((float) (128.0f * currententity->colormod[1]));
406                         b = (byte) ((float) (128.0f * currententity->colormod[2]));
407                 }
408                 else
409                 {
410                         r = (byte) ((float) (255.0f * currententity->colormod[0]));
411                         g = (byte) ((float) (255.0f * currententity->colormod[1]));
412                         b = (byte) ((float) (255.0f * currententity->colormod[2]));
413                 }
414                 for (i = 0;i < numverts;i++)
415                 {
416                         *avc++ = r;
417                         *avc++ = g;
418                         *avc++ = b;
419                         *avc++ = a;
420                 }
421                 return;
422         }
423         if (r_lightmodels.value)
424         {
425                 for (i = 0;i < MAX_DLIGHTS;i++)
426                 {
427                         if (cl_dlights[i].die < cl.time || !cl_dlights[i].radius)
428                                 continue;
429                         VectorSubtract (center, cl_dlights[i].origin, dist);
430                         if ((t2 = DotProduct(dist,dist) + 16.0f) + 64.0f < (t1 = cl_dlights[i].radius*cl_dlights[i].radius))
431                         {
432                                 VectorCopy(cl_dlights[i].origin, nearlight[nearlights].origin);
433                                 nearlight[nearlights].color[0] = cl_dlights[i].color[0] * cl_dlights[i].radius * cl_dlights[i].radius * 0.5f;
434                                 nearlight[nearlights].color[1] = cl_dlights[i].color[1] * cl_dlights[i].radius * cl_dlights[i].radius * 0.5f;
435                                 nearlight[nearlights].color[2] = cl_dlights[i].color[2] * cl_dlights[i].radius * cl_dlights[i].radius * 0.5f;
436                                 if (cl_dlights[i].dark)
437                                 {
438                                         nearlight[nearlights].color[0] = -nearlight[nearlights].color[0];
439                                         nearlight[nearlights].color[1] = -nearlight[nearlights].color[1];
440                                         nearlight[nearlights].color[2] = -nearlight[nearlights].color[2];
441                                 }
442                                 if (lighthalf)
443                                 {
444                                         nearlight[nearlights].color[0] *= 0.5f;
445                                         nearlight[nearlights].color[1] *= 0.5f;
446                                         nearlight[nearlights].color[2] *= 0.5f;
447                                 }
448                                 t1 = 1.0f / t2;
449                                 shadecolor[0] += nearlight[nearlights].color[0] * t1;
450                                 shadecolor[1] += nearlight[nearlights].color[1] * t1;
451                                 shadecolor[2] += nearlight[nearlights].color[2] * t1;
452                                 nearlight[nearlights].color[0] *= currententity->colormod[0];
453                                 nearlight[nearlights].color[1] *= currententity->colormod[1];
454                                 nearlight[nearlights].color[2] *= currententity->colormod[2];
455                                 nearlights++;
456                         }
457                 }
458         }
459         else
460         {
461                 for (i = 0;i < MAX_DLIGHTS;i++)
462                 {
463                         if (cl_dlights[i].die < cl.time || !cl_dlights[i].radius)
464                                 continue;
465                         VectorSubtract (center, cl_dlights[i].origin, dist);
466                         if ((t2 = DotProduct(dist,dist)) + 64.0f < (t1 = cl_dlights[i].radius*cl_dlights[i].radius))
467                         {
468                                 dist[0] = cl_dlights[i].color[0] * cl_dlights[i].radius * cl_dlights[i].radius * 0.5f;
469                                 dist[1] = cl_dlights[i].color[1] * cl_dlights[i].radius * cl_dlights[i].radius * 0.5f;
470                                 dist[2] = cl_dlights[i].color[2] * cl_dlights[i].radius * cl_dlights[i].radius * 0.5f;
471                                 if (cl_dlights[i].dark)
472                                 {
473                                         dist[0] = -dist[0];
474                                         dist[1] = -dist[1];
475                                         dist[2] = -dist[2];
476                                 }
477                                 if (lighthalf)
478                                 {
479                                         dist[0] *= 0.5f;
480                                         dist[1] *= 0.5f;
481                                         dist[2] *= 0.5f;
482                                 }
483                                 t1 = 1.5f / t2;
484                                 shadecolor[0] += dist[0] * t1;
485                                 shadecolor[1] += dist[1] * t1;
486                                 shadecolor[2] += dist[2] * t1;
487                         }
488                 }
489         }
490         shadecolor[0] *= currententity->colormod[0];
491         shadecolor[1] *= currententity->colormod[1];
492         shadecolor[2] *= currententity->colormod[2];
493         t1 = bound(0, shadecolor[0], 255);r = (byte) t1;
494         t1 = bound(0, shadecolor[1], 255);g = (byte) t1;
495         t1 = bound(0, shadecolor[2], 255);b = (byte) t1;
496         if (nearlights)
497         {
498                 int temp;
499                 vec3_t v;
500                 float *av;
501                 av = aliasvert;
502                 if (nearlights == 1)
503                 {
504                         for (i = 0;i < numverts;i++)
505                         {
506                                 VectorSubtract(nearlight[0].origin, av, v);
507                                 t = DotProduct(avn,v);
508                                 if (t > 0)
509                                 {
510                                         t /= DotProduct(v,v);
511                                         temp = (int) ((float) (shadecolor[0] + nearlight[0].color[0] * t));if (temp < 0) temp = 0;else if (temp > 255) temp = 255;*avc++ = temp;
512                                         temp = (int) ((float) (shadecolor[1] + nearlight[0].color[1] * t));if (temp < 0) temp = 0;else if (temp > 255) temp = 255;*avc++ = temp;
513                                         temp = (int) ((float) (shadecolor[2] + nearlight[0].color[2] * t));if (temp < 0) temp = 0;else if (temp > 255) temp = 255;*avc++ = temp;
514                                 }
515                                 else
516                                 {
517                                         *avc++ = r;
518                                         *avc++ = g;
519                                         *avc++ = b;
520                                 }
521                                 *avc++ = a;
522                                 av+=3;
523                                 avn+=3;
524                         }
525                 }
526                 else
527                 {
528                         int i1, i2, i3;
529                         for (i = 0;i < numverts;i++)
530                         {
531                                 t1 = shadecolor[0];
532                                 t2 = shadecolor[1];
533                                 t3 = shadecolor[2];
534                                 for (j = 0;j < nearlights;j++)
535                                 {
536                                         VectorSubtract(nearlight[j].origin, av, v);
537                                         t = DotProduct(avn,v);
538                                         if (t > 0)
539                                         {
540                                                 t /= DotProduct(v,v);
541                                                 t1 += nearlight[j].color[0] * t;
542                                                 t2 += nearlight[j].color[1] * t;
543                                                 t3 += nearlight[j].color[2] * t;
544                                         }
545                                 }
546                                 i1 = t1;if (i1 < 0) i1 = 0;else if (i1 > 255) i1 = 255;
547                                 i2 = t2;if (i2 < 0) i2 = 0;else if (i2 > 255) i2 = 255;
548                                 i3 = t3;if (i3 < 0) i3 = 0;else if (i3 > 255) i3 = 255;
549                                 *avc++ = i1;
550                                 *avc++ = i2;
551                                 *avc++ = i3;
552                                 *avc++ = a;
553                         }
554                 }
555         }
556         else
557         {
558                 for (i = 0;i < numverts;i++)
559                 {
560                         *avc++ = r;
561                         *avc++ = g;
562                         *avc++ = b;
563                         *avc++ = a;
564                 }
565         }
566 }