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