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