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