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