added R_ScrollTexCoord2f (copies while texture coordinates with an offset)
[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 #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 typedef struct
640 {
641         vec3_t origin;
642         //vec_t cullradius2;
643         vec3_t light;
644         // how much this light would contribute to ambient if replaced
645         vec3_t ambientlight;
646         vec_t subtract;
647         vec_t falloff;
648         vec_t offset;
649         // used for choosing only the brightest lights
650         vec_t intensity;
651 }
652 nearlight_t;
653
654 static int nearlights;
655 static nearlight_t nearlight[MAX_DLIGHTS];
656
657 int R_LightModel(float *ambient4f, const entity_render_t *ent, float colorr, float colorg, float colorb, float colora, int worldcoords)
658 {
659         int i, j, maxnearlights;
660         float v[3], f, mscale, stylescale, intensity, ambientcolor[3];
661         nearlight_t *nl;
662         mlight_t *sl;
663         rdlight_t *rd;
664         mleaf_t *leaf;
665
666         nearlights = 0;
667         maxnearlights = r_modellights.integer;
668         if (r_fullbright.integer || (ent->effects & EF_FULLBRIGHT))
669         {
670                 // highly rare
671                 ambient4f[0] = colorr;
672                 ambient4f[1] = colorg;
673                 ambient4f[2] = colorb;
674                 ambient4f[3] = colora;
675                 return false;
676         }
677         if (r_shadow_realtime_world.integer)
678         {
679                 // user config choice
680                 ambient4f[0] = r_ambient.value * (2.0f / 128.0f) * colorr;
681                 ambient4f[1] = r_ambient.value * (2.0f / 128.0f) * colorg;
682                 ambient4f[2] = r_ambient.value * (2.0f / 128.0f) * colorb;
683                 ambient4f[3] = colora;
684                 return false;
685         }
686         if (maxnearlights == 0)
687         {
688                 // user config choice
689                 R_CompleteLightPoint (ambient4f, ent->origin, true, NULL);
690                 ambient4f[0] *= colorr;
691                 ambient4f[1] *= colorg;
692                 ambient4f[2] *= colorb;
693                 ambient4f[3] = colora;
694                 return false;
695         }
696         leaf = Mod_PointInLeaf(ent->origin, cl.worldmodel);
697         if (!leaf || leaf->contents == CONTENTS_SOLID || !cl.worldmodel->lightdata)
698                 ambient4f[0] = ambient4f[1] = ambient4f[2] = 1;
699         else
700         {
701                 ambient4f[0] = ambient4f[1] = ambient4f[2] = r_ambient.value * (2.0f / 128.0f);
702                 if (!cl.worldmodel->numlights)
703                         RecursiveLightPoint (ambient4f, cl.worldmodel->nodes, ent->origin[0], ent->origin[1], ent->origin[2], ent->origin[2] - 65536);
704         }
705         // scale of the model's coordinate space, to alter light attenuation to match
706         // make the mscale squared so it can scale the squared distance results
707         mscale = ent->scale * ent->scale;
708         nl = &nearlight[0];
709         for (i = 0;i < ent->numentlights;i++)
710         {
711                 sl = cl.worldmodel->lights + ent->entlights[i];
712                 stylescale = d_lightstylevalue[sl->style] * (1.0f / 65536.0f);
713                 VectorSubtract (ent->origin, sl->origin, v);
714                 f = ((1.0f / (DotProduct(v, v) * sl->falloff + sl->distbias)) - sl->subtract) * stylescale;
715                 VectorScale(sl->light, f, ambientcolor);
716                 intensity = DotProduct(ambientcolor, ambientcolor);
717                 if (f < 0)
718                         intensity *= -1.0f;
719                 if (nearlights < maxnearlights)
720                         j = nearlights++;
721                 else
722                 {
723                         for (j = 0;j < maxnearlights;j++)
724                         {
725                                 if (nearlight[j].intensity < intensity)
726                                 {
727                                         if (nearlight[j].intensity > 0)
728                                                 VectorAdd(ambient4f, nearlight[j].ambientlight, ambient4f);
729                                         break;
730                                 }
731                         }
732                 }
733                 if (j >= maxnearlights)
734                 {
735                         // this light is less significant than all others,
736                         // add it to ambient
737                         if (intensity > 0)
738                                 VectorAdd(ambient4f, ambientcolor, ambient4f);
739                 }
740                 else
741                 {
742                         nl = nearlight + j;
743                         nl->intensity = intensity;
744                         // transform the light into the model's coordinate system
745                         if (worldcoords)
746                                 VectorCopy(sl->origin, nl->origin);
747                         else
748                                 Matrix4x4_Transform(&ent->inversematrix, sl->origin, nl->origin);
749                         // integrate mscale into falloff, for maximum speed
750                         nl->falloff = sl->falloff * mscale;
751                         VectorCopy(ambientcolor, nl->ambientlight);
752                         nl->light[0] = sl->light[0] * stylescale * colorr * 4.0f;
753                         nl->light[1] = sl->light[1] * stylescale * colorg * 4.0f;
754                         nl->light[2] = sl->light[2] * stylescale * colorb * 4.0f;
755                         nl->subtract = sl->subtract;
756                         nl->offset = sl->distbias;
757                 }
758         }
759         if (!r_shadow_realtime_dlight.integer)
760         {
761                 for (i = 0;i < r_numdlights;i++)
762                 {
763                         rd = r_dlight + i;
764                         VectorCopy(rd->origin, v);
765                         if (v[0] < ent->mins[0]) v[0] = ent->mins[0];if (v[0] > ent->maxs[0]) v[0] = ent->maxs[0];
766                         if (v[1] < ent->mins[1]) v[1] = ent->mins[1];if (v[1] > ent->maxs[1]) v[1] = ent->maxs[1];
767                         if (v[2] < ent->mins[2]) v[2] = ent->mins[2];if (v[2] > ent->maxs[2]) v[2] = ent->maxs[2];
768                         VectorSubtract (v, rd->origin, v);
769                         if (DotProduct(v, v) < rd->cullradius2)
770                         {
771                                 if (CL_TraceLine(ent->origin, rd->origin, NULL, NULL, 0, false, NULL) != 1)
772                                         continue;
773                                 VectorSubtract (ent->origin, rd->origin, v);
774                                 f = ((1.0f / (DotProduct(v, v) + LIGHTOFFSET)) - rd->subtract);
775                                 VectorScale(rd->light, f, ambientcolor);
776                                 intensity = DotProduct(ambientcolor, ambientcolor);
777                                 if (f < 0)
778                                         intensity *= -1.0f;
779                                 if (nearlights < maxnearlights)
780                                         j = nearlights++;
781                                 else
782                                 {
783                                         for (j = 0;j < maxnearlights;j++)
784                                         {
785                                                 if (nearlight[j].intensity < intensity)
786                                                 {
787                                                         if (nearlight[j].intensity > 0)
788                                                                 VectorAdd(ambient4f, nearlight[j].ambientlight, ambient4f);
789                                                         break;
790                                                 }
791                                         }
792                                 }
793                                 if (j >= maxnearlights)
794                                 {
795                                         // this light is less significant than all others,
796                                         // add it to ambient
797                                         if (intensity > 0)
798                                                 VectorAdd(ambient4f, ambientcolor, ambient4f);
799                                 }
800                                 else
801                                 {
802                                         nl = nearlight + j;
803                                         nl->intensity = intensity;
804                                         // transform the light into the model's coordinate system
805                                         if (worldcoords)
806                                                 VectorCopy(rd->origin, nl->origin);
807                                         else
808                                         {
809                                                 Matrix4x4_Transform(&ent->inversematrix, rd->origin, nl->origin);
810                                                 /*
811                                                 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"
812                                                 , rd - r_dlight, ent->model->name
813                                                 , rd->origin[0], rd->origin[1], rd->origin[2]
814                                                 , nl->origin[0], nl->origin[1], nl->origin[2]
815                                                 , ent->inversematrix.m[0][0], ent->inversematrix.m[0][1], ent->inversematrix.m[0][2], ent->inversematrix.m[0][3]
816                                                 , ent->inversematrix.m[1][0], ent->inversematrix.m[1][1], ent->inversematrix.m[1][2], ent->inversematrix.m[1][3]
817                                                 , ent->inversematrix.m[2][0], ent->inversematrix.m[2][1], ent->inversematrix.m[2][2], ent->inversematrix.m[2][3]
818                                                 , ent->inversematrix.m[3][0], ent->inversematrix.m[3][1], ent->inversematrix.m[3][2], ent->inversematrix.m[3][3]);
819                                                 */
820                                         }
821                                         // integrate mscale into falloff, for maximum speed
822                                         nl->falloff = mscale;
823                                         VectorCopy(ambientcolor, nl->ambientlight);
824                                         nl->light[0] = rd->light[0] * colorr * 4.0f;
825                                         nl->light[1] = rd->light[1] * colorg * 4.0f;
826                                         nl->light[2] = rd->light[2] * colorb * 4.0f;
827                                         nl->subtract = rd->subtract;
828                                         nl->offset = LIGHTOFFSET;
829                                 }
830                         }
831                 }
832         }
833         ambient4f[0] *= colorr;
834         ambient4f[1] *= colorg;
835         ambient4f[2] *= colorb;
836         ambient4f[3] = colora;
837         return nearlights != 0;
838 }
839
840 void R_LightModel_CalcVertexColors(const float *ambientcolor4f, int numverts, const float *vertex3f, const float *normal3f, float *color4f)
841 {
842         int i, j;
843         float color[4], v[3], dot, dist2, f;
844         nearlight_t *nl;
845         // directional shading code here
846         for (i = 0;i < numverts;i++, vertex3f += 3, normal3f += 3, color4f += 4)
847         {
848                 VectorCopy4(ambientcolor4f, color);
849                 for (j = 0, nl = &nearlight[0];j < nearlights;j++, nl++)
850                 {
851                         VectorSubtract(vertex3f, nl->origin, v);
852                         // first eliminate negative lighting (back side)
853                         dot = DotProduct(normal3f, v);
854                         if (dot > 0)
855                         {
856                                 // we'll need this again later to normalize the dotproduct
857                                 dist2 = DotProduct(v,v);
858                                 // do the distance attenuation math
859                                 f = (1.0f / (dist2 * nl->falloff + nl->offset)) - nl->subtract;
860                                 if (f > 0)
861                                 {
862                                         // we must divide dot by sqrt(dist2) to compensate for
863                                         // the fact we did not normalize v before doing the
864                                         // dotproduct, the result is in the range 0 to 1 (we
865                                         // eliminated negative numbers already)
866                                         f *= dot / sqrt(dist2);
867                                         // blend in the lighting
868                                         VectorMA(color, f, nl->light, color);
869                                 }
870                         }
871                 }
872                 VectorCopy4(color, color4f);
873         }
874 }
875
876 void R_UpdateEntLights(entity_render_t *ent)
877 {
878         int i;
879         const mlight_t *sl;
880         vec3_t v;
881         if (r_shadow_realtime_dlight.integer)
882                 return;
883         VectorSubtract(ent->origin, ent->entlightsorigin, v);
884         if (ent->entlightsframe != (r_framecount - 1) || (realtime > ent->entlightstime && DotProduct(v,v) >= 1.0f))
885         {
886                 ent->entlightstime = realtime + 0.1;
887                 VectorCopy(ent->origin, ent->entlightsorigin);
888                 ent->numentlights = 0;
889                 if (cl.worldmodel)
890                         for (i = 0, sl = cl.worldmodel->lights;i < cl.worldmodel->numlights && ent->numentlights < MAXENTLIGHTS;i++, sl++)
891                                 if (CL_TraceLine(ent->origin, sl->origin, NULL, NULL, 0, false, NULL) == 1)
892                                         ent->entlights[ent->numentlights++] = i;
893         }
894         ent->entlightsframe = r_framecount;
895 }