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