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