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