fix some bugs with r_fullbright, no lights, and other such cases
[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 || !cl.worldmodel->lightdata)
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 (r_fullbright.integer || (ent->effects & EF_FULLBRIGHT))
695                 VectorSet(basecolor, 1, 1, 1);
696         else if (maxnearlights == 0 && r_shadow_lightingmode < 2)
697                 R_CompleteLightPoint (basecolor, ent->origin, true, NULL);
698         else
699         {
700                 R_ModelLightPoint(ent, basecolor, ent->origin);
701
702                 if (r_shadow_lightingmode < 2)
703                 {
704                         nl = &nearlight[0];
705                         for (i = 0;i < ent->numentlights;i++)
706                         {
707                                 sl = cl.worldmodel->lights + ent->entlights[i];
708                                 stylescale = d_lightstylevalue[sl->style] * (1.0f / 65536.0f);
709                                 VectorSubtract (ent->origin, sl->origin, v);
710                                 f = ((1.0f / (DotProduct(v, v) * sl->falloff + sl->distbias)) - sl->subtract) * stylescale;
711                                 VectorScale(sl->light, f, ambientcolor);
712                                 intensity = DotProduct(ambientcolor, ambientcolor);
713                                 if (f < 0)
714                                         intensity *= -1.0f;
715                                 if (nearlights < maxnearlights)
716                                         j = nearlights++;
717                                 else
718                                 {
719                                         for (j = 0;j < maxnearlights;j++)
720                                         {
721                                                 if (nearlight[j].intensity < intensity)
722                                                 {
723                                                         if (nearlight[j].intensity > 0)
724                                                                 VectorAdd(basecolor, nearlight[j].ambientlight, basecolor);
725                                                         break;
726                                                 }
727                                         }
728                                 }
729                                 if (j >= maxnearlights)
730                                 {
731                                         // this light is less significant than all others,
732                                         // add it to ambient
733                                         if (intensity > 0)
734                                                 VectorAdd(basecolor, ambientcolor, basecolor);
735                                 }
736                                 else
737                                 {
738                                         nl = nearlight + j;
739                                         nl->intensity = intensity;
740                                         // transform the light into the model's coordinate system
741                                         if (worldcoords)
742                                                 VectorCopy(sl->origin, nl->origin);
743                                         else
744                                                 Matrix4x4_Transform(&ent->inversematrix, sl->origin, nl->origin);
745                                         // integrate mscale into falloff, for maximum speed
746                                         nl->falloff = sl->falloff * mscale;
747                                         VectorCopy(ambientcolor, nl->ambientlight);
748                                         nl->light[0] = sl->light[0] * stylescale * colorr * 4.0f;
749                                         nl->light[1] = sl->light[1] * stylescale * colorg * 4.0f;
750                                         nl->light[2] = sl->light[2] * stylescale * colorb * 4.0f;
751                                         nl->subtract = sl->subtract;
752                                         nl->offset = sl->distbias;
753                                 }
754                         }
755                         if (r_shadow_lightingmode < 1)
756                         {
757                                 for (i = 0;i < r_numdlights;i++)
758                                 {
759                                         rd = r_dlight + i;
760                                         VectorCopy(rd->origin, v);
761                                         if (v[0] < ent->mins[0]) v[0] = ent->mins[0];if (v[0] > ent->maxs[0]) v[0] = ent->maxs[0];
762                                         if (v[1] < ent->mins[1]) v[1] = ent->mins[1];if (v[1] > ent->maxs[1]) v[1] = ent->maxs[1];
763                                         if (v[2] < ent->mins[2]) v[2] = ent->mins[2];if (v[2] > ent->maxs[2]) v[2] = ent->maxs[2];
764                                         VectorSubtract (v, rd->origin, v);
765                                         if (DotProduct(v, v) < rd->cullradius2)
766                                         {
767                                                 if (CL_TraceLine(ent->origin, rd->origin, NULL, NULL, 0, false, NULL) != 1)
768                                                         continue;
769                                                 VectorSubtract (ent->origin, rd->origin, v);
770                                                 f = ((1.0f / (DotProduct(v, v) + LIGHTOFFSET)) - rd->subtract);
771                                                 VectorScale(rd->light, f, ambientcolor);
772                                                 intensity = DotProduct(ambientcolor, ambientcolor);
773                                                 if (f < 0)
774                                                         intensity *= -1.0f;
775                                                 if (nearlights < maxnearlights)
776                                                         j = nearlights++;
777                                                 else
778                                                 {
779                                                         for (j = 0;j < maxnearlights;j++)
780                                                         {
781                                                                 if (nearlight[j].intensity < intensity)
782                                                                 {
783                                                                         if (nearlight[j].intensity > 0)
784                                                                                 VectorAdd(basecolor, nearlight[j].ambientlight, basecolor);
785                                                                         break;
786                                                                 }
787                                                         }
788                                                 }
789                                                 if (j >= maxnearlights)
790                                                 {
791                                                         // this light is less significant than all others,
792                                                         // add it to ambient
793                                                         if (intensity > 0)
794                                                                 VectorAdd(basecolor, ambientcolor, basecolor);
795                                                 }
796                                                 else
797                                                 {
798                                                         nl = nearlight + j;
799                                                         nl->intensity = intensity;
800                                                         // transform the light into the model's coordinate system
801                                                         if (worldcoords)
802                                                                 VectorCopy(rd->origin, nl->origin);
803                                                         else
804                                                         {
805                                                                 Matrix4x4_Transform(&ent->inversematrix, rd->origin, nl->origin);
806                                                                 /*
807                                                                 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"
808                                                                 , rd - r_dlight, ent->model->name
809                                                                 , rd->origin[0], rd->origin[1], rd->origin[2]
810                                                                 , nl->origin[0], nl->origin[1], nl->origin[2]
811                                                                 , ent->inversematrix.m[0][0], ent->inversematrix.m[0][1], ent->inversematrix.m[0][2], ent->inversematrix.m[0][3]
812                                                                 , ent->inversematrix.m[1][0], ent->inversematrix.m[1][1], ent->inversematrix.m[1][2], ent->inversematrix.m[1][3]
813                                                                 , ent->inversematrix.m[2][0], ent->inversematrix.m[2][1], ent->inversematrix.m[2][2], ent->inversematrix.m[2][3]
814                                                                 , ent->inversematrix.m[3][0], ent->inversematrix.m[3][1], ent->inversematrix.m[3][2], ent->inversematrix.m[3][3]);
815                                                                 */
816                                                         }
817                                                         // integrate mscale into falloff, for maximum speed
818                                                         nl->falloff = mscale;
819                                                         VectorCopy(ambientcolor, nl->ambientlight);
820                                                         nl->light[0] = rd->light[0] * colorr * 4.0f;
821                                                         nl->light[1] = rd->light[1] * colorg * 4.0f;
822                                                         nl->light[2] = rd->light[2] * colorb * 4.0f;
823                                                         nl->subtract = rd->subtract;
824                                                         nl->offset = LIGHTOFFSET;
825                                                 }
826                                         }
827                                 }
828                         }
829                 }
830         }
831         basecolor[0] *= colorr;
832         basecolor[1] *= colorg;
833         basecolor[2] *= colorb;
834         avc = colors;
835         if (nearlights)
836         {
837                 GL_UseColorArray();
838                 av = vertices;
839                 avn = normals;
840                 for (i = 0;i < numverts;i++)
841                 {
842                         VectorCopy(basecolor, color);
843                         for (j = 0, nl = &nearlight[0];j < nearlights;j++, nl++)
844                         {
845                                 VectorSubtract(av, nl->origin, v);
846                                 // directional shading
847                                 dot = DotProduct(avn,v);
848                                 if (dot > 0)
849                                 {
850                                         // the vertex normal faces the light
851
852                                         // do the distance attenuation
853                                         dist2 = DotProduct(v,v);
854                                         f = (1.0f / (dist2 * nl->falloff + nl->offset)) - nl->subtract;
855                                         if (f > 0)
856                                         {
857                                                 //#if SLOWMATH
858                                                 t = 1.0f / sqrt(dist2);
859                                                 //#else
860                                                 //*((int *)&t) = 0x5f3759df - ((* (int *) &dist2) >> 1);
861                                                 //t = t * (1.5f - (dist2 * 0.5f * t * t));
862                                                 //#endif
863
864                                                 // dot * t is dotproduct with a normalized v.
865                                                 // (the result would be -1 to +1, but we already
866                                                 // eliminated the <= 0 case, so it is 0 to 1)
867
868                                                 // the hardness variables are for backlighting/shinyness
869                                                 // these have been hardwired at * 0.5 + 0.5 to match
870                                                 // the quake map lighting utility's equations
871                                                 f *= dot * t;// * 0.5f + 0.5f;// * hardness + hardnessoffset;
872                                                 VectorMA(color, f, nl->light, color);
873                                         }
874                                 }
875                         }
876
877                         VectorCopy(color, avc);
878                         avc[3] = a;
879                         avc += 4;
880                         av += 4;
881                         avn += 4;
882                 }
883         }
884         else
885                 GL_Color(basecolor[0], basecolor[1], basecolor[2], a);
886 }
887
888 void R_UpdateEntLights(entity_render_t *ent)
889 {
890         int i;
891         const mlight_t *sl;
892         vec3_t v;
893         if (r_shadow_lightingmode >= 2)
894                 return;
895         VectorSubtract(ent->origin, ent->entlightsorigin, v);
896         if (ent->entlightsframe != (r_framecount - 1) || (realtime > ent->entlightstime && DotProduct(v,v) >= 1.0f))
897         {
898                 ent->entlightstime = realtime + 0.1;
899                 VectorCopy(ent->origin, ent->entlightsorigin);
900                 ent->numentlights = 0;
901                 if (cl.worldmodel)
902                         for (i = 0, sl = cl.worldmodel->lights;i < cl.worldmodel->numlights && ent->numentlights < MAXENTLIGHTS;i++, sl++)
903                                 if (CL_TraceLine(ent->origin, sl->origin, NULL, NULL, 0, false, NULL) == 1)
904                                         ent->entlights[ent->numentlights++] = i;
905         }
906         ent->entlightsframe = r_framecount;
907 }