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