gloss now works correctly
[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 #include "r_shadow.h"
25
26 rdlight_t r_dlight[MAX_DLIGHTS];
27 int r_numdlights = 0;
28
29 cvar_t r_modellights = {CVAR_SAVE, "r_modellights", "4"};
30 cvar_t r_vismarklights = {0, "r_vismarklights", "1"};
31 cvar_t r_coronas = {CVAR_SAVE, "r_coronas", "1"};
32 cvar_t gl_flashblend = {CVAR_SAVE, "gl_flashblend", "1"};
33
34 static rtexture_t *lightcorona;
35 static rtexturepool_t *lighttexturepool;
36
37 void r_light_start(void)
38 {
39         float dx, dy;
40         int x, y, a;
41         qbyte pixels[32][32][4];
42         lighttexturepool = R_AllocTexturePool();
43         for (y = 0;y < 32;y++)
44         {
45                 dy = (y - 15.5f) * (1.0f / 16.0f);
46                 for (x = 0;x < 32;x++)
47                 {
48                         dx = (x - 15.5f) * (1.0f / 16.0f);
49                         a = ((1.0f / (dx * dx + dy * dy + 0.2f)) - (1.0f / (1.0f + 0.2))) * 32.0f / (1.0f / (1.0f + 0.2));
50                         a = bound(0, a, 255);
51                         pixels[y][x][0] = a;
52                         pixels[y][x][1] = a;
53                         pixels[y][x][2] = a;
54                         pixels[y][x][3] = 255;
55                 }
56         }
57         lightcorona = R_LoadTexture2D(lighttexturepool, "lightcorona", 32, 32, &pixels[0][0][0], TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
58 }
59
60 void r_light_shutdown(void)
61 {
62         lighttexturepool = NULL;
63         lightcorona = NULL;
64 }
65
66 void r_light_newmap(void)
67 {
68         int i;
69         for (i = 0;i < 256;i++)
70                 d_lightstylevalue[i] = 264;             // normal light value
71 }
72
73 void R_Light_Init(void)
74 {
75         Cvar_RegisterVariable(&r_modellights);
76         Cvar_RegisterVariable(&r_vismarklights);
77         Cvar_RegisterVariable(&r_coronas);
78         Cvar_RegisterVariable(&gl_flashblend);
79         R_RegisterModule("R_Light", r_light_start, r_light_shutdown, r_light_newmap);
80 }
81
82 /*
83 ==================
84 R_AnimateLight
85 ==================
86 */
87 void R_AnimateLight (void)
88 {
89         int i, j, k;
90
91 //
92 // light animations
93 // 'm' is normal light, 'a' is no light, 'z' is double bright
94         i = (int)(cl.time * 10);
95         for (j = 0;j < MAX_LIGHTSTYLES;j++)
96         {
97                 if (!cl_lightstyle || !cl_lightstyle[j].length)
98                 {
99                         d_lightstylevalue[j] = 256;
100                         continue;
101                 }
102                 k = i % cl_lightstyle[j].length;
103                 k = cl_lightstyle[j].map[k] - 'a';
104                 k = k*22;
105                 d_lightstylevalue[j] = k;
106         }
107 }
108
109
110 void R_BuildLightList(void)
111 {
112         int i;
113         dlight_t *cd;
114         rdlight_t *rd;
115
116         r_numdlights = 0;
117         c_dlights = 0;
118
119         if (!r_dynamic.integer || !cl_dlights)
120                 return;
121
122         for (i = 0;i < MAX_DLIGHTS;i++)
123         {
124                 cd = cl_dlights + i;
125                 if (cd->radius <= 0)
126                         continue;
127                 rd = &r_dlight[r_numdlights++];
128                 VectorCopy(cd->origin, rd->origin);
129                 VectorScale(cd->color, cd->radius * 64.0f, rd->light);
130                 rd->cullradius2 = DotProduct(rd->light, rd->light) * (0.25f / (64.0f * 64.0f)) + 4096.0f;
131                 // clamp radius to avoid overflowing division table in lightmap code
132                 if (rd->cullradius2 > (2048.0f * 2048.0f))
133                         rd->cullradius2 = (2048.0f * 2048.0f);
134                 rd->cullradius = sqrt(rd->cullradius2);
135                 rd->subtract = 1.0f / rd->cullradius2;
136                 rd->ent = cd->ent;
137                 c_dlights++; // count every dlight in use
138         }
139 }
140
141 void R_DrawCoronas(void)
142 {
143         int i;
144         rmeshstate_t m;
145         float scale, viewdist, diff[3], dist;
146         rdlight_t *rd;
147         if (!r_coronas.integer)
148                 return;
149         memset(&m, 0, sizeof(m));
150         m.blendfunc1 = GL_ONE;
151         m.blendfunc2 = GL_ONE;
152         m.depthdisable = true; // magic
153         m.tex[0] = R_GetTexture(lightcorona);
154         R_Mesh_Matrix(&r_identitymatrix);
155         R_Mesh_State(&m);
156         viewdist = DotProduct(r_origin, vpn);
157         varray_texcoord[0][ 0] = 0;varray_texcoord[0][ 1] = 0;
158         varray_texcoord[0][ 4] = 0;varray_texcoord[0][ 5] = 1;
159         varray_texcoord[0][ 8] = 1;varray_texcoord[0][ 9] = 1;
160         varray_texcoord[0][12] = 1;varray_texcoord[0][13] = 0;
161         for (i = 0;i < r_numdlights;i++)
162         {
163                 rd = r_dlight + i;
164                 dist = (DotProduct(rd->origin, vpn) - viewdist);
165                 if (dist >= 24.0f && CL_TraceLine(rd->origin, r_origin, NULL, NULL, 0, true, NULL) == 1)
166                 {
167                         scale = r_colorscale * (1.0f / 131072.0f);
168                         if (gl_flashblend.integer)
169                                 scale *= 4.0f;
170                         if (fogenabled)
171                         {
172                                 VectorSubtract(rd->origin, r_origin, diff);
173                                 scale *= 1 - exp(fogdensity/DotProduct(diff,diff));
174                         }
175                         GL_Color(rd->light[0] * scale, rd->light[1] * scale, rd->light[2] * scale, 1);
176                         scale = rd->cullradius * 0.25f;
177                         if (gl_flashblend.integer)
178                                 scale *= 2.0f;
179                         varray_vertex[0] = rd->origin[0] - vright[0] * scale - vup[0] * scale;
180                         varray_vertex[1] = rd->origin[1] - vright[1] * scale - vup[1] * scale;
181                         varray_vertex[2] = rd->origin[2] - vright[2] * scale - vup[2] * scale;
182                         varray_vertex[4] = rd->origin[0] - vright[0] * scale + vup[0] * scale;
183                         varray_vertex[5] = rd->origin[1] - vright[1] * scale + vup[1] * scale;
184                         varray_vertex[6] = rd->origin[2] - vright[2] * scale + vup[2] * scale;
185                         varray_vertex[8] = rd->origin[0] + vright[0] * scale + vup[0] * scale;
186                         varray_vertex[9] = rd->origin[1] + vright[1] * scale + vup[1] * scale;
187                         varray_vertex[10] = rd->origin[2] + vright[2] * scale + vup[2] * scale;
188                         varray_vertex[12] = rd->origin[0] + vright[0] * scale - vup[0] * scale;
189                         varray_vertex[13] = rd->origin[1] + vright[1] * scale - vup[1] * scale;
190                         varray_vertex[14] = rd->origin[2] + vright[2] * scale - vup[2] * scale;
191                         R_Mesh_Draw(4, 2, polygonelements);
192                 }
193         }
194 }
195
196 /*
197 =============================================================================
198
199 DYNAMIC LIGHTS
200
201 =============================================================================
202 */
203
204 /*
205 =============
206 R_MarkLights
207 =============
208 */
209 static void R_OldMarkLights (entity_render_t *ent, vec3_t lightorigin, rdlight_t *rd, int bit, int bitindex, mnode_t *node)
210 {
211         float ndist, maxdist;
212         msurface_t *surf;
213         int i, *surfacepvsframes;
214         int d, impacts, impactt;
215         float dist, dist2, impact[3];
216
217         if (!r_dynamic.integer)
218                 return;
219
220         // for comparisons to minimum acceptable light
221         maxdist = rd->cullradius2;
222
223         surfacepvsframes = ent->model->surfacepvsframes;
224 loc0:
225         if (node->contents < 0)
226                 return;
227
228         ndist = PlaneDiff(lightorigin, node->plane);
229
230         if (ndist > rd->cullradius)
231         {
232                 node = node->children[0];
233                 goto loc0;
234         }
235         if (ndist < -rd->cullradius)
236         {
237                 node = node->children[1];
238                 goto loc0;
239         }
240
241 // mark the polygons
242         surf = ent->model->surfaces + node->firstsurface;
243         for (i = 0;i < node->numsurfaces;i++, surf++)
244         {
245                 if (surfacepvsframes[surf->number] != ent->model->pvsframecount)
246                         continue;
247                 dist = ndist;
248                 if (surf->flags & SURF_PLANEBACK)
249                         dist = -dist;
250
251                 if (dist < -0.25f && !(surf->flags & SURF_LIGHTBOTHSIDES))
252                         continue;
253
254                 dist2 = dist * dist;
255                 if (dist2 >= maxdist)
256                         continue;
257
258                 if (node->plane->type < 3)
259                 {
260                         VectorCopy(lightorigin, impact);
261                         impact[node->plane->type] -= dist;
262                 }
263                 else
264                 {
265                         impact[0] = lightorigin[0] - surf->plane->normal[0] * dist;
266                         impact[1] = lightorigin[1] - surf->plane->normal[1] * dist;
267                         impact[2] = lightorigin[2] - surf->plane->normal[2] * dist;
268                 }
269
270                 impacts = DotProduct (impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3] - surf->texturemins[0];
271
272                 d = bound(0, impacts, surf->extents[0] + 16) - impacts;
273                 dist2 += d * d;
274                 if (dist2 > maxdist)
275                         continue;
276
277                 impactt = DotProduct (impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3] - surf->texturemins[1];
278
279                 d = bound(0, impactt, surf->extents[1] + 16) - impactt;
280                 dist2 += d * d;
281                 if (dist2 > maxdist)
282                         continue;
283
284                 if (surf->dlightframe != r_framecount) // not dynamic until now
285                 {
286                         surf->dlightbits[0] = surf->dlightbits[1] = surf->dlightbits[2] = surf->dlightbits[3] = surf->dlightbits[4] = surf->dlightbits[5] = surf->dlightbits[6] = surf->dlightbits[7] = 0;
287                         surf->dlightframe = r_framecount;
288                 }
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] != model->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 && r_shadow_lightingmode < 2)
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                 if (r_shadow_lightingmode < 2)
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                         if (r_shadow_lightingmode < 1)
748                         {
749                                 for (i = 0;i < r_numdlights;i++)
750                                 {
751                                         rd = r_dlight + i;
752                                         VectorCopy(rd->origin, v);
753                                         if (v[0] < ent->mins[0]) v[0] = ent->mins[0];if (v[0] > ent->maxs[0]) v[0] = ent->maxs[0];
754                                         if (v[1] < ent->mins[1]) v[1] = ent->mins[1];if (v[1] > ent->maxs[1]) v[1] = ent->maxs[1];
755                                         if (v[2] < ent->mins[2]) v[2] = ent->mins[2];if (v[2] > ent->maxs[2]) v[2] = ent->maxs[2];
756                                         VectorSubtract (v, rd->origin, v);
757                                         if (DotProduct(v, v) < rd->cullradius2)
758                                         {
759                                                 if (CL_TraceLine(ent->origin, rd->origin, NULL, NULL, 0, false, NULL) != 1)
760                                                         continue;
761                                                 VectorSubtract (ent->origin, rd->origin, v);
762                                                 f = ((1.0f / (DotProduct(v, v) + LIGHTOFFSET)) - rd->subtract);
763                                                 VectorScale(rd->light, f, ambientcolor);
764                                                 intensity = DotProduct(ambientcolor, ambientcolor);
765                                                 if (f < 0)
766                                                         intensity *= -1.0f;
767                                                 if (nearlights < maxnearlights)
768                                                         j = nearlights++;
769                                                 else
770                                                 {
771                                                         for (j = 0;j < maxnearlights;j++)
772                                                         {
773                                                                 if (nearlight[j].intensity < intensity)
774                                                                 {
775                                                                         if (nearlight[j].intensity > 0)
776                                                                                 VectorAdd(basecolor, nearlight[j].ambientlight, basecolor);
777                                                                         break;
778                                                                 }
779                                                         }
780                                                 }
781                                                 if (j >= maxnearlights)
782                                                 {
783                                                         // this light is less significant than all others,
784                                                         // add it to ambient
785                                                         if (intensity > 0)
786                                                                 VectorAdd(basecolor, ambientcolor, basecolor);
787                                                 }
788                                                 else
789                                                 {
790                                                         nl = nearlight + j;
791                                                         nl->intensity = intensity;
792                                                         // transform the light into the model's coordinate system
793                                                         if (worldcoords)
794                                                                 VectorCopy(rd->origin, nl->origin);
795                                                         else
796                                                         {
797                                                                 Matrix4x4_Transform(&ent->inversematrix, rd->origin, nl->origin);
798                                                                 /*
799                                                                 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"
800                                                                 , rd - r_dlight, ent->model->name
801                                                                 , rd->origin[0], rd->origin[1], rd->origin[2]
802                                                                 , nl->origin[0], nl->origin[1], nl->origin[2]
803                                                                 , ent->inversematrix.m[0][0], ent->inversematrix.m[0][1], ent->inversematrix.m[0][2], ent->inversematrix.m[0][3]
804                                                                 , ent->inversematrix.m[1][0], ent->inversematrix.m[1][1], ent->inversematrix.m[1][2], ent->inversematrix.m[1][3]
805                                                                 , ent->inversematrix.m[2][0], ent->inversematrix.m[2][1], ent->inversematrix.m[2][2], ent->inversematrix.m[2][3]
806                                                                 , ent->inversematrix.m[3][0], ent->inversematrix.m[3][1], ent->inversematrix.m[3][2], ent->inversematrix.m[3][3]);
807                                                                 */
808                                                         }
809                                                         // integrate mscale into falloff, for maximum speed
810                                                         nl->falloff = mscale;
811                                                         VectorCopy(ambientcolor, nl->ambientlight);
812                                                         nl->light[0] = rd->light[0] * colorr * 4.0f;
813                                                         nl->light[1] = rd->light[1] * colorg * 4.0f;
814                                                         nl->light[2] = rd->light[2] * colorb * 4.0f;
815                                                         nl->subtract = rd->subtract;
816                                                         nl->offset = LIGHTOFFSET;
817                                                 }
818                                         }
819                                 }
820                         }
821                 }
822         }
823         else
824                 R_CompleteLightPoint (basecolor, ent->origin, true, NULL);
825         basecolor[0] *= colorr;
826         basecolor[1] *= colorg;
827         basecolor[2] *= colorb;
828         avc = colors;
829         if (nearlights)
830         {
831                 GL_UseColorArray();
832                 av = vertices;
833                 avn = normals;
834                 for (i = 0;i < numverts;i++)
835                 {
836                         VectorCopy(basecolor, color);
837                         for (j = 0, nl = &nearlight[0];j < nearlights;j++, nl++)
838                         {
839                                 VectorSubtract(nl->origin, av, v);
840                                 // directional shading
841                                 dot = DotProduct(avn,v);
842                                 if (dot > 0)
843                                 {
844                                         // the vertex normal faces the light
845
846                                         // do the distance attenuation
847                                         dist2 = DotProduct(v,v);
848                                         f = (1.0f / (dist2 * nl->falloff + nl->offset)) - nl->subtract;
849                                         if (f > 0)
850                                         {
851                                                 //#if SLOWMATH
852                                                 t = 1.0f / sqrt(dist2);
853                                                 //#else
854                                                 //*((int *)&t) = 0x5f3759df - ((* (int *) &dist2) >> 1);
855                                                 //t = t * (1.5f - (dist2 * 0.5f * t * t));
856                                                 //#endif
857
858                                                 // dot * t is dotproduct with a normalized v.
859                                                 // (the result would be -1 to +1, but we already
860                                                 // eliminated the <= 0 case, so it is 0 to 1)
861
862                                                 // the hardness variables are for backlighting/shinyness
863                                                 // these have been hardwired at * 0.5 + 0.5 to match
864                                                 // the quake map lighting utility's equations
865                                                 f *= dot * t;// * 0.5f + 0.5f;// * hardness + hardnessoffset;
866                                                 VectorMA(color, f, nl->light, color);
867                                         }
868                                 }
869                         }
870
871                         VectorCopy(color, avc);
872                         avc[3] = a;
873                         avc += 4;
874                         av += 4;
875                         avn += 4;
876                 }
877         }
878         else
879                 GL_Color(basecolor[0], basecolor[1], basecolor[2], a);
880 }
881
882 void R_UpdateEntLights(entity_render_t *ent)
883 {
884         int i;
885         const mlight_t *sl;
886         vec3_t v;
887         if (r_shadow_lightingmode >= 2)
888                 return;
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 }