]> icculus.org git repositories - divverent/darkplaces.git/blob - r_light.c
rewrote most of the RSurfShader_ functions to use R_Mesh_Draw_GetBuffer instead of...
[divverent/darkplaces.git] / r_light.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // r_light.c
21
22 #include "quakedef.h"
23 #include "cl_collision.h"
24
25 rdlight_t r_dlight[MAX_DLIGHTS];
26 int r_numdlights = 0;
27
28 cvar_t r_modellights = {CVAR_SAVE, "r_modellights", "4"};
29 cvar_t r_vismarklights = {0, "r_vismarklights", "1"};
30
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_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 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 v;
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, v);
666                                 f = ((1.0f / (DotProduct(v, v) * sl->falloff + sl->distbias)) - sl->subtract);
667                                 if (f > 0 && CL_TraceLine(p, sl->origin, NULL, NULL, 0, false) == 1)
668                                 {
669                                         f *= d_lightstylevalue[sl->style] * (1.0f / 65536.0f);
670                                         VectorMA(color, f, sl->light, color);
671                                 }
672                         }
673                 }
674         }
675         else
676                 RecursiveLightPoint (color, cl.worldmodel->nodes, p[0], p[1], p[2], p[2] - 65536);
677
678         if (dynamic && leaf->dlightframe == r_framecount)
679         {
680                 dlightbits = leaf->dlightbits;
681                 for (i = 0;i < r_numdlights;i++)
682                 {
683                         if (!(dlightbits[i >> 5] & (1 << (i & 31))))
684                                 continue;
685                         rd = r_dlight + i;
686                         VectorSubtract (p, rd->origin, v);
687                         f = DotProduct(v, v);
688                         if (f < rd->cullradius2)
689                         {
690                                 f = (1.0f / (f + LIGHTOFFSET)) - rd->subtract;
691                                 VectorMA(color, f, rd->light, color);
692                         }
693                 }
694         }
695 }
696
697 void R_ModelLightPoint (vec3_t color, vec3_t p, int *dlightbits)
698 {
699         mleaf_t *leaf;
700         leaf = Mod_PointInLeaf(p, cl.worldmodel);
701         if (leaf->contents == CONTENTS_SOLID)
702         {
703                 color[0] = color[1] = color[2] = 0;
704                 dlightbits[0] = dlightbits[1] = dlightbits[2] = dlightbits[3] = dlightbits[4] = dlightbits[5] = dlightbits[6] = dlightbits[7] = 0;
705                 return;
706         }
707
708         if (r_fullbright.integer || !cl.worldmodel->lightdata || currentrenderentity->effects & EF_FULLBRIGHT)
709         {
710                 color[0] = color[1] = color[2] = 2;
711                 dlightbits[0] = dlightbits[1] = dlightbits[2] = dlightbits[3] = dlightbits[4] = dlightbits[5] = dlightbits[6] = dlightbits[7] = 0;
712                 return;
713         }
714
715         color[0] = color[1] = color[2] = r_ambient.value * (2.0f / 128.0f);
716         if (!cl.worldmodel->numlights)
717                 RecursiveLightPoint (color, cl.worldmodel->nodes, p[0], p[1], p[2], p[2] - 65536);
718
719         if (leaf->dlightframe == r_framecount)
720         {
721                 dlightbits[0] = leaf->dlightbits[0];
722                 dlightbits[1] = leaf->dlightbits[1];
723                 dlightbits[2] = leaf->dlightbits[2];
724                 dlightbits[3] = leaf->dlightbits[3];
725                 dlightbits[4] = leaf->dlightbits[4];
726                 dlightbits[5] = leaf->dlightbits[5];
727                 dlightbits[6] = leaf->dlightbits[6];
728                 dlightbits[7] = leaf->dlightbits[7];
729         }
730         else
731                 dlightbits[0] = dlightbits[1] = dlightbits[2] = dlightbits[3] = dlightbits[4] = dlightbits[5] = dlightbits[6] = dlightbits[7] = 0;
732 }
733
734 void R_LightModel(int numverts, float colorr, float colorg, float colorb, int worldcoords)
735 {
736         int i, j, nearlights = 0, maxnearlights = r_modellights.integer;
737         float color[3], basecolor[3], v[3], t, *av, *avn, *avc, a, f, dist2, mscale, dot, stylescale, intensity, ambientcolor[3];
738         struct
739         {
740                 vec3_t origin;
741                 //vec_t cullradius2;
742                 vec3_t light;
743                 // how much this light would contribute to ambient if replaced
744                 vec3_t ambientlight;
745                 vec_t subtract;
746                 vec_t falloff;
747                 vec_t offset;
748                 // used for choosing only the brightest lights
749                 vec_t intensity;
750         }
751         nearlight[MAX_DLIGHTS], *nl;
752         int modeldlightbits[8];
753         mlight_t *sl;
754         rdlight_t *rd;
755         a = currentrenderentity->alpha;
756         // scale of the model's coordinate space, to alter light attenuation to match
757         // make the mscale squared so it can scale the squared distance results
758         mscale = currentrenderentity->scale * currentrenderentity->scale;
759         if ((maxnearlights != 0) && !r_fullbright.integer && !(currentrenderentity->effects & EF_FULLBRIGHT))
760         {
761                 R_ModelLightPoint(basecolor, currentrenderentity->origin, modeldlightbits);
762
763                 nl = &nearlight[0];
764                 VectorSubtract(currentrenderentity->origin, currentrenderentity->entlightsorigin, v);
765                 if ((realtime > currentrenderentity->entlightstime && DotProduct(v,v) >= 1.0f))
766                 {
767                         currentrenderentity->numentlights = 0;
768                         currentrenderentity->entlightstime = realtime + 0.2;
769                         VectorCopy(currentrenderentity->origin, currentrenderentity->entlightsorigin);
770                         for (i = 0, sl = cl.worldmodel->lights;i < cl.worldmodel->numlights && currentrenderentity->numentlights < MAXENTLIGHTS;i++, sl++)
771                                 if (CL_TraceLine(currentrenderentity->origin, sl->origin, NULL, NULL, 0, false) == 1)
772                                         currentrenderentity->entlights[currentrenderentity->numentlights++] = i;
773                 }
774                 for (i = 0;i < currentrenderentity->numentlights;i++)
775                 {
776                         sl = cl.worldmodel->lights + currentrenderentity->entlights[i];
777                         stylescale = d_lightstylevalue[sl->style] * (1.0f / 65536.0f);
778                         VectorSubtract (currentrenderentity->origin, sl->origin, v);
779                         f = ((1.0f / (DotProduct(v, v) * sl->falloff + sl->distbias)) - sl->subtract) * stylescale;
780                         VectorScale(sl->light, f, ambientcolor);
781                         intensity = DotProduct(ambientcolor, ambientcolor);
782                         if (f < 0)
783                                 intensity *= -1.0f;
784                         if (nearlights < maxnearlights)
785                                 j = nearlights++;
786                         else
787                         {
788                                 for (j = 0;j < maxnearlights;j++)
789                                 {
790                                         if (nearlight[j].intensity < intensity)
791                                         {
792                                                 if (nearlight[j].intensity > 0)
793                                                         VectorAdd(basecolor, nearlight[j].ambientlight, basecolor);
794                                                 break;
795                                         }
796                                 }
797                         }
798                         if (j >= maxnearlights)
799                         {
800                                 // this light is less significant than all others,
801                                 // add it to ambient
802                                 if (intensity > 0)
803                                         VectorAdd(basecolor, ambientcolor, basecolor);
804                         }
805                         else
806                         {
807                                 nl = nearlight + j;
808                                 nl->intensity = intensity;
809                                 // transform the light into the model's coordinate system
810                                 if (worldcoords)
811                                         VectorCopy(sl->origin, nl->origin);
812                                 else
813                                         softwareuntransform(sl->origin, nl->origin);
814                                 // integrate mscale into falloff, for maximum speed
815                                 nl->falloff = sl->falloff * mscale;
816                                 VectorCopy(ambientcolor, nl->ambientlight);
817                                 nl->light[0] = sl->light[0] * stylescale * colorr * 4.0f;
818                                 nl->light[1] = sl->light[1] * stylescale * colorg * 4.0f;
819                                 nl->light[2] = sl->light[2] * stylescale * colorb * 4.0f;
820                                 nl->subtract = sl->subtract;
821                                 nl->offset = sl->distbias;
822                         }
823                 }
824                 for (i = 0;i < r_numdlights;i++)
825                 {
826                         if (!(modeldlightbits[i >> 5] & (1 << (i & 31))))
827                                 continue;
828                         rd = r_dlight + i;
829                         VectorSubtract (currentrenderentity->origin, rd->origin, v);
830                         f = ((1.0f / (DotProduct(v, v) + LIGHTOFFSET)) - rd->subtract);
831                         VectorScale(rd->light, f, ambientcolor);
832                         intensity = DotProduct(ambientcolor, ambientcolor);
833                         if (f < 0)
834                                 intensity *= -1.0f;
835                         if (nearlights < maxnearlights)
836                                 j = nearlights++;
837                         else
838                         {
839                                 for (j = 0;j < maxnearlights;j++)
840                                 {
841                                         if (nearlight[j].intensity < intensity)
842                                         {
843                                                 if (nearlight[j].intensity > 0)
844                                                         VectorAdd(basecolor, nearlight[j].ambientlight, basecolor);
845                                                 break;
846                                         }
847                                 }
848                         }
849                         if (j >= maxnearlights)
850                         {
851                                 // this light is less significant than all others,
852                                 // add it to ambient
853                                 if (intensity > 0)
854                                         VectorAdd(basecolor, ambientcolor, basecolor);
855                         }
856                         else
857                         {
858                                 nl = nearlight + j;
859                                 nl->intensity = intensity;
860                                 // transform the light into the model's coordinate system
861                                 if (worldcoords)
862                                         VectorCopy(rd->origin, nl->origin);
863                                 else
864                                         softwareuntransform(rd->origin, nl->origin);
865                                 // integrate mscale into falloff, for maximum speed
866                                 nl->falloff = mscale;
867                                 VectorCopy(ambientcolor, nl->ambientlight);
868                                 nl->light[0] = rd->light[0] * colorr * 4.0f;
869                                 nl->light[1] = rd->light[1] * colorg * 4.0f;
870                                 nl->light[2] = rd->light[2] * colorb * 4.0f;
871                                 nl->subtract = rd->subtract;
872                                 nl->offset = LIGHTOFFSET;
873                         }
874                 }
875         }
876         else
877         {
878                 R_CompleteLightPoint (basecolor, currentrenderentity->origin, true, NULL);
879         }
880         basecolor[0] *= colorr;
881         basecolor[1] *= colorg;
882         basecolor[2] *= colorb;
883         avc = aliasvertcolor;
884         if (nearlights)
885         {
886                 av = aliasvert;
887                 avn = aliasvertnorm;
888                 for (i = 0;i < numverts;i++)
889                 {
890                         VectorCopy(basecolor, color);
891                         for (j = 0, nl = &nearlight[0];j < nearlights;j++, nl++)
892                         {
893                                 VectorSubtract(nl->origin, av, v);
894                                 // directional shading
895                                 dot = DotProduct(avn,v);
896                                 if (dot > 0)
897                                 {
898                                         // the vertex normal faces the light
899
900                                         // do the distance attenuation
901                                         dist2 = DotProduct(v,v);
902                                         f = (1.0f / (dist2 * nl->falloff + nl->offset)) - nl->subtract;
903                                         if (f > 0)
904                                         {
905                                                 #if SLOWMATH
906                                                 t = 1.0f / sqrt(dist2);
907                                                 #else
908                                                 *((int *)&t) = 0x5f3759df - ((* (int *) &dist2) >> 1);
909                                                 t = t * (1.5f - (dist2 * 0.5f * t * t));
910                                                 #endif
911
912                                                 // dot * t is dotproduct with a normalized v.
913                                                 // (the result would be -1 to +1, but we already
914                                                 // eliminated the <= 0 case, so it is 0 to 1)
915
916                                                 // the hardness variables are for backlighting/shinyness
917                                                 // these have been hardwired at * 0.5 + 0.5 to match
918                                                 // the quake map lighting utility's equations
919                                                 f *= dot * t;// * 0.5f + 0.5f;// * hardness + hardnessoffset;
920                                                 VectorMA(color, f, nl->light, color);
921                                         }
922                                 }
923                         }
924
925                         VectorCopy(color, avc);
926                         avc[3] = a;
927                         avc += 4;
928                         av += 4;
929                         avn += 3;
930                 }
931         }
932         else
933         {
934                 for (i = 0;i < numverts;i++)
935                 {
936                         VectorCopy(basecolor, avc);
937                         avc[3] = a;
938                         avc += 4;
939                 }
940         }
941 }
942