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