fixed some dynamic lighting bugs related to glowing self
[xonotic/darkplaces.git] / r_light.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // r_light.c
21
22 #include "quakedef.h"
23 #include "cl_collision.h"
24
25 rdlight_t r_dlight[MAX_DLIGHTS];
26 int r_numdlights = 0;
27
28 cvar_t r_modellights = {CVAR_SAVE, "r_modellights", "4"};
29 cvar_t r_vismarklights = {0, "r_vismarklights", "1"};
30 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1"};
31 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "1"};
32
33 static rtexture_t *lightcorona;
34 static rtexturepool_t *lighttexturepool;
35
36 void r_light_start(void)
37 {
38         float dx, dy;
39         int x, y, a;
40         qbyte pixels[32][32][4];
41         lighttexturepool = R_AllocTexturePool();
42         for (y = 0;y < 32;y++)
43         {
44                 dy = (y - 15.5f) * (1.0f / 16.0f);
45                 for (x = 0;x < 32;x++)
46                 {
47                         dx = (x - 15.5f) * (1.0f / 16.0f);
48                         a = ((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2));
49                         a = bound(0, a, 255);
50                         pixels[y][x][0] = a;
51                         pixels[y][x][1] = a;
52                         pixels[y][x][2] = a;
53                         pixels[y][x][3] = 255;
54                 }
55         }
56         lightcorona = R_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 extern cvar_t r_shadows;
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                 if (r_shadows.integer != 3)
695                 {
696                         nl = &nearlight[0];
697                         for (i = 0;i < ent->numentlights;i++)
698                         {
699                                 sl = cl.worldmodel->lights + ent->entlights[i];
700                                 stylescale = d_lightstylevalue[sl->style] * (1.0f / 65536.0f);
701                                 VectorSubtract (ent->origin, sl->origin, v);
702                                 f = ((1.0f / (DotProduct(v, v) * sl->falloff + sl->distbias)) - sl->subtract) * stylescale;
703                                 VectorScale(sl->light, f, ambientcolor);
704                                 intensity = DotProduct(ambientcolor, ambientcolor);
705                                 if (f < 0)
706                                         intensity *= -1.0f;
707                                 if (nearlights < maxnearlights)
708                                         j = nearlights++;
709                                 else
710                                 {
711                                         for (j = 0;j < maxnearlights;j++)
712                                         {
713                                                 if (nearlight[j].intensity < intensity)
714                                                 {
715                                                         if (nearlight[j].intensity > 0)
716                                                                 VectorAdd(basecolor, nearlight[j].ambientlight, basecolor);
717                                                         break;
718                                                 }
719                                         }
720                                 }
721                                 if (j >= maxnearlights)
722                                 {
723                                         // this light is less significant than all others,
724                                         // add it to ambient
725                                         if (intensity > 0)
726                                                 VectorAdd(basecolor, ambientcolor, basecolor);
727                                 }
728                                 else
729                                 {
730                                         nl = nearlight + j;
731                                         nl->intensity = intensity;
732                                         // transform the light into the model's coordinate system
733                                         if (worldcoords)
734                                                 VectorCopy(sl->origin, nl->origin);
735                                         else
736                                                 Matrix4x4_Transform(&ent->inversematrix, sl->origin, nl->origin);
737                                         // integrate mscale into falloff, for maximum speed
738                                         nl->falloff = sl->falloff * mscale;
739                                         VectorCopy(ambientcolor, nl->ambientlight);
740                                         nl->light[0] = sl->light[0] * stylescale * colorr * 4.0f;
741                                         nl->light[1] = sl->light[1] * stylescale * colorg * 4.0f;
742                                         nl->light[2] = sl->light[2] * stylescale * colorb * 4.0f;
743                                         nl->subtract = sl->subtract;
744                                         nl->offset = sl->distbias;
745                                 }
746                         }
747                         for (i = 0;i < r_numdlights;i++)
748                         {
749                                 rd = r_dlight + i;
750                                 VectorCopy(rd->origin, v);
751                                 if (v[0] < ent->mins[0]) v[0] = ent->mins[0];if (v[0] > ent->maxs[0]) v[0] = ent->maxs[0];
752                                 if (v[1] < ent->mins[1]) v[1] = ent->mins[1];if (v[1] > ent->maxs[1]) v[1] = ent->maxs[1];
753                                 if (v[2] < ent->mins[2]) v[2] = ent->mins[2];if (v[2] > ent->maxs[2]) v[2] = ent->maxs[2];
754                                 VectorSubtract (v, rd->origin, v);
755                                 if (DotProduct(v, v) < rd->cullradius2)
756                                 {
757                                         if (CL_TraceLine(ent->origin, rd->origin, NULL, NULL, 0, false, NULL) != 1)
758                                                 continue;
759                                         VectorSubtract (ent->origin, rd->origin, v);
760                                         f = ((1.0f / (DotProduct(v, v) + LIGHTOFFSET)) - rd->subtract);
761                                         VectorScale(rd->light, f, ambientcolor);
762                                         intensity = DotProduct(ambientcolor, ambientcolor);
763                                         if (f < 0)
764                                                 intensity *= -1.0f;
765                                         if (nearlights < maxnearlights)
766                                                 j = nearlights++;
767                                         else
768                                         {
769                                                 for (j = 0;j < maxnearlights;j++)
770                                                 {
771                                                         if (nearlight[j].intensity < intensity)
772                                                         {
773                                                                 if (nearlight[j].intensity > 0)
774                                                                         VectorAdd(basecolor, nearlight[j].ambientlight, basecolor);
775                                                                 break;
776                                                         }
777                                                 }
778                                         }
779                                         if (j >= maxnearlights)
780                                         {
781                                                 // this light is less significant than all others,
782                                                 // add it to ambient
783                                                 if (intensity > 0)
784                                                         VectorAdd(basecolor, ambientcolor, basecolor);
785                                         }
786                                         else
787                                         {
788                                                 nl = nearlight + j;
789                                                 nl->intensity = intensity;
790                                                 // transform the light into the model's coordinate system
791                                                 if (worldcoords)
792                                                         VectorCopy(rd->origin, nl->origin);
793                                                 else
794                                                 {
795                                                         Matrix4x4_Transform(&ent->inversematrix, rd->origin, nl->origin);
796                                                         /*
797                                                         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"
798                                                         , rd - r_dlight, ent->model->name
799                                                         , rd->origin[0], rd->origin[1], rd->origin[2]
800                                                         , nl->origin[0], nl->origin[1], nl->origin[2]
801                                                         , ent->inversematrix.m[0][0], ent->inversematrix.m[0][1], ent->inversematrix.m[0][2], ent->inversematrix.m[0][3]
802                                                         , ent->inversematrix.m[1][0], ent->inversematrix.m[1][1], ent->inversematrix.m[1][2], ent->inversematrix.m[1][3]
803                                                         , ent->inversematrix.m[2][0], ent->inversematrix.m[2][1], ent->inversematrix.m[2][2], ent->inversematrix.m[2][3]
804                                                         , ent->inversematrix.m[3][0], ent->inversematrix.m[3][1], ent->inversematrix.m[3][2], ent->inversematrix.m[3][3]);
805                                                         */
806                                                 }
807                                                 // integrate mscale into falloff, for maximum speed
808                                                 nl->falloff = mscale;
809                                                 VectorCopy(ambientcolor, nl->ambientlight);
810                                                 nl->light[0] = rd->light[0] * colorr * 4.0f;
811                                                 nl->light[1] = rd->light[1] * colorg * 4.0f;
812                                                 nl->light[2] = rd->light[2] * colorb * 4.0f;
813                                                 nl->subtract = rd->subtract;
814                                                 nl->offset = LIGHTOFFSET;
815                                         }
816                                 }
817                         }
818                 }
819         }
820         else
821                 R_CompleteLightPoint (basecolor, ent->origin, true, NULL);
822         basecolor[0] *= colorr;
823         basecolor[1] *= colorg;
824         basecolor[2] *= colorb;
825         avc = colors;
826         if (nearlights)
827         {
828                 GL_UseColorArray();
829                 av = vertices;
830                 avn = normals;
831                 for (i = 0;i < numverts;i++)
832                 {
833                         VectorCopy(basecolor, color);
834                         for (j = 0, nl = &nearlight[0];j < nearlights;j++, nl++)
835                         {
836                                 VectorSubtract(nl->origin, av, v);
837                                 // directional shading
838                                 dot = DotProduct(avn,v);
839                                 if (dot > 0)
840                                 {
841                                         // the vertex normal faces the light
842
843                                         // do the distance attenuation
844                                         dist2 = DotProduct(v,v);
845                                         f = (1.0f / (dist2 * nl->falloff + nl->offset)) - nl->subtract;
846                                         if (f > 0)
847                                         {
848                                                 //#if SLOWMATH
849                                                 t = 1.0f / sqrt(dist2);
850                                                 //#else
851                                                 //*((int *)&t) = 0x5f3759df - ((* (int *) &dist2) >> 1);
852                                                 //t = t * (1.5f - (dist2 * 0.5f * t * t));
853                                                 //#endif
854
855                                                 // dot * t is dotproduct with a normalized v.
856                                                 // (the result would be -1 to +1, but we already
857                                                 // eliminated the <= 0 case, so it is 0 to 1)
858
859                                                 // the hardness variables are for backlighting/shinyness
860                                                 // these have been hardwired at * 0.5 + 0.5 to match
861                                                 // the quake map lighting utility's equations
862                                                 f *= dot * t;// * 0.5f + 0.5f;// * hardness + hardnessoffset;
863                                                 VectorMA(color, f, nl->light, color);
864                                         }
865                                 }
866                         }
867
868                         VectorCopy(color, avc);
869                         avc[3] = a;
870                         avc += 4;
871                         av += 4;
872                         avn += 4;
873                 }
874         }
875         else
876                 GL_Color(basecolor[0], basecolor[1], basecolor[2], a);
877 }
878
879 void R_UpdateEntLights(entity_render_t *ent)
880 {
881         int i;
882         const mlight_t *sl;
883         vec3_t v;
884         VectorSubtract(ent->origin, ent->entlightsorigin, v);
885         if (ent->entlightsframe != (r_framecount - 1) || (realtime > ent->entlightstime && DotProduct(v,v) >= 1.0f))
886         {
887                 ent->entlightstime = realtime + 0.1;
888                 VectorCopy(ent->origin, ent->entlightsorigin);
889                 ent->numentlights = 0;
890                 if (cl.worldmodel)
891                         for (i = 0, sl = cl.worldmodel->lights;i < cl.worldmodel->numlights && ent->numentlights < MAXENTLIGHTS;i++, sl++)
892                                 if (CL_TraceLine(ent->origin, sl->origin, NULL, NULL, 0, false, NULL) == 1)
893                                         ent->entlights[ent->numentlights++] = i;
894         }
895         ent->entlightsframe = r_framecount;
896 }