split r_shadow_realtime into r_shadow_realtime_world (which requires stencil) and...
[xonotic/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 #include "cl_collision.h"
24 #include "r_shadow.h"
25
26 rdlight_t r_dlight[MAX_DLIGHTS];
27 int r_numdlights = 0;
28
29 cvar_t r_modellights = {CVAR_SAVE, "r_modellights", "4"};
30 cvar_t r_vismarklights = {0, "r_vismarklights", "1"};
31 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1"};
32 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "1"};
33
34 static rtexture_t *lightcorona;
35 static rtexturepool_t *lighttexturepool;
36
37 void r_light_start(void)
38 {
39         float dx, dy;
40         int x, y, a;
41         qbyte pixels[32][32][4];
42         lighttexturepool = R_AllocTexturePool();
43         for (y = 0;y < 32;y++)
44         {
45                 dy = (y - 15.5f) * (1.0f / 16.0f);
46                 for (x = 0;x < 32;x++)
47                 {
48                         dx = (x - 15.5f) * (1.0f / 16.0f);
49                         a = ((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2));
50                         a = bound(0, a, 255);
51                         pixels[y][x][0] = a;
52                         pixels[y][x][1] = a;
53                         pixels[y][x][2] = a;
54                         pixels[y][x][3] = 255;
55                 }
56         }
57         lightcorona = R_LoadTexture2D(lighttexturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
58 }
59
60 void r_light_shutdown(void)
61 {
62         lighttexturepool = NULL;
63         lightcorona = NULL;
64 }
65
66 void r_light_newmap(void)
67 {
68         int i;
69         for (i = 0;i < 256;i++)
70                 d_lightstylevalue[i] = 264;             // normal light value
71 }
72
73 void R_Light_Init(void)
74 {
75         Cvar_RegisterVariable(&r_modellights);
76         Cvar_RegisterVariable(&r_vismarklights);
77         Cvar_RegisterVariable(&r_coronas);
78         Cvar_RegisterVariable(&gl_flashblend);
79         R_RegisterModule("R_Light", r_light_start, r_light_shutdown, r_light_newmap);
80 }
81
82 /*
83 ==================
84 R_AnimateLight
85 ==================
86 */
87 void R_AnimateLight (void)
88 {
89         int i, j, k;
90
91 //
92 // light animations
93 // 'm' is normal light, 'a' is no light, 'z' is double bright
94         i = (int)(cl.time * 10);
95         for (j = 0;j < MAX_LIGHTSTYLES;j++)
96         {
97                 if (!cl_lightstyle || !cl_lightstyle[j].length)
98                 {
99                         d_lightstylevalue[j] = 256;
100                         continue;
101                 }
102                 k = i % cl_lightstyle[j].length;
103                 k = cl_lightstyle[j].map[k] - 'a';
104                 k = k*22;
105                 d_lightstylevalue[j] = k;
106         }
107 }
108
109
110 void R_BuildLightList(void)
111 {
112         int i;
113         dlight_t *cd;
114         rdlight_t *rd;
115
116         r_numdlights = 0;
117         c_dlights = 0;
118
119         if (!r_dynamic.integer || !cl_dlights)
120                 return;
121
122         for (i = 0;i < MAX_DLIGHTS;i++)
123         {
124                 cd = cl_dlights + i;
125                 if (cd->radius <= 0)
126                         continue;
127                 rd = &r_dlight[r_numdlights++];
128                 VectorCopy(cd->origin, rd->origin);
129                 VectorScale(cd->color, cd->radius * 64.0f, rd->light);
130                 rd->cullradius2 = DotProduct(rd->light, rd->light) * (0.25f / (64.0f * 64.0f)) + 4096.0f;
131                 // clamp radius to avoid overflowing division table in lightmap code
132                 if (rd->cullradius2 > (2048.0f * 2048.0f))
133                         rd->cullradius2 = (2048.0f * 2048.0f);
134                 rd->cullradius = sqrt(rd->cullradius2);
135                 rd->subtract = 1.0f / rd->cullradius2;
136                 rd->ent = cd->ent;
137                 c_dlights++; // count every dlight in use
138         }
139 }
140
141 void R_DrawCoronas(void)
142 {
143         int i;
144         rmeshstate_t m;
145         float scale, viewdist, diff[3], dist;
146         rdlight_t *rd;
147         if (!r_coronas.integer)
148                 return;
149         memset(&m, 0, sizeof(m));
150         m.blendfunc1 = GL_ONE;
151         m.blendfunc2 = GL_ONE;
152         m.depthdisable = true; // magic
153         m.tex[0] = R_GetTexture(lightcorona);
154         R_Mesh_Matrix(&r_identitymatrix);
155         R_Mesh_State(&m);
156         viewdist = DotProduct(r_origin, vpn);
157         for (i = 0;i < r_numdlights;i++)
158         {
159                 rd = r_dlight + i;
160                 dist = (DotProduct(rd->origin, vpn) - viewdist);
161                 if (dist >= 24.0f && CL_TraceLine(rd->origin, r_origin, NULL, NULL, 0, true, NULL) == 1)
162                 {
163                         scale = r_colorscale * (1.0f / 131072.0f);
164                         if (gl_flashblend.integer)
165                                 scale *= 4.0f;
166                         if (fogenabled)
167                         {
168                                 VectorSubtract(rd->origin, r_origin, diff);
169                                 scale *= 1 - exp(fogdensity/DotProduct(diff,diff));
170                         }
171                         GL_Color(rd->light[0] * scale, rd->light[1] * scale, rd->light[2] * scale, 1);
172                         scale = rd->cullradius * 0.25f;
173                         if (gl_flashblend.integer)
174                                 scale *= 2.0f;
175                         R_DrawSpriteMesh(rd->origin, vright, vup, scale, -scale, -scale, scale);
176                 }
177         }
178 }
179
180 /*
181 =============================================================================
182
183 DYNAMIC LIGHTS
184
185 =============================================================================
186 */
187
188 /*
189 =============
190 R_MarkLights
191 =============
192 */
193 static void R_OldMarkLights (entity_render_t *ent, vec3_t lightorigin, rdlight_t *rd, int bit, int bitindex, mnode_t *node)
194 {
195         float ndist, maxdist;
196         msurface_t *surf;
197         int i, *surfacepvsframes;
198         int d, impacts, impactt;
199         float dist, dist2, impact[3];
200
201         if (!r_dynamic.integer)
202                 return;
203
204         // for comparisons to minimum acceptable light
205         maxdist = rd->cullradius2;
206
207         surfacepvsframes = ent->model->surfacepvsframes;
208 loc0:
209         if (node->contents < 0)
210                 return;
211
212         ndist = PlaneDiff(lightorigin, node->plane);
213
214         if (ndist > rd->cullradius)
215         {
216                 node = node->children[0];
217                 goto loc0;
218         }
219         if (ndist < -rd->cullradius)
220         {
221                 node = node->children[1];
222                 goto loc0;
223         }
224
225 // mark the polygons
226         surf = ent->model->surfaces + node->firstsurface;
227         for (i = 0;i < node->numsurfaces;i++, surf++)
228         {
229                 if (surfacepvsframes[surf->number] != ent->model->pvsframecount)
230                         continue;
231                 dist = ndist;
232                 if (surf->flags & SURF_PLANEBACK)
233                         dist = -dist;
234
235                 if (dist < -0.25f && !(surf->flags & SURF_LIGHTBOTHSIDES))
236                         continue;
237
238                 dist2 = dist * dist;
239                 if (dist2 >= maxdist)
240                         continue;
241
242                 if (node->plane->type < 3)
243                 {
244                         VectorCopy(lightorigin, impact);
245                         impact[node->plane->type] -= dist;
246                 }
247                 else
248                 {
249                         impact[0] = lightorigin[0] - surf->plane->normal[0] * dist;
250                         impact[1] = lightorigin[1] - surf->plane->normal[1] * dist;
251                         impact[2] = lightorigin[2] - surf->plane->normal[2] * dist;
252                 }
253
254                 impacts = DotProduct (impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3] - surf->texturemins[0];
255
256                 d = bound(0, impacts, surf->extents[0] + 16) - impacts;
257                 dist2 += d * d;
258                 if (dist2 > maxdist)
259                         continue;
260
261                 impactt = DotProduct (impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3] - surf->texturemins[1];
262
263                 d = bound(0, impactt, surf->extents[1] + 16) - impactt;
264                 dist2 += d * d;
265                 if (dist2 > maxdist)
266                         continue;
267
268                 if (surf->dlightframe != r_framecount) // not dynamic until now
269                 {
270                         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;
271                         surf->dlightframe = r_framecount;
272                         if (r_dlightmap.integer)
273                                 surf->cached_dlight = true;
274                 }
275                 surf->dlightbits[bitindex] |= bit;
276         }
277
278         if (node->children[0]->contents >= 0)
279         {
280                 if (node->children[1]->contents >= 0)
281                 {
282                         R_OldMarkLights (ent, lightorigin, rd, bit, bitindex, node->children[0]);
283                         node = node->children[1];
284                         goto loc0;
285                 }
286                 else
287                 {
288                         node = node->children[0];
289                         goto loc0;
290                 }
291         }
292         else if (node->children[1]->contents >= 0)
293         {
294                 node = node->children[1];
295                 goto loc0;
296         }
297 }
298
299
300 static void R_VisMarkLights (entity_render_t *ent, rdlight_t *rd, int bit, int bitindex)
301 {
302         static int lightframe = 0;
303         mleaf_t *pvsleaf;
304         vec3_t lightorigin;
305         model_t *model;
306         int i, k, m, c, leafnum, *surfacepvsframes, *mark;
307         msurface_t *surf;
308         mleaf_t *leaf;
309         qbyte *in;
310         int row;
311         float low[3], high[3], dist, maxdist;
312
313         if (!r_dynamic.integer)
314                 return;
315
316         Matrix4x4_Transform(&ent->inversematrix, rd->origin, lightorigin);
317
318         model = ent->model;
319         pvsleaf = Mod_PointInLeaf (lightorigin, model);
320         if (pvsleaf == NULL)
321                 return;
322
323         in = pvsleaf->compressed_vis;
324         if (!r_vismarklights.integer || !in)
325         {
326                 // told not to use pvs, or there's no pvs to use
327                 R_OldMarkLights(ent, lightorigin, rd, bit, bitindex, model->nodes + model->hulls[0].firstclipnode);
328                 return;
329         }
330
331         lightframe++;
332
333         low[0] = lightorigin[0] - rd->cullradius;low[1] = lightorigin[1] - rd->cullradius;low[2] = lightorigin[2] - rd->cullradius;
334         high[0] = lightorigin[0] + rd->cullradius;high[1] = lightorigin[1] + rd->cullradius;high[2] = lightorigin[2] + rd->cullradius;
335
336         // for comparisons to minimum acceptable light
337         maxdist = rd->cullradius2;
338
339         row = (model->numleafs+7)>>3;
340         surfacepvsframes = model->surfacepvsframes;
341
342         k = 0;
343         while (k < row)
344         {
345                 c = *in++;
346                 if (c)
347                 {
348                         for (i = 0;i < 8;i++)
349                         {
350                                 if (c & (1<<i))
351                                 {
352                                         // warning to the clumsy: numleafs is one less than it should be, it only counts leafs with vis bits (skips leaf 0)
353                                         leafnum = (k << 3)+i+1;
354                                         if (leafnum > model->numleafs)
355                                                 return;
356                                         leaf = &model->leafs[leafnum];
357                                         if (leaf->mins[0] > high[0] || leaf->maxs[0] < low[0]
358                                          || leaf->mins[1] > high[1] || leaf->maxs[1] < low[1]
359                                          || leaf->mins[2] > high[2] || leaf->maxs[2] < low[2])
360                                                 continue;
361                                         if ((m = leaf->nummarksurfaces))
362                                         {
363                                                 mark = leaf->firstmarksurface;
364                                                 do
365                                                 {
366                                                         surf = model->surfaces + *mark++;
367                                                         // if not visible in current frame, or already marked because it was in another leaf we passed, skip
368                                                         if (surf->lightframe == lightframe)
369                                                                 continue;
370                                                         surf->lightframe = lightframe;
371                                                         if (surfacepvsframes[surf->number] != model->pvsframecount)
372                                                                 continue;
373                                                         dist = PlaneDiff(lightorigin, surf->plane);
374                                                         if (surf->flags & SURF_PLANEBACK)
375                                                                 dist = -dist;
376                                                         // LordHavoc: make sure it is infront of the surface and not too far away
377                                                         if (dist < rd->cullradius && (dist > -0.25f || ((surf->flags & SURF_LIGHTBOTHSIDES) && dist > -rd->cullradius)))
378                                                         {
379                                                                 int d;
380                                                                 int impacts, impactt;
381                                                                 float dist2, impact[3];
382
383                                                                 dist2 = dist * dist;
384
385                                                                 if (surf->plane->type < 3)
386                                                                 {
387                                                                         VectorCopy(lightorigin, impact);
388                                                                         impact[surf->plane->type] -= dist;
389                                                                 }
390                                                                 else
391                                                                 {
392                                                                         impact[0] = lightorigin[0] - surf->plane->normal[0] * dist;
393                                                                         impact[1] = lightorigin[1] - surf->plane->normal[1] * dist;
394                                                                         impact[2] = lightorigin[2] - surf->plane->normal[2] * dist;
395                                                                 }
396
397                                                                 impacts = DotProduct (impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3] - surf->texturemins[0];
398                                                                 d = bound(0, impacts, surf->extents[0] + 16) - impacts;
399                                                                 dist2 += d * d;
400                                                                 if (dist2 > maxdist)
401                                                                         continue;
402
403                                                                 impactt = DotProduct (impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3] - surf->texturemins[1];
404                                                                 d = bound(0, impactt, surf->extents[1] + 16) - impactt;
405                                                                 dist2 += d * d;
406                                                                 if (dist2 > maxdist)
407                                                                         continue;
408
409                                                                 if (surf->dlightframe != r_framecount) // not dynamic until now
410                                                                 {
411                                                                         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;
412                                                                         surf->dlightframe = r_framecount;
413                                                                         if (r_dlightmap.integer)
414                                                                                 surf->cached_dlight = true;
415                                                                 }
416                                                                 surf->dlightbits[bitindex] |= bit;
417                                                         }
418                                                 }
419                                                 while (--m);
420                                         }
421                                 }
422                         }
423                         k++;
424                         continue;
425                 }
426
427                 k += *in++;
428         }
429 }
430
431 void R_MarkLights(entity_render_t *ent)
432 {
433         int i;
434         if (!gl_flashblend.integer)
435                 for (i = 0;i < r_numdlights;i++)
436                         R_VisMarkLights (ent, r_dlight + i, 1 << (i & 31), i >> 5);
437 }
438
439 /*
440 =============================================================================
441
442 LIGHT SAMPLING
443
444 =============================================================================
445 */
446
447 static int RecursiveLightPoint (vec3_t color, const mnode_t *node, float x, float y, float startz, float endz)
448 {
449         int side, distz = endz - startz;
450         float front, back;
451         float mid;
452
453 loc0:
454         if (node->contents < 0)
455                 return false;           // didn't hit anything
456
457         switch (node->plane->type)
458         {
459         case PLANE_X:
460                 node = node->children[x < node->plane->dist];
461                 goto loc0;
462         case PLANE_Y:
463                 node = node->children[y < node->plane->dist];
464                 goto loc0;
465         case PLANE_Z:
466                 side = startz < node->plane->dist;
467                 if ((endz < node->plane->dist) == side)
468                 {
469                         node = node->children[side];
470                         goto loc0;
471                 }
472                 // found an intersection
473                 mid = node->plane->dist;
474                 break;
475         default:
476                 back = front = x * node->plane->normal[0] + y * node->plane->normal[1];
477                 front += startz * node->plane->normal[2];
478                 back += endz * node->plane->normal[2];
479                 side = front < node->plane->dist;
480                 if ((back < node->plane->dist) == side)
481                 {
482                         node = node->children[side];
483                         goto loc0;
484                 }
485                 // found an intersection
486                 mid = startz + distz * (front - node->plane->dist) / (front - back);
487                 break;
488         }
489
490         // go down front side
491         if (node->children[side]->contents >= 0 && RecursiveLightPoint (color, node->children[side], x, y, startz, mid))
492                 return true;    // hit something
493         else
494         {
495                 // check for impact on this node
496                 if (node->numsurfaces)
497                 {
498                         int i, ds, dt;
499                         msurface_t *surf;
500
501                         surf = cl.worldmodel->surfaces + node->firstsurface;
502                         for (i = 0;i < node->numsurfaces;i++, surf++)
503                         {
504                                 if (!(surf->flags & SURF_LIGHTMAP))
505                                         continue;       // no lightmaps
506
507                                 ds = (int) (x * surf->texinfo->vecs[0][0] + y * surf->texinfo->vecs[0][1] + mid * surf->texinfo->vecs[0][2] + surf->texinfo->vecs[0][3]);
508                                 dt = (int) (x * surf->texinfo->vecs[1][0] + y * surf->texinfo->vecs[1][1] + mid * surf->texinfo->vecs[1][2] + surf->texinfo->vecs[1][3]);
509
510                                 if (ds < surf->texturemins[0] || dt < surf->texturemins[1])
511                                         continue;
512
513                                 ds -= surf->texturemins[0];
514                                 dt -= surf->texturemins[1];
515
516                                 if (ds > surf->extents[0] || dt > surf->extents[1])
517                                         continue;
518
519                                 if (surf->samples)
520                                 {
521                                         qbyte *lightmap;
522                                         int maps, line3, size3, dsfrac = ds & 15, dtfrac = dt & 15, scale = 0, r00 = 0, g00 = 0, b00 = 0, r01 = 0, g01 = 0, b01 = 0, r10 = 0, g10 = 0, b10 = 0, r11 = 0, g11 = 0, b11 = 0;
523                                         line3 = ((surf->extents[0]>>4)+1)*3;
524                                         size3 = ((surf->extents[0]>>4)+1) * ((surf->extents[1]>>4)+1)*3; // LordHavoc: *3 for colored lighting
525
526                                         lightmap = surf->samples + ((dt>>4) * ((surf->extents[0]>>4)+1) + (ds>>4))*3; // LordHavoc: *3 for color
527
528                                         for (maps = 0;maps < MAXLIGHTMAPS && surf->styles[maps] != 255;maps++)
529                                         {
530                                                 scale = d_lightstylevalue[surf->styles[maps]];
531                                                 r00 += lightmap[      0] * scale;g00 += lightmap[      1] * scale;b00 += lightmap[      2] * scale;
532                                                 r01 += lightmap[      3] * scale;g01 += lightmap[      4] * scale;b01 += lightmap[      5] * scale;
533                                                 r10 += lightmap[line3+0] * scale;g10 += lightmap[line3+1] * scale;b10 += lightmap[line3+2] * scale;
534                                                 r11 += lightmap[line3+3] * scale;g11 += lightmap[line3+4] * scale;b11 += lightmap[line3+5] * scale;
535                                                 lightmap += size3;
536                                         }
537
538 /*
539 LordHavoc: here's the readable version of the interpolation
540 code, not quite as easy for the compiler to optimize...
541
542 dsfrac is the X position in the lightmap pixel, * 16
543 dtfrac is the Y position in the lightmap pixel, * 16
544 r00 is top left corner, r01 is top right corner
545 r10 is bottom left corner, r11 is bottom right corner
546 g and b are the same layout.
547 r0 and r1 are the top and bottom intermediate results
548
549 first we interpolate the top two points, to get the top
550 edge sample
551
552         r0 = (((r01-r00) * dsfrac) >> 4) + r00;
553         g0 = (((g01-g00) * dsfrac) >> 4) + g00;
554         b0 = (((b01-b00) * dsfrac) >> 4) + b00;
555
556 then we interpolate the bottom two points, to get the
557 bottom edge sample
558
559         r1 = (((r11-r10) * dsfrac) >> 4) + r10;
560         g1 = (((g11-g10) * dsfrac) >> 4) + g10;
561         b1 = (((b11-b10) * dsfrac) >> 4) + b10;
562
563 then we interpolate the top and bottom samples to get the
564 middle sample (the one which was requested)
565
566         r = (((r1-r0) * dtfrac) >> 4) + r0;
567         g = (((g1-g0) * dtfrac) >> 4) + g0;
568         b = (((b1-b0) * dtfrac) >> 4) + b0;
569 */
570
571                                         color[0] += (float) ((((((((r11-r10) * dsfrac) >> 4) + r10)-((((r01-r00) * dsfrac) >> 4) + r00)) * dtfrac) >> 4) + ((((r01-r00) * dsfrac) >> 4) + r00)) * (1.0f / 32768.0f);
572                                         color[1] += (float) ((((((((g11-g10) * dsfrac) >> 4) + g10)-((((g01-g00) * dsfrac) >> 4) + g00)) * dtfrac) >> 4) + ((((g01-g00) * dsfrac) >> 4) + g00)) * (1.0f / 32768.0f);
573                                         color[2] += (float) ((((((((b11-b10) * dsfrac) >> 4) + b10)-((((b01-b00) * dsfrac) >> 4) + b00)) * dtfrac) >> 4) + ((((b01-b00) * dsfrac) >> 4) + b00)) * (1.0f / 32768.0f);
574                                 }
575                                 return true; // success
576                         }
577                 }
578
579                 // go down back side
580                 node = node->children[side ^ 1];
581                 startz = mid;
582                 distz = endz - startz;
583                 goto loc0;
584         }
585 }
586
587 void R_CompleteLightPoint (vec3_t color, const vec3_t p, int dynamic, const mleaf_t *leaf)
588 {
589         int i;
590         vec3_t v;
591         float f;
592         rdlight_t *rd;
593         mlight_t *sl;
594         if (leaf == NULL)
595                 leaf = Mod_PointInLeaf(p, cl.worldmodel);
596         if (!leaf || leaf->contents == CONTENTS_SOLID || r_fullbright.integer || !cl.worldmodel->lightdata)
597         {
598                 color[0] = color[1] = color[2] = 1;
599                 return;
600         }
601
602         color[0] = color[1] = color[2] = r_ambient.value * (2.0f / 128.0f);
603         if (cl.worldmodel->numlights)
604         {
605                 for (i = 0;i < cl.worldmodel->numlights;i++)
606                 {
607                         sl = cl.worldmodel->lights + i;
608                         if (d_lightstylevalue[sl->style] > 0)
609                         {
610                                 VectorSubtract (p, sl->origin, v);
611                                 f = ((1.0f / (DotProduct(v, v) * sl->falloff + sl->distbias)) - sl->subtract);
612                                 if (f > 0 && CL_TraceLine(p, sl->origin, NULL, NULL, 0, false, NULL) == 1)
613                                 {
614                                         f *= d_lightstylevalue[sl->style] * (1.0f / 65536.0f);
615                                         VectorMA(color, f, sl->light, color);
616                                 }
617                         }
618                 }
619         }
620         else
621                 RecursiveLightPoint (color, cl.worldmodel->nodes, p[0], p[1], p[2], p[2] - 65536);
622
623         if (dynamic)
624         {
625                 for (i = 0;i < r_numdlights;i++)
626                 {
627                         rd = r_dlight + i;
628                         VectorSubtract (p, rd->origin, v);
629                         f = DotProduct(v, v);
630                         if (f < rd->cullradius2 && CL_TraceLine(p, rd->origin, NULL, NULL, 0, false, NULL) == 1)
631                         {
632                                 f = (1.0f / (f + LIGHTOFFSET)) - rd->subtract;
633                                 VectorMA(color, f, rd->light, color);
634                         }
635                 }
636         }
637 }
638
639 void R_ModelLightPoint (const entity_render_t *ent, vec3_t color, const vec3_t p)
640 {
641         mleaf_t *leaf;
642         leaf = Mod_PointInLeaf(p, cl.worldmodel);
643         if (!leaf || leaf->contents == CONTENTS_SOLID || !cl.worldmodel->lightdata)
644         {
645                 color[0] = color[1] = color[2] = 1;
646                 return;
647         }
648
649         color[0] = color[1] = color[2] = r_ambient.value * (2.0f / 128.0f);
650         if (!cl.worldmodel->numlights)
651                 RecursiveLightPoint (color, cl.worldmodel->nodes, p[0], p[1], p[2], p[2] - 65536);
652 }
653
654 void R_LightModel(const entity_render_t *ent, int numverts, float *vertices, float *normals, float *colors, float colorr, float colorg, float colorb, int worldcoords)
655 {
656         int i, j, nearlights = 0, maxnearlights = r_modellights.integer;
657         float color[3], basecolor[3], v[3], t, *av, *avn, *avc, a, f, dist2, mscale, dot, stylescale, intensity, ambientcolor[3];
658         struct
659         {
660                 vec3_t origin;
661                 //vec_t cullradius2;
662                 vec3_t light;
663                 // how much this light would contribute to ambient if replaced
664                 vec3_t ambientlight;
665                 vec_t subtract;
666                 vec_t falloff;
667                 vec_t offset;
668                 // used for choosing only the brightest lights
669                 vec_t intensity;
670         }
671         nearlight[MAX_DLIGHTS], *nl;
672         mlight_t *sl;
673         rdlight_t *rd;
674         a = ent->alpha;
675         // scale of the model's coordinate space, to alter light attenuation to match
676         // make the mscale squared so it can scale the squared distance results
677         mscale = ent->scale * ent->scale;
678         if (r_fullbright.integer || (ent->effects & EF_FULLBRIGHT))
679                 basecolor[0] = basecolor[1] = basecolor[2] = 1.0f;
680         else if (r_shadow_realtime_world.integer)
681                 basecolor[0] = basecolor[1] = basecolor[2] = r_ambient.value * (2.0f / 128.0f);
682         else if (maxnearlights == 0)
683                 R_CompleteLightPoint (basecolor, ent->origin, true, NULL);
684         else
685         {
686                 R_ModelLightPoint(ent, basecolor, ent->origin);
687                 nl = &nearlight[0];
688                 for (i = 0;i < ent->numentlights;i++)
689                 {
690                         sl = cl.worldmodel->lights + ent->entlights[i];
691                         stylescale = d_lightstylevalue[sl->style] * (1.0f / 65536.0f);
692                         VectorSubtract (ent->origin, sl->origin, v);
693                         f = ((1.0f / (DotProduct(v, v) * sl->falloff + sl->distbias)) - sl->subtract) * stylescale;
694                         VectorScale(sl->light, f, ambientcolor);
695                         intensity = DotProduct(ambientcolor, ambientcolor);
696                         if (f < 0)
697                                 intensity *= -1.0f;
698                         if (nearlights < maxnearlights)
699                                 j = nearlights++;
700                         else
701                         {
702                                 for (j = 0;j < maxnearlights;j++)
703                                 {
704                                         if (nearlight[j].intensity < intensity)
705                                         {
706                                                 if (nearlight[j].intensity > 0)
707                                                         VectorAdd(basecolor, nearlight[j].ambientlight, basecolor);
708                                                 break;
709                                         }
710                                 }
711                         }
712                         if (j >= maxnearlights)
713                         {
714                                 // this light is less significant than all others,
715                                 // add it to ambient
716                                 if (intensity > 0)
717                                         VectorAdd(basecolor, ambientcolor, basecolor);
718                         }
719                         else
720                         {
721                                 nl = nearlight + j;
722                                 nl->intensity = intensity;
723                                 // transform the light into the model's coordinate system
724                                 if (worldcoords)
725                                         VectorCopy(sl->origin, nl->origin);
726                                 else
727                                         Matrix4x4_Transform(&ent->inversematrix, sl->origin, nl->origin);
728                                 // integrate mscale into falloff, for maximum speed
729                                 nl->falloff = sl->falloff * mscale;
730                                 VectorCopy(ambientcolor, nl->ambientlight);
731                                 nl->light[0] = sl->light[0] * stylescale * colorr * 4.0f;
732                                 nl->light[1] = sl->light[1] * stylescale * colorg * 4.0f;
733                                 nl->light[2] = sl->light[2] * stylescale * colorb * 4.0f;
734                                 nl->subtract = sl->subtract;
735                                 nl->offset = sl->distbias;
736                         }
737                 }
738                 if (!r_shadow_realtime_dlight.integer)
739                 {
740                         for (i = 0;i < r_numdlights;i++)
741                         {
742                                 rd = r_dlight + i;
743                                 VectorCopy(rd->origin, v);
744                                 if (v[0] < ent->mins[0]) v[0] = ent->mins[0];if (v[0] > ent->maxs[0]) v[0] = ent->maxs[0];
745                                 if (v[1] < ent->mins[1]) v[1] = ent->mins[1];if (v[1] > ent->maxs[1]) v[1] = ent->maxs[1];
746                                 if (v[2] < ent->mins[2]) v[2] = ent->mins[2];if (v[2] > ent->maxs[2]) v[2] = ent->maxs[2];
747                                 VectorSubtract (v, rd->origin, v);
748                                 if (DotProduct(v, v) < rd->cullradius2)
749                                 {
750                                         if (CL_TraceLine(ent->origin, rd->origin, NULL, NULL, 0, false, NULL) != 1)
751                                                 continue;
752                                         VectorSubtract (ent->origin, rd->origin, v);
753                                         f = ((1.0f / (DotProduct(v, v) + LIGHTOFFSET)) - rd->subtract);
754                                         VectorScale(rd->light, f, ambientcolor);
755                                         intensity = DotProduct(ambientcolor, ambientcolor);
756                                         if (f < 0)
757                                                 intensity *= -1.0f;
758                                         if (nearlights < maxnearlights)
759                                                 j = nearlights++;
760                                         else
761                                         {
762                                                 for (j = 0;j < maxnearlights;j++)
763                                                 {
764                                                         if (nearlight[j].intensity < intensity)
765                                                         {
766                                                                 if (nearlight[j].intensity > 0)
767                                                                         VectorAdd(basecolor, nearlight[j].ambientlight, basecolor);
768                                                                 break;
769                                                         }
770                                                 }
771                                         }
772                                         if (j >= maxnearlights)
773                                         {
774                                                 // this light is less significant than all others,
775                                                 // add it to ambient
776                                                 if (intensity > 0)
777                                                         VectorAdd(basecolor, ambientcolor, basecolor);
778                                         }
779                                         else
780                                         {
781                                                 nl = nearlight + j;
782                                                 nl->intensity = intensity;
783                                                 // transform the light into the model's coordinate system
784                                                 if (worldcoords)
785                                                         VectorCopy(rd->origin, nl->origin);
786                                                 else
787                                                 {
788                                                         Matrix4x4_Transform(&ent->inversematrix, rd->origin, nl->origin);
789                                                         /*
790                                                         Con_Printf("%i %s : %f %f %f : %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n"
791                                                         , rd - r_dlight, ent->model->name
792                                                         , rd->origin[0], rd->origin[1], rd->origin[2]
793                                                         , nl->origin[0], nl->origin[1], nl->origin[2]
794                                                         , ent->inversematrix.m[0][0], ent->inversematrix.m[0][1], ent->inversematrix.m[0][2], ent->inversematrix.m[0][3]
795                                                         , ent->inversematrix.m[1][0], ent->inversematrix.m[1][1], ent->inversematrix.m[1][2], ent->inversematrix.m[1][3]
796                                                         , ent->inversematrix.m[2][0], ent->inversematrix.m[2][1], ent->inversematrix.m[2][2], ent->inversematrix.m[2][3]
797                                                         , ent->inversematrix.m[3][0], ent->inversematrix.m[3][1], ent->inversematrix.m[3][2], ent->inversematrix.m[3][3]);
798                                                         */
799                                                 }
800                                                 // integrate mscale into falloff, for maximum speed
801                                                 nl->falloff = mscale;
802                                                 VectorCopy(ambientcolor, nl->ambientlight);
803                                                 nl->light[0] = rd->light[0] * colorr * 4.0f;
804                                                 nl->light[1] = rd->light[1] * colorg * 4.0f;
805                                                 nl->light[2] = rd->light[2] * colorb * 4.0f;
806                                                 nl->subtract = rd->subtract;
807                                                 nl->offset = LIGHTOFFSET;
808                                         }
809                                 }
810                         }
811                 }
812         }
813         basecolor[0] *= colorr;
814         basecolor[1] *= colorg;
815         basecolor[2] *= colorb;
816         avc = colors;
817         if (nearlights)
818         {
819                 GL_UseColorArray();
820                 av = vertices;
821                 avn = normals;
822                 for (i = 0;i < numverts;i++)
823                 {
824                         VectorCopy(basecolor, color);
825                         for (j = 0, nl = &nearlight[0];j < nearlights;j++, nl++)
826                         {
827                                 VectorSubtract(av, nl->origin, v);
828                                 // directional shading
829                                 dot = DotProduct(avn,v);
830                                 if (dot > 0)
831                                 {
832                                         // the vertex normal faces the light
833
834                                         // do the distance attenuation
835                                         dist2 = DotProduct(v,v);
836                                         f = (1.0f / (dist2 * nl->falloff + nl->offset)) - nl->subtract;
837                                         if (f > 0)
838                                         {
839                                                 //#if SLOWMATH
840                                                 t = 1.0f / sqrt(dist2);
841                                                 //#else
842                                                 //*((int *)&t) = 0x5f3759df - ((* (int *) &dist2) >> 1);
843                                                 //t = t * (1.5f - (dist2 * 0.5f * t * t));
844                                                 //#endif
845
846                                                 // dot * t is dotproduct with a normalized v.
847                                                 // (the result would be -1 to +1, but we already
848                                                 // eliminated the <= 0 case, so it is 0 to 1)
849
850                                                 // the hardness variables are for backlighting/shinyness
851                                                 // these have been hardwired at * 0.5 + 0.5 to match
852                                                 // the quake map lighting utility's equations
853                                                 f *= dot * t;// * 0.5f + 0.5f;// * hardness + hardnessoffset;
854                                                 VectorMA(color, f, nl->light, color);
855                                         }
856                                 }
857                         }
858
859                         VectorCopy(color, avc);
860                         avc[3] = a;
861                         avc += 4;
862                         av += 3;
863                         avn += 3;
864                 }
865         }
866         else
867                 GL_Color(basecolor[0], basecolor[1], basecolor[2], a);
868 }
869
870 void R_UpdateEntLights(entity_render_t *ent)
871 {
872         int i;
873         const mlight_t *sl;
874         vec3_t v;
875         if (r_shadow_realtime_dlight.integer)
876                 return;
877         VectorSubtract(ent->origin, ent->entlightsorigin, v);
878         if (ent->entlightsframe != (r_framecount - 1) || (realtime > ent->entlightstime && DotProduct(v,v) >= 1.0f))
879         {
880                 ent->entlightstime = realtime + 0.1;
881                 VectorCopy(ent->origin, ent->entlightsorigin);
882                 ent->numentlights = 0;
883                 if (cl.worldmodel)
884                         for (i = 0, sl = cl.worldmodel->lights;i < cl.worldmodel->numlights && ent->numentlights < MAXENTLIGHTS;i++, sl++)
885                                 if (CL_TraceLine(ent->origin, sl->origin, NULL, NULL, 0, false, NULL) == 1)
886                                         ent->entlights[ent->numentlights++] = i;
887         }
888         ent->entlightsframe = r_framecount;
889 }