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