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