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