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