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