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