clean up, r_farclip cvar, lit particles (optional), stuff
[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 int RecursiveLightPoint (vec3_t color, mnode_t *node, vec3_t start, vec3_t end)
207 {
208         float           front, back, frac;
209         vec3_t          mid;
210
211 loc0:
212         if (node->contents < 0)
213                 return false;           // didn't hit anything
214         
215 // calculate mid point
216         front = PlaneDiff (start, node->plane);
217         back = PlaneDiff (end, node->plane);
218
219         // LordHavoc: optimized recursion
220         if ((back < 0) == (front < 0))
221 //              return RecursiveLightPoint (color, node->children[front < 0], start, end);
222         {
223                 node = node->children[front < 0];
224                 goto loc0;
225         }
226         
227         frac = front / (front-back);
228         mid[0] = start[0] + (end[0] - start[0])*frac;
229         mid[1] = start[1] + (end[1] - start[1])*frac;
230         mid[2] = start[2] + (end[2] - start[2])*frac;
231         
232 // go down front side
233         if (RecursiveLightPoint (color, node->children[front < 0], start, mid))
234                 return true;    // hit something
235         else
236         {
237                 int i, ds, dt;
238                 msurface_t *surf;
239         // check for impact on this node
240                 VectorCopy (mid, lightspot);
241                 lightplane = node->plane;
242
243                 surf = cl.worldmodel->surfaces + node->firstsurface;
244                 for (i = 0;i < node->numsurfaces;i++, surf++)
245                 {
246                         if (surf->flags & SURF_DRAWTILED)
247                                 continue;       // no lightmaps
248
249                         ds = (int) ((float) DotProduct (mid, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]);
250                         dt = (int) ((float) DotProduct (mid, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]);
251
252                         if (ds < surf->texturemins[0] || dt < surf->texturemins[1])
253                                 continue;
254                         
255                         ds -= surf->texturemins[0];
256                         dt -= surf->texturemins[1];
257                         
258                         if (ds > surf->extents[0] || dt > surf->extents[1])
259                                 continue;
260
261                         if (surf->samples)
262                         {
263                                 byte *lightmap;
264                                 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;
265                                 float scale;
266                                 line3 = ((surf->extents[0]>>4)+1)*3;
267
268                                 lightmap = surf->samples + ((dt>>4) * ((surf->extents[0]>>4)+1) + (ds>>4))*3; // LordHavoc: *3 for color
269
270                                 for (maps = 0;maps < MAXLIGHTMAPS && surf->styles[maps] != 255;maps++)
271                                 {
272                                         scale = (float) d_lightstylevalue[surf->styles[maps]] * 1.0 / 256.0;
273                                         r00 += (float) lightmap[      0] * scale;g00 += (float) lightmap[      1] * scale;b00 += (float) lightmap[2] * scale;
274                                         r01 += (float) lightmap[      3] * scale;g01 += (float) lightmap[      4] * scale;b01 += (float) lightmap[5] * scale;
275                                         r10 += (float) lightmap[line3+0] * scale;g10 += (float) lightmap[line3+1] * scale;b10 += (float) lightmap[line3+2] * scale;
276                                         r11 += (float) lightmap[line3+3] * scale;g11 += (float) lightmap[line3+4] * scale;b11 += (float) lightmap[line3+5] * scale;
277                                         lightmap += ((surf->extents[0]>>4)+1) * ((surf->extents[1]>>4)+1)*3; // LordHavoc: *3 for colored lighting
278                                 }
279
280                                 color[0] += (float) ((int) ((((((((r11-r10) * dsfrac) >> 4) + r10)-((((r01-r00) * dsfrac) >> 4) + r00)) * dtfrac) >> 4) + ((((r01-r00) * dsfrac) >> 4) + r00)));
281                                 color[1] += (float) ((int) ((((((((g11-g10) * dsfrac) >> 4) + g10)-((((g01-g00) * dsfrac) >> 4) + g00)) * dtfrac) >> 4) + ((((g01-g00) * dsfrac) >> 4) + g00)));
282                                 color[2] += (float) ((int) ((((((((b11-b10) * dsfrac) >> 4) + b10)-((((b01-b00) * dsfrac) >> 4) + b00)) * dtfrac) >> 4) + ((((b01-b00) * dsfrac) >> 4) + b00)));
283                         }
284                         return true; // success
285                 }
286
287         // go down back side
288                 return RecursiveLightPoint (color, node->children[front >= 0], mid, end);
289         }
290 }
291
292 void R_LightPoint (vec3_t color, vec3_t p)
293 {
294         vec3_t          end;
295         
296         if (r_fullbright.value || !cl.worldmodel->lightdata)
297         {
298                 color[0] = color[1] = color[2] = 255;
299                 return;
300         }
301         
302         end[0] = p[0];
303         end[1] = p[1];
304         end[2] = p[2] - 2048;
305
306         color[0] = color[1] = color[2] = 0;
307         RecursiveLightPoint (color, cl.worldmodel->nodes, p, end);
308 }
309
310 // LordHavoc: R_DynamicLightPoint - acumulates the dynamic lighting
311 void R_DynamicLightPoint(vec3_t color, vec3_t org, int *dlightbits)
312 {
313         int             i;
314         vec3_t  dist;
315         float   brightness, r, f;
316
317         if (/*gl_flashblend.value ||*/ !r_dynamic.value || (!dlightbits[0] && !dlightbits[1] && !dlightbits[2] && !dlightbits[3] && !dlightbits[4] && !dlightbits[5] && !dlightbits[6] && !dlightbits[7]))
318                 return;
319
320         for (i=0 ; i<MAX_DLIGHTS ; i++)
321         {
322                 if (!((1 << (i&31)) & dlightbits[i>>5]))
323                         continue;
324                 if (cl_dlights[i].die < cl.time || !cl_dlights[i].radius)
325                         continue;
326                 VectorSubtract (org, cl_dlights[i].origin, dist);
327                 if ((f = DotProduct(dist, dist) + 64.0) < (r = cl_dlights[i].radius*cl_dlights[i].radius))
328                 {
329                         brightness = r * 16.0 / f;
330                         if (cl_dlights[i].dark)
331                                 brightness = -brightness;
332                         color[0] += brightness * cl_dlights[i].color[0];
333                         color[1] += brightness * cl_dlights[i].color[1];
334                         color[2] += brightness * cl_dlights[i].color[2];
335                 }
336         }
337 }
338
339 // same as above but no bitmask to check
340 void R_DynamicLightPointNoMask(vec3_t color, vec3_t org)
341 {
342         int             i;
343         vec3_t  dist;
344         float   brightness, r, f;
345
346         if (/*gl_flashblend.value ||*/ !r_dynamic.value)
347                 return;
348
349         for (i=0 ; i<MAX_DLIGHTS ; i++)
350         {
351                 if (cl_dlights[i].die < cl.time || !cl_dlights[i].radius)
352                         continue;
353                 VectorSubtract (org, cl_dlights[i].origin, dist);
354                 if ((f = DotProduct(dist, dist) + 64.0) < (r = cl_dlights[i].radius*cl_dlights[i].radius))
355                 {
356                         brightness = r * 16.0 / f;
357                         if (cl_dlights[i].dark)
358                                 brightness = -brightness;
359                         color[0] += brightness * cl_dlights[i].color[0];
360                         color[1] += brightness * cl_dlights[i].color[1];
361                         color[2] += brightness * cl_dlights[i].color[2];
362                 }
363         }
364 }
365
366 void R_CompleteLightPoint (vec3_t color, vec3_t p)
367 {
368         R_LightPoint(color, p);
369         R_DynamicLightPointNoMask(color, p);
370 }
371
372 extern float *aliasvert;
373 extern float *aliasvertnorm;
374 extern byte *aliasvertcolor;
375 extern vec_t shadecolor[];
376 extern float modelalpha;
377 extern qboolean lighthalf;
378 void R_LightModel(int numverts, vec3_t center)
379 {
380         int i, j, nearlights = 0;
381         vec3_t dist;
382         float t, t1, t2, t3, *avn;
383         byte r,g,b,a, *avc;
384         struct
385         {
386                 vec3_t color;
387                 vec3_t origin;
388         } nearlight[MAX_DLIGHTS];
389         if (!lighthalf)
390         {
391                 shadecolor[0] *= 2.0f;
392                 shadecolor[1] *= 2.0f;
393                 shadecolor[2] *= 2.0f;
394         }
395         avc = aliasvertcolor;
396         avn = aliasvertnorm;
397         a = (byte) bound((int) 0, (int) (modelalpha * 255.0f), (int) 255);
398         if (currententity->effects & EF_FULLBRIGHT)
399         {
400                 if (lighthalf)
401                 {
402                         r = (byte) ((float) (128.0f * currententity->colormod[0]));
403                         g = (byte) ((float) (128.0f * currententity->colormod[1]));
404                         b = (byte) ((float) (128.0f * currententity->colormod[2]));
405                 }
406                 else
407                 {
408                         r = (byte) ((float) (255.0f * currententity->colormod[0]));
409                         g = (byte) ((float) (255.0f * currententity->colormod[1]));
410                         b = (byte) ((float) (255.0f * currententity->colormod[2]));
411                 }
412                 for (i = 0;i < numverts;i++)
413                 {
414                         *avc++ = r;
415                         *avc++ = g;
416                         *avc++ = b;
417                         *avc++ = a;
418                 }
419                 return;
420         }
421         if (r_lightmodels.value)
422         {
423                 for (i = 0;i < MAX_DLIGHTS;i++)
424                 {
425                         if (cl_dlights[i].die < cl.time || !cl_dlights[i].radius)
426                                 continue;
427                         VectorSubtract (center, cl_dlights[i].origin, dist);
428                         if ((t2 = DotProduct(dist,dist) + 16.0f) + 64.0f < (t1 = cl_dlights[i].radius*cl_dlights[i].radius))
429                         {
430                                 VectorCopy(cl_dlights[i].origin, nearlight[nearlights].origin);
431                                 nearlight[nearlights].color[0] = cl_dlights[i].color[0] * cl_dlights[i].radius * cl_dlights[i].radius * 0.5f;
432                                 nearlight[nearlights].color[1] = cl_dlights[i].color[1] * cl_dlights[i].radius * cl_dlights[i].radius * 0.5f;
433                                 nearlight[nearlights].color[2] = cl_dlights[i].color[2] * cl_dlights[i].radius * cl_dlights[i].radius * 0.5f;
434                                 if (cl_dlights[i].dark)
435                                 {
436                                         nearlight[nearlights].color[0] = -nearlight[nearlights].color[0];
437                                         nearlight[nearlights].color[1] = -nearlight[nearlights].color[1];
438                                         nearlight[nearlights].color[2] = -nearlight[nearlights].color[2];
439                                 }
440                                 if (lighthalf)
441                                 {
442                                         nearlight[nearlights].color[0] *= 0.5f;
443                                         nearlight[nearlights].color[1] *= 0.5f;
444                                         nearlight[nearlights].color[2] *= 0.5f;
445                                 }
446                                 t1 = 1.0f / t2;
447                                 shadecolor[0] += nearlight[nearlights].color[0] * t1;
448                                 shadecolor[1] += nearlight[nearlights].color[1] * t1;
449                                 shadecolor[2] += nearlight[nearlights].color[2] * t1;
450                                 nearlight[nearlights].color[0] *= currententity->colormod[0];
451                                 nearlight[nearlights].color[1] *= currententity->colormod[1];
452                                 nearlight[nearlights].color[2] *= currententity->colormod[2];
453                                 nearlights++;
454                         }
455                 }
456         }
457         else
458         {
459                 for (i = 0;i < MAX_DLIGHTS;i++)
460                 {
461                         if (cl_dlights[i].die < cl.time || !cl_dlights[i].radius)
462                                 continue;
463                         VectorSubtract (center, cl_dlights[i].origin, dist);
464                         if ((t2 = DotProduct(dist,dist)) + 64.0f < (t1 = cl_dlights[i].radius*cl_dlights[i].radius))
465                         {
466                                 dist[0] = cl_dlights[i].color[0] * cl_dlights[i].radius * cl_dlights[i].radius * 0.5f;
467                                 dist[1] = cl_dlights[i].color[1] * cl_dlights[i].radius * cl_dlights[i].radius * 0.5f;
468                                 dist[2] = cl_dlights[i].color[2] * cl_dlights[i].radius * cl_dlights[i].radius * 0.5f;
469                                 if (cl_dlights[i].dark)
470                                 {
471                                         dist[0] = -dist[0];
472                                         dist[1] = -dist[1];
473                                         dist[2] = -dist[2];
474                                 }
475                                 if (lighthalf)
476                                 {
477                                         dist[0] *= 0.5f;
478                                         dist[1] *= 0.5f;
479                                         dist[2] *= 0.5f;
480                                 }
481                                 t1 = 1.5f / t2;
482                                 shadecolor[0] += dist[0] * t1;
483                                 shadecolor[1] += dist[1] * t1;
484                                 shadecolor[2] += dist[2] * t1;
485                         }
486                 }
487         }
488         shadecolor[0] *= currententity->colormod[0];
489         shadecolor[1] *= currententity->colormod[1];
490         shadecolor[2] *= currententity->colormod[2];
491         t1 = bound(0, shadecolor[0], 255);r = (byte) t1;
492         t1 = bound(0, shadecolor[1], 255);g = (byte) t1;
493         t1 = bound(0, shadecolor[2], 255);b = (byte) t1;
494         if (nearlights)
495         {
496                 int temp;
497                 vec3_t v;
498                 float *av;
499                 av = aliasvert;
500                 if (nearlights == 1)
501                 {
502                         for (i = 0;i < numverts;i++)
503                         {
504                                 VectorSubtract(nearlight[0].origin, av, v);
505                                 t = DotProduct(avn,v);
506                                 if (t > 0)
507                                 {
508                                         t /= DotProduct(v,v);
509                                         temp = (int) ((float) (shadecolor[0] + nearlight[0].color[0] * t));if (temp < 0) temp = 0;else if (temp > 255) temp = 255;*avc++ = temp;
510                                         temp = (int) ((float) (shadecolor[1] + nearlight[0].color[1] * t));if (temp < 0) temp = 0;else if (temp > 255) temp = 255;*avc++ = temp;
511                                         temp = (int) ((float) (shadecolor[2] + nearlight[0].color[2] * t));if (temp < 0) temp = 0;else if (temp > 255) temp = 255;*avc++ = temp;
512                                 }
513                                 else
514                                 {
515                                         *avc++ = r;
516                                         *avc++ = g;
517                                         *avc++ = b;
518                                 }
519                                 *avc++ = a;
520                                 av+=3;
521                                 avn+=3;
522                         }
523                 }
524                 else
525                 {
526                         int i1, i2, i3;
527                         for (i = 0;i < numverts;i++)
528                         {
529                                 t1 = shadecolor[0];
530                                 t2 = shadecolor[1];
531                                 t3 = shadecolor[2];
532                                 for (j = 0;j < nearlights;j++)
533                                 {
534                                         VectorSubtract(nearlight[j].origin, av, v);
535                                         t = DotProduct(avn,v);
536                                         if (t > 0)
537                                         {
538                                                 t /= DotProduct(v,v);
539                                                 t1 += nearlight[j].color[0] * t;
540                                                 t2 += nearlight[j].color[1] * t;
541                                                 t3 += nearlight[j].color[2] * t;
542                                         }
543                                 }
544                                 i1 = t1;if (i1 < 0) i1 = 0;else if (i1 > 255) i1 = 255;
545                                 i2 = t2;if (i2 < 0) i2 = 0;else if (i2 > 255) i2 = 255;
546                                 i3 = t3;if (i3 < 0) i3 = 0;else if (i3 > 255) i3 = 255;
547                                 *avc++ = i1;
548                                 *avc++ = i2;
549                                 *avc++ = i3;
550                                 *avc++ = a;
551                         }
552                 }
553         }
554         else
555         {
556                 for (i = 0;i < numverts;i++)
557                 {
558                         *avc++ = r;
559                         *avc++ = g;
560                         *avc++ = b;
561                         *avc++ = a;
562                 }
563         }
564 }