Host_SaveConfig_f now refuses to save if Host_Frame hasn't completed the first frame...
[xonotic/darkplaces.git] / gl_rsurf.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_surf.c: surface-related refresh code
21
22 #include "quakedef.h"
23 #include "r_shadow.h"
24
25 #define MAX_LIGHTMAP_SIZE 256
26
27 static unsigned int intblocklights[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*3]; // LordHavoc: *3 for colored lighting
28 static float floatblocklights[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*3]; // LordHavoc: *3 for colored lighting
29
30 static qbyte templight[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*4];
31
32 cvar_t r_ambient = {0, "r_ambient", "0"};
33 cvar_t r_drawportals = {0, "r_drawportals", "0"};
34 cvar_t r_testvis = {0, "r_testvis", "0"};
35 cvar_t r_floatbuildlightmap = {0, "r_floatbuildlightmap", "0"};
36 cvar_t r_detailtextures = {CVAR_SAVE, "r_detailtextures", "1"};
37 cvar_t r_surfaceworldnode = {0, "r_surfaceworldnode", "0"};
38 cvar_t r_drawcollisionbrushes_polygonfactor = {0, "r_drawcollisionbrushes_polygonfactor", "-1"};
39 cvar_t r_drawcollisionbrushes_polygonoffset = {0, "r_drawcollisionbrushes_polygonoffset", "0"};
40 cvar_t r_q3bsp_renderskydepth = {0, "r_q3bsp_renderskydepth", "0"};
41 cvar_t gl_lightmaps = {0, "gl_lightmaps", "0"};
42
43 // flag arrays used for visibility checking on world model
44 // (all other entities have no per-surface/per-leaf visibility checks)
45 // TODO: dynamic resize according to r_refdef.worldmodel->brush.num_clusters
46 qbyte r_pvsbits[(32768+7)>>3];
47 // TODO: dynamic resize according to r_refdef.worldmodel->brush.num_leafs
48 qbyte r_worldleafvisible[32768];
49 // TODO: dynamic resize according to r_refdef.worldmodel->brush.num_surfaces
50 qbyte r_worldsurfacevisible[262144];
51
52 static int dlightdivtable[32768];
53
54 static int R_IntAddDynamicLights (const matrix4x4_t *matrix, msurface_t *surface)
55 {
56         int sdtable[256], lnum, td, maxdist, maxdist2, maxdist3, i, s, t, smax, tmax, smax3, red, green, blue, lit, dist2, impacts, impactt, subtract, k;
57         unsigned int *bl;
58         float dist, impact[3], local[3], planenormal[3], planedist;
59         dlight_t *light;
60
61         lit = false;
62
63         smax = (surface->extents[0] >> 4) + 1;
64         tmax = (surface->extents[1] >> 4) + 1;
65         smax3 = smax * 3;
66
67         for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
68         {
69                 if (!(surface->dlightbits[lnum >> 5] & (1 << (lnum & 31))))
70                         continue;                                       // not lit by this light
71
72                 Matrix4x4_Transform(matrix, light->origin, local);
73                 VectorCopy(surface->mesh.data_normal3f, planenormal);
74                 planedist = DotProduct(surface->mesh.data_vertex3f, planenormal);
75                 dist = DotProduct(local, planenormal) - planedist;
76
77                 // for comparisons to minimum acceptable light
78                 // compensate for LIGHTOFFSET
79                 maxdist = (int) light->rtlight.lightmap_cullradius2 + LIGHTOFFSET;
80
81                 dist2 = dist * dist;
82                 dist2 += LIGHTOFFSET;
83                 if (dist2 >= maxdist)
84                         continue;
85
86                 VectorMA(local, -dist, planenormal, impact);
87
88                 impacts = DotProduct (impact, surface->texinfo->vecs[0]) + surface->texinfo->vecs[0][3] - surface->texturemins[0];
89                 impactt = DotProduct (impact, surface->texinfo->vecs[1]) + surface->texinfo->vecs[1][3] - surface->texturemins[1];
90
91                 s = bound(0, impacts, smax * 16) - impacts;
92                 t = bound(0, impactt, tmax * 16) - impactt;
93                 i = s * s + t * t + dist2;
94                 if (i > maxdist)
95                         continue;
96
97                 // reduce calculations
98                 for (s = 0, i = impacts; s < smax; s++, i -= 16)
99                         sdtable[s] = i * i + dist2;
100
101                 maxdist3 = maxdist - dist2;
102
103                 // convert to 8.8 blocklights format
104                 red = light->rtlight.lightmap_light[0] * (1.0f / 128.0f);
105                 green = light->rtlight.lightmap_light[1] * (1.0f / 128.0f);
106                 blue = light->rtlight.lightmap_light[2] * (1.0f / 128.0f);
107                 subtract = (int) (light->rtlight.lightmap_subtract * 4194304.0f);
108                 bl = intblocklights;
109
110                 i = impactt;
111                 for (t = 0;t < tmax;t++, i -= 16)
112                 {
113                         td = i * i;
114                         // make sure some part of it is visible on this line
115                         if (td < maxdist3)
116                         {
117                                 maxdist2 = maxdist - td;
118                                 for (s = 0;s < smax;s++)
119                                 {
120                                         if (sdtable[s] < maxdist2)
121                                         {
122                                                 k = dlightdivtable[(sdtable[s] + td) >> 7] - subtract;
123                                                 if (k > 0)
124                                                 {
125                                                         bl[0] += (red   * k);
126                                                         bl[1] += (green * k);
127                                                         bl[2] += (blue  * k);
128                                                         lit = true;
129                                                 }
130                                         }
131                                         bl += 3;
132                                 }
133                         }
134                         else // skip line
135                                 bl += smax3;
136                 }
137         }
138         return lit;
139 }
140
141 static int R_FloatAddDynamicLights (const matrix4x4_t *matrix, msurface_t *surface)
142 {
143         int lnum, s, t, smax, tmax, smax3, lit, impacts, impactt;
144         float sdtable[256], *bl, k, dist, dist2, maxdist, maxdist2, maxdist3, td1, td, red, green, blue, impact[3], local[3], subtract, planenormal[3], planedist;
145         dlight_t *light;
146
147         lit = false;
148
149         smax = (surface->extents[0] >> 4) + 1;
150         tmax = (surface->extents[1] >> 4) + 1;
151         smax3 = smax * 3;
152
153         for (lnum = 0, light = r_dlight;lnum < r_numdlights;lnum++, light++)
154         {
155                 if (!(surface->dlightbits[lnum >> 5] & (1 << (lnum & 31))))
156                         continue;                                       // not lit by this light
157
158                 Matrix4x4_Transform(matrix, light->origin, local);
159                 VectorCopy(surface->mesh.data_normal3f, planenormal);
160                 planedist = DotProduct(surface->mesh.data_vertex3f, planenormal);
161                 dist = DotProduct(local, planenormal) - planedist;
162
163                 // for comparisons to minimum acceptable light
164                 // compensate for LIGHTOFFSET
165                 maxdist = (int) light->rtlight.lightmap_cullradius2 + LIGHTOFFSET;
166
167                 dist2 = dist * dist;
168                 dist2 += LIGHTOFFSET;
169                 if (dist2 >= maxdist)
170                         continue;
171
172                 VectorMA(local, -dist, planenormal, impact);
173
174                 impacts = DotProduct (impact, surface->texinfo->vecs[0]) + surface->texinfo->vecs[0][3] - surface->texturemins[0];
175                 impactt = DotProduct (impact, surface->texinfo->vecs[1]) + surface->texinfo->vecs[1][3] - surface->texturemins[1];
176
177                 td = bound(0, impacts, smax * 16) - impacts;
178                 td1 = bound(0, impactt, tmax * 16) - impactt;
179                 td = td * td + td1 * td1 + dist2;
180                 if (td > maxdist)
181                         continue;
182
183                 // reduce calculations
184                 for (s = 0, td1 = impacts; s < smax; s++, td1 -= 16.0f)
185                         sdtable[s] = td1 * td1 + dist2;
186
187                 maxdist3 = maxdist - dist2;
188
189                 // convert to 8.8 blocklights format
190                 red = light->rtlight.lightmap_light[0];
191                 green = light->rtlight.lightmap_light[1];
192                 blue = light->rtlight.lightmap_light[2];
193                 subtract = light->rtlight.lightmap_subtract * 32768.0f;
194                 bl = floatblocklights;
195
196                 td1 = impactt;
197                 for (t = 0;t < tmax;t++, td1 -= 16.0f)
198                 {
199                         td = td1 * td1;
200                         // make sure some part of it is visible on this line
201                         if (td < maxdist3)
202                         {
203                                 maxdist2 = maxdist - td;
204                                 for (s = 0;s < smax;s++)
205                                 {
206                                         if (sdtable[s] < maxdist2)
207                                         {
208                                                 k = (32768.0f / (sdtable[s] + td)) - subtract;
209                                                 bl[0] += red   * k;
210                                                 bl[1] += green * k;
211                                                 bl[2] += blue  * k;
212                                                 lit = true;
213                                         }
214                                         bl += 3;
215                                 }
216                         }
217                         else // skip line
218                                 bl += smax3;
219                 }
220         }
221         return lit;
222 }
223
224 /*
225 ===============
226 R_BuildLightMap
227
228 Combine and scale multiple lightmaps into the 8.8 format in blocklights
229 ===============
230 */
231 static void R_BuildLightMap (const entity_render_t *ent, msurface_t *surface)
232 {
233         if (!r_floatbuildlightmap.integer)
234         {
235                 int smax, tmax, i, j, size, size3, maps, stride, l;
236                 unsigned int *bl, scale;
237                 qbyte *lightmap, *out, *stain;
238
239                 // update cached lighting info
240                 surface->cached_dlight = 0;
241
242                 smax = (surface->extents[0]>>4)+1;
243                 tmax = (surface->extents[1]>>4)+1;
244                 size = smax*tmax;
245                 size3 = size*3;
246                 lightmap = surface->samples;
247
248         // set to full bright if no light data
249                 bl = intblocklights;
250                 if (!ent->model->brushq1.lightdata)
251                 {
252                         for (i = 0;i < size3;i++)
253                                 bl[i] = 255*256;
254                 }
255                 else
256                 {
257         // clear to no light
258                         memset(bl, 0, size*3*sizeof(unsigned int));
259
260                         if (surface->dlightframe == r_framecount)
261                         {
262                                 surface->cached_dlight = R_IntAddDynamicLights(&ent->inversematrix, surface);
263                                 if (surface->cached_dlight)
264                                         c_light_polys++;
265                         }
266
267         // add all the lightmaps
268                         if (lightmap)
269                         {
270                                 bl = intblocklights;
271                                 for (maps = 0;maps < MAXLIGHTMAPS && surface->styles[maps] != 255;maps++, lightmap += size3)
272                                         for (scale = d_lightstylevalue[surface->styles[maps]], i = 0;i < size3;i++)
273                                                 bl[i] += lightmap[i] * scale;
274                         }
275                 }
276
277                 stain = surface->stainsamples;
278                 bl = intblocklights;
279                 out = templight;
280                 // the >> 16 shift adjusts down 8 bits to account for the stainmap
281                 // scaling, and remaps the 0-65536 (2x overbright) to 0-256, it will
282                 // be doubled during rendering to achieve 2x overbright
283                 // (0 = 0.0, 128 = 1.0, 256 = 2.0)
284                 if (ent->model->brushq1.lightmaprgba)
285                 {
286                         stride = (surface->lightmaptexturestride - smax) * 4;
287                         for (i = 0;i < tmax;i++, out += stride)
288                         {
289                                 for (j = 0;j < smax;j++)
290                                 {
291                                         l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255);
292                                         l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255);
293                                         l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255);
294                                         *out++ = 255;
295                                 }
296                         }
297                 }
298                 else
299                 {
300                         stride = (surface->lightmaptexturestride - smax) * 3;
301                         for (i = 0;i < tmax;i++, out += stride)
302                         {
303                                 for (j = 0;j < smax;j++)
304                                 {
305                                         l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255);
306                                         l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255);
307                                         l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255);
308                                 }
309                         }
310                 }
311
312                 R_UpdateTexture(surface->lightmaptexture, templight);
313         }
314         else
315         {
316                 int smax, tmax, i, j, size, size3, maps, stride, l;
317                 float *bl, scale;
318                 qbyte *lightmap, *out, *stain;
319
320                 // update cached lighting info
321                 surface->cached_dlight = 0;
322
323                 smax = (surface->extents[0]>>4)+1;
324                 tmax = (surface->extents[1]>>4)+1;
325                 size = smax*tmax;
326                 size3 = size*3;
327                 lightmap = surface->samples;
328
329         // set to full bright if no light data
330                 bl = floatblocklights;
331                 if (!ent->model->brushq1.lightdata)
332                 {
333                         for (i = 0;i < size3;i++)
334                                 bl[i] = 255*256;
335                 }
336                 else
337                 {
338                         memset(bl, 0, size*3*sizeof(float));
339
340                         if (surface->dlightframe == r_framecount)
341                         {
342                                 surface->cached_dlight = R_FloatAddDynamicLights(&ent->inversematrix, surface);
343                                 if (surface->cached_dlight)
344                                         c_light_polys++;
345                         }
346
347                         // add all the lightmaps
348                         if (lightmap)
349                         {
350                                 bl = floatblocklights;
351                                 for (maps = 0;maps < MAXLIGHTMAPS && surface->styles[maps] != 255;maps++, lightmap += size3)
352                                         for (scale = d_lightstylevalue[surface->styles[maps]], i = 0;i < size3;i++)
353                                                 bl[i] += lightmap[i] * scale;
354                         }
355                 }
356
357                 stain = surface->stainsamples;
358                 bl = floatblocklights;
359                 out = templight;
360                 // this scaling adjusts down 8 bits to account for the stainmap
361                 // scaling, and remaps the 0.0-2.0 (2x overbright) to 0-256, it will
362                 // be doubled during rendering to achieve 2x overbright
363                 // (0 = 0.0, 128 = 1.0, 256 = 2.0)
364                 scale = 1.0f / (1 << 16);
365                 if (ent->model->brushq1.lightmaprgba)
366                 {
367                         stride = (surface->lightmaptexturestride - smax) * 4;
368                         for (i = 0;i < tmax;i++, out += stride)
369                         {
370                                 for (j = 0;j < smax;j++)
371                                 {
372                                         l = *bl++ * *stain++ * scale;*out++ = min(l, 255);
373                                         l = *bl++ * *stain++ * scale;*out++ = min(l, 255);
374                                         l = *bl++ * *stain++ * scale;*out++ = min(l, 255);
375                                         *out++ = 255;
376                                 }
377                         }
378                 }
379                 else
380                 {
381                         stride = (surface->lightmaptexturestride - smax) * 3;
382                         for (i = 0;i < tmax;i++, out += stride)
383                         {
384                                 for (j = 0;j < smax;j++)
385                                 {
386                                         l = *bl++ * *stain++ * scale;*out++ = min(l, 255);
387                                         l = *bl++ * *stain++ * scale;*out++ = min(l, 255);
388                                         l = *bl++ * *stain++ * scale;*out++ = min(l, 255);
389                                 }
390                         }
391                 }
392
393                 R_UpdateTexture(surface->lightmaptexture, templight);
394         }
395 }
396
397 void R_StainNode (mnode_t *node, model_t *model, const vec3_t origin, float radius, const float fcolor[8])
398 {
399         float ndist, a, ratio, maxdist, maxdist2, maxdist3, invradius, sdtable[256], td, dist2;
400         msurface_t *surface, *endsurface;
401         int i, s, t, smax, tmax, smax3, impacts, impactt, stained;
402         qbyte *bl;
403         vec3_t impact;
404
405         maxdist = radius * radius;
406         invradius = 1.0f / radius;
407
408 loc0:
409         if (!node->plane)
410                 return;
411         ndist = PlaneDiff(origin, node->plane);
412         if (ndist > radius)
413         {
414                 node = node->children[0];
415                 goto loc0;
416         }
417         if (ndist < -radius)
418         {
419                 node = node->children[1];
420                 goto loc0;
421         }
422
423         dist2 = ndist * ndist;
424         maxdist3 = maxdist - dist2;
425
426         if (node->plane->type < 3)
427         {
428                 VectorCopy(origin, impact);
429                 impact[node->plane->type] -= ndist;
430         }
431         else
432         {
433                 impact[0] = origin[0] - node->plane->normal[0] * ndist;
434                 impact[1] = origin[1] - node->plane->normal[1] * ndist;
435                 impact[2] = origin[2] - node->plane->normal[2] * ndist;
436         }
437
438         for (surface = model->brush.data_surfaces + node->firstsurface, endsurface = surface + node->numsurfaces;surface < endsurface;surface++)
439         {
440                 if (surface->stainsamples)
441                 {
442                         smax = (surface->extents[0] >> 4) + 1;
443                         tmax = (surface->extents[1] >> 4) + 1;
444
445                         impacts = DotProduct (impact, surface->texinfo->vecs[0]) + surface->texinfo->vecs[0][3] - surface->texturemins[0];
446                         impactt = DotProduct (impact, surface->texinfo->vecs[1]) + surface->texinfo->vecs[1][3] - surface->texturemins[1];
447
448                         s = bound(0, impacts, smax * 16) - impacts;
449                         t = bound(0, impactt, tmax * 16) - impactt;
450                         i = s * s + t * t + dist2;
451                         if (i > maxdist)
452                                 continue;
453
454                         // reduce calculations
455                         for (s = 0, i = impacts; s < smax; s++, i -= 16)
456                                 sdtable[s] = i * i + dist2;
457
458                         bl = surface->stainsamples;
459                         smax3 = smax * 3;
460                         stained = false;
461
462                         i = impactt;
463                         for (t = 0;t < tmax;t++, i -= 16)
464                         {
465                                 td = i * i;
466                                 // make sure some part of it is visible on this line
467                                 if (td < maxdist3)
468                                 {
469                                         maxdist2 = maxdist - td;
470                                         for (s = 0;s < smax;s++)
471                                         {
472                                                 if (sdtable[s] < maxdist2)
473                                                 {
474                                                         ratio = lhrandom(0.0f, 1.0f);
475                                                         a = (fcolor[3] + ratio * fcolor[7]) * (1.0f - sqrt(sdtable[s] + td) * invradius);
476                                                         if (a >= (1.0f / 64.0f))
477                                                         {
478                                                                 if (a > 1)
479                                                                         a = 1;
480                                                                 bl[0] = (qbyte) ((float) bl[0] + a * ((fcolor[0] + ratio * fcolor[4]) - (float) bl[0]));
481                                                                 bl[1] = (qbyte) ((float) bl[1] + a * ((fcolor[1] + ratio * fcolor[5]) - (float) bl[1]));
482                                                                 bl[2] = (qbyte) ((float) bl[2] + a * ((fcolor[2] + ratio * fcolor[6]) - (float) bl[2]));
483                                                                 stained = true;
484                                                         }
485                                                 }
486                                                 bl += 3;
487                                         }
488                                 }
489                                 else // skip line
490                                         bl += smax3;
491                         }
492                         // force lightmap upload
493                         if (stained)
494                                 surface->cached_dlight = true;
495                 }
496         }
497
498         if (node->children[0]->plane)
499         {
500                 if (node->children[1]->plane)
501                 {
502                         R_StainNode(node->children[0], model, origin, radius, fcolor);
503                         node = node->children[1];
504                         goto loc0;
505                 }
506                 else
507                 {
508                         node = node->children[0];
509                         goto loc0;
510                 }
511         }
512         else if (node->children[1]->plane)
513         {
514                 node = node->children[1];
515                 goto loc0;
516         }
517 }
518
519 void R_Stain (const vec3_t origin, float radius, int cr1, int cg1, int cb1, int ca1, int cr2, int cg2, int cb2, int ca2)
520 {
521         int n;
522         float fcolor[8];
523         entity_render_t *ent;
524         model_t *model;
525         vec3_t org;
526         if (r_refdef.worldmodel == NULL || !r_refdef.worldmodel->brush.data_nodes)
527                 return;
528         fcolor[0] = cr1;
529         fcolor[1] = cg1;
530         fcolor[2] = cb1;
531         fcolor[3] = ca1 * (1.0f / 64.0f);
532         fcolor[4] = cr2 - cr1;
533         fcolor[5] = cg2 - cg1;
534         fcolor[6] = cb2 - cb1;
535         fcolor[7] = (ca2 - ca1) * (1.0f / 64.0f);
536
537         R_StainNode(r_refdef.worldmodel->brush.data_nodes + r_refdef.worldmodel->brushq1.hulls[0].firstclipnode, r_refdef.worldmodel, origin, radius, fcolor);
538
539         // look for embedded bmodels
540         for (n = 0;n < cl_num_brushmodel_entities;n++)
541         {
542                 ent = cl_brushmodel_entities[n];
543                 model = ent->model;
544                 if (model && model->name[0] == '*')
545                 {
546                         Mod_CheckLoaded(model);
547                         if (model->brush.data_nodes)
548                         {
549                                 Matrix4x4_Transform(&ent->inversematrix, origin, org);
550                                 R_StainNode(model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode, model, org, radius, fcolor);
551                         }
552                 }
553         }
554 }
555
556
557 /*
558 =============================================================
559
560         BRUSH MODELS
561
562 =============================================================
563 */
564
565 static void RSurf_AddLightmapToVertexColors_Color4f(const int *lightmapoffsets, float *c, int numverts, const qbyte *samples, int size3, const qbyte *styles)
566 {
567         int i;
568         float scale;
569         const qbyte *lm;
570         if (styles[0] != 255)
571         {
572                 for (i = 0;i < numverts;i++, c += 4)
573                 {
574                         lm = samples + lightmapoffsets[i];
575                         scale = d_lightstylevalue[styles[0]] * (1.0f / 32768.0f);
576                         VectorMA(c, scale, lm, c);
577                         if (styles[1] != 255)
578                         {
579                                 lm += size3;
580                                 scale = d_lightstylevalue[styles[1]] * (1.0f / 32768.0f);
581                                 VectorMA(c, scale, lm, c);
582                                 if (styles[2] != 255)
583                                 {
584                                         lm += size3;
585                                         scale = d_lightstylevalue[styles[2]] * (1.0f / 32768.0f);
586                                         VectorMA(c, scale, lm, c);
587                                         if (styles[3] != 255)
588                                         {
589                                                 lm += size3;
590                                                 scale = d_lightstylevalue[styles[3]] * (1.0f / 32768.0f);
591                                                 VectorMA(c, scale, lm, c);
592                                         }
593                                 }
594                         }
595                 }
596         }
597 }
598
599 static void RSurf_FogColors_Vertex3f_Color4f(const float *v, float *c, float colorscale, int numverts, const float *modelorg)
600 {
601         int i;
602         float diff[3], f;
603         if (fogenabled)
604         {
605                 for (i = 0;i < numverts;i++, v += 3, c += 4)
606                 {
607                         VectorSubtract(v, modelorg, diff);
608                         f = colorscale * (1 - exp(fogdensity/DotProduct(diff, diff)));
609                         VectorScale(c, f, c);
610                 }
611         }
612         else if (colorscale != 1)
613                 for (i = 0;i < numverts;i++, c += 4)
614                         VectorScale(c, colorscale, c);
615 }
616
617 static void RSurf_FoggedColors_Vertex3f_Color4f(const float *v, float *c, float r, float g, float b, float a, float colorscale, int numverts, const float *modelorg)
618 {
619         int i;
620         float diff[3], f;
621         r *= colorscale;
622         g *= colorscale;
623         b *= colorscale;
624         if (fogenabled)
625         {
626                 for (i = 0;i < numverts;i++, v += 3, c += 4)
627                 {
628                         VectorSubtract(v, modelorg, diff);
629                         f = 1 - exp(fogdensity/DotProduct(diff, diff));
630                         c[0] = r * f;
631                         c[1] = g * f;
632                         c[2] = b * f;
633                         c[3] = a;
634                 }
635         }
636         else
637         {
638                 for (i = 0;i < numverts;i++, c += 4)
639                 {
640                         c[0] = r;
641                         c[1] = g;
642                         c[2] = b;
643                         c[3] = a;
644                 }
645         }
646 }
647
648 static void RSurf_FogPassColors_Vertex3f_Color4f(const float *v, float *c, float r, float g, float b, float a, float colorscale, int numverts, const float *modelorg)
649 {
650         int i;
651         float diff[3], f;
652         r *= colorscale;
653         g *= colorscale;
654         b *= colorscale;
655         for (i = 0;i < numverts;i++, v += 3, c += 4)
656         {
657                 VectorSubtract(v, modelorg, diff);
658                 f = exp(fogdensity/DotProduct(diff, diff));
659                 c[0] = r;
660                 c[1] = g;
661                 c[2] = b;
662                 c[3] = a * f;
663         }
664 }
665
666 static int RSurf_LightSeparate_Vertex3f_Color4f(const matrix4x4_t *matrix, const int *dlightbits, int numverts, const float *vert, float *color, float scale)
667 {
668         float f;
669         const float *v;
670         float *c;
671         int i, l, lit = false;
672         const dlight_t *light;
673         vec3_t lightorigin;
674         for (l = 0;l < r_numdlights;l++)
675         {
676                 if (dlightbits[l >> 5] & (1 << (l & 31)))
677                 {
678                         light = &r_dlight[l];
679                         Matrix4x4_Transform(matrix, light->origin, lightorigin);
680                         for (i = 0, v = vert, c = color;i < numverts;i++, v += 3, c += 4)
681                         {
682                                 f = VectorDistance2(v, lightorigin) + LIGHTOFFSET;
683                                 if (f < light->rtlight.lightmap_cullradius2)
684                                 {
685                                         f = ((1.0f / f) - light->rtlight.lightmap_subtract) * scale;
686                                         VectorMA(c, f, light->rtlight.lightmap_light, c);
687                                         lit = true;
688                                 }
689                         }
690                 }
691         }
692         return lit;
693 }
694
695 void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t)
696 {
697         t->currentmaterialflags = t->basematerialflags;
698         t->currentalpha = ent->alpha;
699         if (t->basematerialflags & MATERIALFLAG_WATERALPHA)
700                 t->currentalpha *= r_wateralpha.value;
701         if (ent->effects & EF_ADDITIVE)
702                 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_TRANSPARENT;
703         if (t->currentalpha < 1 || t->skin.fog != NULL)
704                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_TRANSPARENT;
705         // we don't need to set currentframe if t->animated is false because
706         // it was already set up by the texture loader for non-animating
707         if (t->animated)
708                 t->currentframe = t->anim_frames[ent->frame != 0][(t->anim_total[ent->frame != 0] >= 2) ? ((int)(r_refdef.time * 5.0f) % t->anim_total[ent->frame != 0]) : 0];
709 }
710
711 void R_UpdateAllTextureInfo(entity_render_t *ent)
712 {
713         int i;
714         if (ent->model)
715                 for (i = 0;i < ent->model->brush.num_textures;i++)
716                         R_UpdateTextureInfo(ent, ent->model->brush.data_textures + i);
717 }
718
719 static void RSurfShader_Transparent_Callback(const void *calldata1, int calldata2)
720 {
721         const entity_render_t *ent = calldata1;
722         const msurface_t *surface = ent->model->brush.data_surfaces + calldata2;
723         rmeshstate_t m;
724         float base, colorscale;
725         vec3_t modelorg;
726         texture_t *texture;
727         float args[4] = {0.05f,0,0,0.04f};
728         int turb, fullbright;
729
730         texture = surface->texture;
731         R_UpdateTextureInfo(ent, texture);
732         if (texture->currentmaterialflags & MATERIALFLAG_SKY)
733                 return; // transparent sky is too difficult
734
735         R_Mesh_Matrix(&ent->matrix);
736         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg);
737
738         GL_DepthTest(!(texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
739         GL_DepthMask(!(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT));
740         if (texture->currentmaterialflags & MATERIALFLAG_ADD)
741                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
742         else if (texture->currentmaterialflags & MATERIALFLAG_ALPHA)
743                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
744         else
745                 GL_BlendFunc(GL_ONE, GL_ZERO);
746
747         turb = texture->currentmaterialflags & MATERIALFLAG_WATER && r_waterscroll.value;
748         fullbright = !(ent->flags & RENDER_LIGHT) || (texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !surface->samples;
749         base = fullbright ? 2.0f : r_ambient.value * (1.0f / 64.0f);
750         if (texture->currentmaterialflags & MATERIALFLAG_WATER)
751                 base *= 0.5f;
752         if (texture->currentmaterialflags & MATERIALFLAG_WATER && gl_textureshader && r_watershader.value && !fogenabled && fullbright && ent->colormod[0] == 1 && ent->colormod[1] == 1 && ent->colormod[2] == 1)
753         {
754                 // NVIDIA Geforce3 distortion texture shader on water
755                 GL_Color(1, 1, 1, texture->currentalpha);
756                 memset(&m, 0, sizeof(m));
757                 m.pointer_vertex = surface->mesh.data_vertex3f;
758                 m.tex[0] = R_GetTexture(mod_shared_distorttexture[(int)(r_refdef.time * 16)&63]);
759                 m.tex[1] = R_GetTexture(texture->skin.base);
760                 m.texcombinergb[0] = GL_REPLACE;
761                 m.texcombinergb[1] = GL_REPLACE;
762                 m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
763                 m.pointer_texcoord[1] = surface->mesh.data_texcoordtexture2f;
764                 Matrix4x4_CreateFromQuakeEntity(&m.texmatrix[0], 0, 0, 0, 0, 0, 0, r_watershader.value);
765                 Matrix4x4_CreateTranslate(&m.texmatrix[1], sin(r_refdef.time) * 0.025 * r_waterscroll.value, sin(r_refdef.time * 0.8f) * 0.025 * r_waterscroll.value, 0);
766                 R_Mesh_State(&m);
767
768                 GL_ActiveTexture(0);
769                 qglTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_2D);
770                 GL_ActiveTexture(1);
771                 qglTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_OFFSET_TEXTURE_2D_NV);
772                 qglTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, GL_TEXTURE0_ARB);
773                 qglTexEnvfv(GL_TEXTURE_SHADER_NV, GL_OFFSET_TEXTURE_MATRIX_NV, &args[0]);
774                 qglEnable(GL_TEXTURE_SHADER_NV);
775
776                 GL_LockArrays(0, surface->mesh.num_vertices);
777                 R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
778                 GL_LockArrays(0, 0);
779
780                 qglDisable(GL_TEXTURE_SHADER_NV);
781                 qglTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_2D);
782                 GL_ActiveTexture(0);
783         }
784         else
785         {
786                 memset(&m, 0, sizeof(m));
787                 m.pointer_vertex = surface->mesh.data_vertex3f;
788                 m.pointer_color = varray_color4f;
789                 m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
790                 m.tex[0] = R_GetTexture(texture->skin.base);
791                 if (turb)
792                 {
793                         // scrolling in texture matrix
794                         Matrix4x4_CreateTranslate(&m.texmatrix[0], sin(r_refdef.time) * 0.025 * r_waterscroll.value, sin(r_refdef.time * 0.8f) * 0.025 * r_waterscroll.value, 0);
795                 }
796                 colorscale = 1;
797                 if (gl_combine.integer)
798                 {
799                         m.texrgbscale[0] = 4;
800                         colorscale *= 0.25f;
801                 }
802                 R_FillColors(varray_color4f, surface->mesh.num_vertices, base * ent->colormod[0], base * ent->colormod[1], base * ent->colormod[2], texture->currentalpha);
803                 if (!fullbright)
804                 {
805                         if (surface->dlightframe == r_framecount)
806                                 RSurf_LightSeparate_Vertex3f_Color4f(&ent->inversematrix, surface->dlightbits, surface->mesh.num_vertices, surface->mesh.data_vertex3f, varray_color4f, 1);
807                         if (surface->samples)
808                                 RSurf_AddLightmapToVertexColors_Color4f(surface->mesh.data_lightmapoffsets, varray_color4f,surface->mesh.num_vertices, surface->samples, ((surface->extents[0]>>4)+1)*((surface->extents[1]>>4)+1)*3, surface->styles);
809                 }
810                 RSurf_FogColors_Vertex3f_Color4f(surface->mesh.data_vertex3f, varray_color4f, colorscale, surface->mesh.num_vertices, modelorg);
811                 R_Mesh_State(&m);
812                 GL_LockArrays(0, surface->mesh.num_vertices);
813                 R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
814                 GL_LockArrays(0, 0);
815                 if (texture->skin.glow)
816                 {
817                         memset(&m, 0, sizeof(m));
818                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
819                         GL_DepthMask(false);
820                         m.pointer_color = varray_color4f;
821                         m.tex[0] = R_GetTexture(texture->skin.glow);
822                         m.pointer_vertex = surface->mesh.data_vertex3f;
823                         if (m.tex[0])
824                         {
825                                 m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
826                                 if (turb)
827                                 {
828                                         // scrolling in texture matrix
829                                         Matrix4x4_CreateTranslate(&m.texmatrix[0], sin(r_refdef.time) * 0.025 * r_waterscroll.value, sin(r_refdef.time * 0.8f) * 0.025 * r_waterscroll.value, 0);
830                                 }
831                         }
832                         R_Mesh_State(&m);
833                         RSurf_FoggedColors_Vertex3f_Color4f(surface->mesh.data_vertex3f, varray_color4f, 1, 1, 1, texture->currentalpha, 1, surface->mesh.num_vertices, modelorg);
834                         GL_LockArrays(0, surface->mesh.num_vertices);
835                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
836                         GL_LockArrays(0, 0);
837                 }
838                 if (fogenabled && !(texture->currentmaterialflags & MATERIALFLAG_ADD))
839                 {
840                         memset(&m, 0, sizeof(m));
841                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
842                         GL_DepthMask(false);
843                         m.pointer_color = varray_color4f;
844                         m.tex[0] = R_GetTexture(texture->skin.fog);
845                         m.pointer_vertex = surface->mesh.data_vertex3f;
846                         if (m.tex[0])
847                         {
848                                 m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
849                                 if (turb)
850                                 {
851                                         // scrolling in texture matrix
852                                         Matrix4x4_CreateTranslate(&m.texmatrix[0], sin(r_refdef.time) * 0.025 * r_waterscroll.value, sin(r_refdef.time * 0.8f) * 0.025 * r_waterscroll.value, 0);
853                                 }
854                         }
855                         R_Mesh_State(&m);
856                         RSurf_FogPassColors_Vertex3f_Color4f(surface->mesh.data_vertex3f, varray_color4f, fogcolor[0], fogcolor[1], fogcolor[2], texture->currentalpha, 1, surface->mesh.num_vertices, modelorg);
857                         GL_LockArrays(0, surface->mesh.num_vertices);
858                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
859                         GL_LockArrays(0, 0);
860                 }
861         }
862 }
863
864 void R_DrawSurfaceList(entity_render_t *ent, texture_t *texture, int texturenumsurfaces, msurface_t **texturesurfacelist)
865 {
866         int texturesurfaceindex;
867         vec3_t tempcenter, center, modelorg;
868         msurface_t *surface;
869         qboolean dolightmap;
870         qboolean dobase;
871         qboolean doambient;
872         qboolean dodetail;
873         qboolean doglow;
874         qboolean dofog;
875         rmeshstate_t m;
876         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg);
877         c_faces += texturenumsurfaces;
878         // gl_lightmaps debugging mode skips normal texturing
879         if (gl_lightmaps.integer)
880         {
881                 GL_BlendFunc(GL_ONE, GL_ZERO);
882                 GL_DepthMask(true);
883                 GL_DepthTest(true);
884                 qglDisable(GL_CULL_FACE);
885                 GL_Color(1, 1, 1, 1);
886                 memset(&m, 0, sizeof(m));
887                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
888                 {
889                         surface = texturesurfacelist[texturesurfaceindex];
890                         m.tex[0] = R_GetTexture(surface->lightmaptexture);
891                         m.pointer_texcoord[0] = surface->mesh.data_texcoordlightmap2f;
892                         if (surface->lightmaptexture)
893                         {
894                                 GL_Color(1, 1, 1, 1);
895                                 m.pointer_color = NULL;
896                         }
897                         else
898                                 m.pointer_color = surface->mesh.data_lightmapcolor4f;
899                         m.pointer_vertex = surface->mesh.data_vertex3f;
900                         R_Mesh_State(&m);
901                         GL_LockArrays(0, surface->mesh.num_vertices);
902                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
903                         GL_LockArrays(0, 0);
904                 }
905                 qglEnable(GL_CULL_FACE);
906                 return;
907         }
908         // transparent surfaces get sorted for later drawing
909         if (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT)
910         {
911                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
912                 {
913                         surface = texturesurfacelist[texturesurfaceindex];
914                         tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
915                         tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
916                         tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
917                         Matrix4x4_Transform(&ent->matrix, tempcenter, center);
918                         R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_vieworigin : center, RSurfShader_Transparent_Callback, ent, surface - ent->model->brush.data_surfaces);
919                 }
920                 return;
921         }
922         if (texture->currentmaterialflags & MATERIALFLAG_WALL)
923         {
924                 dolightmap = (ent->flags & RENDER_LIGHT);
925                 dobase = true;
926                 doambient = r_ambient.value > 0;
927                 dodetail = texture->skin.detail != NULL && r_detailtextures.integer != 0;
928                 doglow = texture->skin.glow != NULL;
929                 dofog = fogenabled;
930                 // multitexture cases
931                 if (r_textureunits.integer >= 2 && gl_combine.integer && dobase && dolightmap)
932                 {
933                         GL_BlendFunc(GL_ONE, GL_ZERO);
934                         GL_DepthMask(true);
935                         GL_DepthTest(true);
936                         GL_Color(1, 1, 1, 1);
937                         GL_Color(r_lightmapintensity * ent->colormod[0], r_lightmapintensity * ent->colormod[1], r_lightmapintensity * ent->colormod[2], 1);
938                         memset(&m, 0, sizeof(m));
939                         m.tex[0] = R_GetTexture(texture->skin.base);
940                         dobase = false;
941                         m.texrgbscale[1] = 2;
942                         dolightmap = false;
943                         if (r_textureunits.integer >= 4 && !doambient && dodetail && doglow)
944                         {
945                                 m.tex[2] = R_GetTexture(texture->skin.detail);
946                                 m.texrgbscale[2] = 2;
947                                 dodetail = false;
948                                 m.tex[3] = R_GetTexture(texture->skin.glow);
949                                 m.texcombinergb[3] = GL_ADD;
950                                 doglow = false;
951                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
952                                 {
953                                         surface = texturesurfacelist[texturesurfaceindex];
954                                         m.tex[1] = R_GetTexture(surface->lightmaptexture);
955                                         m.pointer_vertex = surface->mesh.data_vertex3f;
956                                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
957                                         m.pointer_texcoord[1] = surface->mesh.data_texcoordlightmap2f;
958                                         m.pointer_texcoord[2] = surface->mesh.data_texcoorddetail2f;
959                                         m.pointer_texcoord[3] = surface->mesh.data_texcoordtexture2f;
960                                         R_Mesh_State(&m);
961                                         GL_LockArrays(0, surface->mesh.num_vertices);
962                                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
963                                         GL_LockArrays(0, 0);
964                                 }
965                         }
966                         else if (r_textureunits.integer >= 3 && !doambient && dodetail)
967                         {
968                                 m.tex[2] = R_GetTexture(texture->skin.detail);
969                                 m.texrgbscale[2] = 2;
970                                 dodetail = false;
971                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
972                                 {
973                                         surface = texturesurfacelist[texturesurfaceindex];
974                                         m.tex[1] = R_GetTexture(surface->lightmaptexture);
975                                         m.pointer_vertex = surface->mesh.data_vertex3f;
976                                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
977                                         m.pointer_texcoord[1] = surface->mesh.data_texcoordlightmap2f;
978                                         m.pointer_texcoord[2] = surface->mesh.data_texcoorddetail2f;
979                                         R_Mesh_State(&m);
980                                         GL_LockArrays(0, surface->mesh.num_vertices);
981                                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
982                                         GL_LockArrays(0, 0);
983                                 }
984                         }
985                         else if (r_textureunits.integer >= 3 && !doambient && !dodetail && doglow)
986                         {
987                                 m.tex[2] = R_GetTexture(texture->skin.glow);
988                                 m.texcombinergb[2] = GL_ADD;
989                                 doglow = false;
990                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
991                                 {
992                                         surface = texturesurfacelist[texturesurfaceindex];
993                                         m.tex[1] = R_GetTexture(surface->lightmaptexture);
994                                         m.pointer_vertex = surface->mesh.data_vertex3f;
995                                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
996                                         m.pointer_texcoord[1] = surface->mesh.data_texcoordlightmap2f;
997                                         m.pointer_texcoord[2] = surface->mesh.data_texcoordtexture2f;
998                                         R_Mesh_State(&m);
999                                         GL_LockArrays(0, surface->mesh.num_vertices);
1000                                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1001                                         GL_LockArrays(0, 0);
1002                                 }
1003                         }
1004                         else
1005                         {
1006                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1007                                 {
1008                                         surface = texturesurfacelist[texturesurfaceindex];
1009                                         m.tex[1] = R_GetTexture(surface->lightmaptexture);
1010                                         m.pointer_vertex = surface->mesh.data_vertex3f;
1011                                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
1012                                         m.pointer_texcoord[1] = surface->mesh.data_texcoordlightmap2f;
1013                                         R_Mesh_State(&m);
1014                                         GL_LockArrays(0, surface->mesh.num_vertices);
1015                                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1016                                         GL_LockArrays(0, 0);
1017                                 }
1018                         }
1019                 }
1020                 // anything not handled above
1021                 if (dobase)
1022                 {
1023                         GL_BlendFunc(GL_ONE, GL_ZERO);
1024                         GL_DepthMask(true);
1025                         GL_DepthTest(true);
1026                         GL_Color(1, 1, 1, 1);
1027                         if (ent->flags & RENDER_LIGHT)
1028                                 GL_Color(r_lightmapintensity * ent->colormod[0], r_lightmapintensity * ent->colormod[1], r_lightmapintensity * ent->colormod[2], 1);
1029                         else
1030                                 GL_Color(ent->colormod[0], ent->colormod[1], ent->colormod[2], 1);
1031                         memset(&m, 0, sizeof(m));
1032                         m.tex[0] = R_GetTexture(texture->skin.base);
1033                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1034                         {
1035                                 surface = texturesurfacelist[texturesurfaceindex];
1036                                 m.pointer_vertex = surface->mesh.data_vertex3f;
1037                                 m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
1038                                 R_Mesh_State(&m);
1039                                 GL_LockArrays(0, surface->mesh.num_vertices);
1040                                 R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1041                                 GL_LockArrays(0, 0);
1042                         }
1043                 }
1044                 GL_DepthMask(false);
1045                 if (dolightmap)
1046                 {
1047                         GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
1048                         GL_DepthMask(false);
1049                         GL_DepthTest(true);
1050                         GL_Color(1, 1, 1, 1);
1051                         memset(&m, 0, sizeof(m));
1052                         m.tex[0] = R_GetTexture(texture->skin.base);
1053                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1054                         {
1055                                 surface = texturesurfacelist[texturesurfaceindex];
1056                                 m.tex[0] = R_GetTexture(surface->lightmaptexture);
1057                                 m.pointer_vertex = surface->mesh.data_vertex3f;
1058                                 m.pointer_texcoord[0] = surface->mesh.data_texcoordlightmap2f;
1059                                 R_Mesh_State(&m);
1060                                 GL_LockArrays(0, surface->mesh.num_vertices);
1061                                 R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1062                                 GL_LockArrays(0, 0);
1063                         }
1064                 }
1065                 if (doambient)
1066                 {
1067                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1068                         GL_DepthMask(false);
1069                         GL_DepthTest(true);
1070                         memset(&m, 0, sizeof(m));
1071                         GL_Color(r_ambient.value * (1.0f / 128.0f) * ent->colormod[0], r_ambient.value * (1.0f / 128.0f) * ent->colormod[1], r_ambient.value * (1.0f / 128.0f) * ent->colormod[2], 1);
1072                         m.tex[0] = R_GetTexture(texture->skin.base);
1073                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1074                         {
1075                                 surface = texturesurfacelist[texturesurfaceindex];
1076                                 m.pointer_vertex = surface->mesh.data_vertex3f;
1077                                 m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
1078                                 R_Mesh_State(&m);
1079                                 GL_LockArrays(0, surface->mesh.num_vertices);
1080                                 R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1081                                 GL_LockArrays(0, 0);
1082                         }
1083                 }
1084                 if (dodetail)
1085                 {
1086                         GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
1087                         GL_DepthMask(false);
1088                         GL_DepthTest(true);
1089                         GL_Color(1, 1, 1, 1);
1090                         memset(&m, 0, sizeof(m));
1091                         m.tex[0] = R_GetTexture(texture->skin.detail);
1092                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1093                         {
1094                                 surface = texturesurfacelist[texturesurfaceindex];
1095                                 m.pointer_vertex = surface->mesh.data_vertex3f;
1096                                 m.pointer_texcoord[0] = surface->mesh.data_texcoorddetail2f;
1097                                 R_Mesh_State(&m);
1098                                 GL_LockArrays(0, surface->mesh.num_vertices);
1099                                 R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1100                                 GL_LockArrays(0, 0);
1101                         }
1102                 }
1103                 if (doglow)
1104                 {
1105                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1106                         GL_DepthMask(false);
1107                         GL_DepthTest(true);
1108                         GL_Color(1, 1, 1, 1);
1109                         memset(&m, 0, sizeof(m));
1110                         m.tex[0] = R_GetTexture(texture->skin.glow);
1111                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1112                         {
1113                                 surface = texturesurfacelist[texturesurfaceindex];
1114                                 m.pointer_vertex = surface->mesh.data_vertex3f;
1115                                 m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
1116                                 R_Mesh_State(&m);
1117                                 GL_LockArrays(0, surface->mesh.num_vertices);
1118                                 R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1119                                 GL_LockArrays(0, 0);
1120                         }
1121                 }
1122                 if (dofog)
1123                 {
1124                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1125                         GL_DepthMask(false);
1126                         GL_DepthTest(true);
1127                         memset(&m, 0, sizeof(m));
1128                         m.pointer_color = varray_color4f;
1129                         m.tex[0] = R_GetTexture(texture->skin.glow);
1130                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1131                         {
1132                                 surface = texturesurfacelist[texturesurfaceindex];
1133                                 m.pointer_vertex = surface->mesh.data_vertex3f;
1134                                 if (m.tex[0])
1135                                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
1136                                 R_Mesh_State(&m);
1137                                 RSurf_FogPassColors_Vertex3f_Color4f(surface->mesh.data_vertex3f, varray_color4f, fogcolor[0], fogcolor[1], fogcolor[2], 1, 1, surface->mesh.num_vertices, modelorg);
1138                                 GL_LockArrays(0, surface->mesh.num_vertices);
1139                                 R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1140                                 GL_LockArrays(0, 0);
1141                         }
1142                 }
1143                 return;
1144         }
1145         if (texture->currentmaterialflags & MATERIALFLAG_WATER)
1146         {
1147                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1148                 {
1149                         surface = texturesurfacelist[texturesurfaceindex];
1150                         RSurfShader_Transparent_Callback(ent, surface - ent->model->brush.data_surfaces);
1151                 }
1152                 return;
1153         }
1154         if (texture->currentmaterialflags & MATERIALFLAG_SKY)
1155         {
1156                 if (skyrendernow)
1157                 {
1158                         skyrendernow = false;
1159                         if (skyrendermasked)
1160                                 R_Sky();
1161                 }
1162                 // LordHavoc: HalfLife maps have freaky skypolys...
1163                 if (!ent->model->brush.ishlbsp)
1164                 {
1165                         R_Mesh_Matrix(&ent->matrix);
1166                         GL_Color(fogcolor[0], fogcolor[1], fogcolor[2], 1);
1167                         if (skyrendermasked)
1168                         {
1169                                 // depth-only (masking)
1170                                 GL_ColorMask(0,0,0,0);
1171                                 // just to make sure that braindead drivers don't draw anything
1172                                 // despite that colormask...
1173                                 GL_BlendFunc(GL_ZERO, GL_ONE);
1174                         }
1175                         else
1176                         {
1177                                 // fog sky
1178                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1179                         }
1180                         GL_DepthMask(true);
1181                         GL_DepthTest(true);
1182                         memset(&m, 0, sizeof(m));
1183                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1184                         {
1185                                 surface = texturesurfacelist[texturesurfaceindex];
1186                                 m.pointer_vertex = surface->mesh.data_vertex3f;
1187                                 R_Mesh_State(&m);
1188                                 GL_LockArrays(0, surface->mesh.num_vertices);
1189                                 R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1190                                 GL_LockArrays(0, 0);
1191                         }
1192                         GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1193                 }
1194                 return;
1195         }
1196 }
1197
1198 void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces)
1199 {
1200         int i, j, f, flagsmask;
1201         msurface_t *surface, **surfacechain;
1202         texture_t *t, *texture;
1203         model_t *model = ent->model;
1204         vec3_t modelorg;
1205         const int maxsurfacelist = 1024;
1206         int numsurfacelist = 0;
1207         msurface_t *surfacelist[1024];
1208         if (model == NULL)
1209                 return;
1210         R_Mesh_Matrix(&ent->matrix);
1211         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg);
1212
1213         if (ent != r_refdef.worldentity)
1214         {
1215                 // because bmodels can be reused, we have to clear dlightframe every time
1216                 surface = model->brush.data_surfaces + model->firstmodelsurface;
1217                 for (i = 0;i < model->nummodelsurfaces;i++, surface++)
1218                         surface->dlightframe = -1;
1219         }
1220
1221         // update light styles
1222         if (!skysurfaces)
1223         {
1224                 if (r_dynamic.integer && !r_rtdlight)
1225                         R_MarkLights(ent);
1226                 for (i = 0;i < model->brushq1.light_styles;i++)
1227                 {
1228                         if (model->brushq1.light_stylevalue[i] != d_lightstylevalue[model->brushq1.light_style[i]])
1229                         {
1230                                 model->brushq1.light_stylevalue[i] = d_lightstylevalue[model->brushq1.light_style[i]];
1231                                 if ((surfacechain = model->brushq1.light_styleupdatechains[i]))
1232                                         for (;(surface = *surfacechain);surfacechain++)
1233                                                 surface->cached_dlight = true;
1234                         }
1235                 }
1236         }
1237
1238         R_UpdateAllTextureInfo(ent);
1239         flagsmask = skysurfaces ? MATERIALFLAG_SKY : (MATERIALFLAG_WATER | MATERIALFLAG_WALL);
1240         f = 0;
1241         t = NULL;
1242         numsurfacelist = 0;
1243         for (i = 0, j = model->firstmodelsurface;i < model->nummodelsurfaces;i++, j++)
1244         {
1245                 if (ent != r_refdef.worldentity || r_worldsurfacevisible[j])
1246                 {
1247                         surface = model->brush.data_surfaces + j;
1248                         if (t != surface->texture)
1249                         {
1250                                 if (numsurfacelist)
1251                                 {
1252                                         R_DrawSurfaceList(ent, texture, numsurfacelist, surfacelist);
1253                                         numsurfacelist = 0;
1254                                 }
1255                                 t = surface->texture;
1256                                 f = t->currentmaterialflags & flagsmask;
1257                                 texture = t->currentframe;
1258                         }
1259                         if (f)
1260                         {
1261                                 // add face to draw list and update lightmap if necessary
1262                                 if (surface->cached_dlight && surface->lightmaptexture != NULL)
1263                                         R_BuildLightMap(ent, surface);
1264                                 surfacelist[numsurfacelist++] = surface;
1265                                 if (numsurfacelist >= maxsurfacelist)
1266                                 {
1267                                         R_DrawSurfaceList(ent, texture, numsurfacelist, surfacelist);
1268                                         numsurfacelist = 0;
1269                                 }
1270                         }
1271                 }
1272         }
1273         if (numsurfacelist)
1274                 R_DrawSurfaceList(ent, texture, numsurfacelist, surfacelist);
1275 }
1276
1277 static void R_DrawPortal_Callback(const void *calldata1, int calldata2)
1278 {
1279         int i;
1280         float *v;
1281         rmeshstate_t m;
1282         const mportal_t *portal = calldata1;
1283         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1284         GL_DepthMask(false);
1285         GL_DepthTest(true);
1286         R_Mesh_Matrix(&r_identitymatrix);
1287
1288         memset(&m, 0, sizeof(m));
1289         m.pointer_vertex = varray_vertex3f;
1290         R_Mesh_State(&m);
1291
1292         i = calldata2;
1293         GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f),
1294                          ((i & 0x0038) >> 3) * (1.0f / 7.0f),
1295                          ((i & 0x01C0) >> 6) * (1.0f / 7.0f),
1296                          0.125f);
1297         if (PlaneDiff(r_vieworigin, (&portal->plane)) < 0)
1298         {
1299                 for (i = portal->numpoints - 1, v = varray_vertex3f;i >= 0;i--, v += 3)
1300                         VectorCopy(portal->points[i].position, v);
1301         }
1302         else
1303                 for (i = 0, v = varray_vertex3f;i < portal->numpoints;i++, v += 3)
1304                         VectorCopy(portal->points[i].position, v);
1305         GL_LockArrays(0, portal->numpoints);
1306         R_Mesh_Draw(portal->numpoints, portal->numpoints - 2, polygonelements);
1307         GL_LockArrays(0, 0);
1308 }
1309
1310 // LordHavoc: this is just a nice debugging tool, very slow
1311 static void R_DrawPortals(void)
1312 {
1313         int i, portalnum;
1314         mportal_t *portal;
1315         float center[3], f;
1316         model_t *model = r_refdef.worldmodel;
1317         if (model == NULL)
1318                 return;
1319         for (portalnum = 0, portal = model->brush.data_portals;portalnum < model->brush.num_portals;portalnum++, portal++)
1320         {
1321                 if (portal->numpoints <= POLYGONELEMENTS_MAXPOINTS)
1322                 if (!R_CullBox(portal->mins, portal->maxs))
1323                 {
1324                         VectorClear(center);
1325                         for (i = 0;i < portal->numpoints;i++)
1326                                 VectorAdd(center, portal->points[i].position, center);
1327                         f = ixtable[portal->numpoints];
1328                         VectorScale(center, f, center);
1329                         R_MeshQueue_AddTransparent(center, R_DrawPortal_Callback, portal, portalnum);
1330                 }
1331         }
1332 }
1333
1334 void R_WorldVisibility(void)
1335 {
1336         int i, j, *mark;
1337         mleaf_t *leaf;
1338         mleaf_t *viewleaf;
1339         model_t *model = r_refdef.worldmodel;
1340
1341         if (!model)
1342                 return;
1343
1344         // if possible find the leaf the view origin is in
1345         viewleaf = model->brushq1.PointInLeaf ? model->brushq1.PointInLeaf(model, r_vieworigin) : NULL;
1346         // if possible fetch the visible cluster bits
1347         if (model->brush.FatPVS)
1348                 model->brush.FatPVS(model, r_vieworigin, 2, r_pvsbits, sizeof(r_pvsbits));
1349
1350         // clear the visible surface and leaf flags arrays
1351         memset(r_worldsurfacevisible, 0, model->brush.num_surfaces);
1352         memset(r_worldleafvisible, 0, model->brush.num_leafs);
1353
1354         // if the user prefers surfaceworldnode (testing?) or the viewleaf could
1355         // not be found, or the viewleaf is not part of the visible world
1356         // (floating around in the void), use the pvs method
1357         if (r_surfaceworldnode.integer || !viewleaf || viewleaf->clusterindex < 0)
1358         {
1359                 // pvs method:
1360                 // similar to quake's RecursiveWorldNode but without cache misses
1361                 for (j = 0, leaf = model->brush.data_leafs;j < model->brush.num_leafs;j++, leaf++)
1362                 {
1363                         // if leaf is in current pvs and on the screen, mark its surfaces
1364                         if (CHECKPVSBIT(r_pvsbits, leaf->clusterindex) && !R_CullBox(leaf->mins, leaf->maxs))
1365                         {
1366                                 c_leafs++;
1367                                 r_worldleafvisible[j] = true;
1368                                 if (leaf->numleafsurfaces)
1369                                         for (i = 0, mark = leaf->firstleafsurface;i < leaf->numleafsurfaces;i++, mark++)
1370                                                 r_worldsurfacevisible[*mark] = true;
1371                         }
1372                 }
1373         }
1374         else
1375         {
1376                 int leafstackpos;
1377                 mportal_t *p;
1378                 mleaf_t *leafstack[8192];
1379                 // portal method:
1380                 // follows portals leading outward from viewleaf, does not venture
1381                 // offscreen or into leafs that are not visible, faster than Quake's
1382                 // RecursiveWorldNode and vastly better in unvised maps, often culls a
1383                 // lot of surface that pvs alone would miss
1384                 leafstack[0] = viewleaf;
1385                 leafstackpos = 1;
1386                 while (leafstackpos)
1387                 {
1388                         c_leafs++;
1389                         leaf = leafstack[--leafstackpos];
1390                         r_worldleafvisible[leaf - model->brush.data_leafs] = true;
1391                         // mark any surfaces bounding this leaf
1392                         if (leaf->numleafsurfaces)
1393                                 for (i = 0, mark = leaf->firstleafsurface;i < leaf->numleafsurfaces;i++, mark++)
1394                                         r_worldsurfacevisible[*mark] = true;
1395                         // follow portals into other leafs
1396                         // the checks are:
1397                         // if viewer is behind portal (portal faces outward into the scene)
1398                         // and the portal polygon's bounding box is on the screen
1399                         // and the leaf has not been visited yet
1400                         // and the leaf is visible in the pvs
1401                         // (the first two checks won't cause as many cache misses as the leaf checks)
1402                         for (p = leaf->portals;p;p = p->next)
1403                                 if (DotProduct(r_vieworigin, p->plane.normal) < (p->plane.dist + 1) && !R_CullBox(p->mins, p->maxs) && !r_worldleafvisible[p->past - model->brush.data_leafs] && CHECKPVSBIT(r_pvsbits, p->past->clusterindex))
1404                                         leafstack[leafstackpos++] = p->past;
1405                 }
1406         }
1407
1408         if (r_drawportals.integer)
1409                 R_DrawPortals();
1410 }
1411
1412 void R_Q1BSP_DrawSky(entity_render_t *ent)
1413 {
1414         if (ent->model == NULL)
1415                 return;
1416         if (r_drawcollisionbrushes.integer < 2)
1417                 R_DrawSurfaces(ent, true);
1418 }
1419
1420 void R_Q1BSP_Draw(entity_render_t *ent)
1421 {
1422         if (ent->model == NULL)
1423                 return;
1424         c_bmodels++;
1425         if (r_drawcollisionbrushes.integer < 2)
1426                 R_DrawSurfaces(ent, false);
1427 }
1428
1429 void R_Q1BSP_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outclusterlist, qbyte *outclusterpvs, int *outnumclusterspointer, int *outsurfacelist, qbyte *outsurfacepvs, int *outnumsurfacespointer)
1430 {
1431         model_t *model = ent->model;
1432         vec3_t lightmins, lightmaxs;
1433         int t, leafindex, leafsurfaceindex, surfaceindex, triangleindex, outnumclusters = 0, outnumsurfaces = 0;
1434         const int *e;
1435         const float *v[3];
1436         msurface_t *surface;
1437         mleaf_t *leaf;
1438         const qbyte *pvs;
1439         lightmins[0] = relativelightorigin[0] - lightradius;
1440         lightmins[1] = relativelightorigin[1] - lightradius;
1441         lightmins[2] = relativelightorigin[2] - lightradius;
1442         lightmaxs[0] = relativelightorigin[0] + lightradius;
1443         lightmaxs[1] = relativelightorigin[1] + lightradius;
1444         lightmaxs[2] = relativelightorigin[2] + lightradius;
1445         *outnumclusterspointer = 0;
1446         *outnumsurfacespointer = 0;
1447         memset(outclusterpvs, 0, model->brush.num_pvsclusterbytes);
1448         memset(outsurfacepvs, 0, (model->nummodelsurfaces + 7) >> 3);
1449         if (model == NULL)
1450         {
1451                 VectorCopy(lightmins, outmins);
1452                 VectorCopy(lightmaxs, outmaxs);
1453                 return;
1454         }
1455         VectorCopy(relativelightorigin, outmins);
1456         VectorCopy(relativelightorigin, outmaxs);
1457         if (model->brush.GetPVS)
1458                 pvs = model->brush.GetPVS(model, relativelightorigin);
1459         else
1460                 pvs = NULL;
1461         R_UpdateAllTextureInfo(ent);
1462         // FIXME: use BSP recursion as lights are often small
1463         for (leafindex = 0, leaf = model->brush.data_leafs;leafindex < model->brush.num_leafs;leafindex++, leaf++)
1464         {
1465                 if (BoxesOverlap(lightmins, lightmaxs, leaf->mins, leaf->maxs) && (pvs == NULL || CHECKPVSBIT(pvs, leaf->clusterindex)))
1466                 {
1467                         outmins[0] = min(outmins[0], leaf->mins[0]);
1468                         outmins[1] = min(outmins[1], leaf->mins[1]);
1469                         outmins[2] = min(outmins[2], leaf->mins[2]);
1470                         outmaxs[0] = max(outmaxs[0], leaf->maxs[0]);
1471                         outmaxs[1] = max(outmaxs[1], leaf->maxs[1]);
1472                         outmaxs[2] = max(outmaxs[2], leaf->maxs[2]);
1473                         if (outclusterpvs)
1474                         {
1475                                 if (!CHECKPVSBIT(outclusterpvs, leaf->clusterindex))
1476                                 {
1477                                         SETPVSBIT(outclusterpvs, leaf->clusterindex);
1478                                         outclusterlist[outnumclusters++] = leaf->clusterindex;
1479                                 }
1480                         }
1481                         if (outsurfacepvs)
1482                         {
1483                                 for (leafsurfaceindex = 0;leafsurfaceindex < leaf->numleafsurfaces;leafsurfaceindex++)
1484                                 {
1485                                         surfaceindex = leaf->firstleafsurface[leafsurfaceindex];
1486                                         if (!CHECKPVSBIT(outsurfacepvs, surfaceindex))
1487                                         {
1488                                                 surface = model->brush.data_surfaces + surfaceindex;
1489                                                 if (BoxesOverlap(lightmins, lightmaxs, surface->mins, surface->maxs) && ((surface->texture->currentmaterialflags & (MATERIALFLAG_WALL | MATERIALFLAG_NODRAW | MATERIALFLAG_TRANSPARENT)) == MATERIALFLAG_WALL) && !surface->texture->skin.fog)
1490                                                 {
1491                                                         for (triangleindex = 0, t = surface->num_firstshadowmeshtriangle, e = model->brush.shadowmesh->element3i + t * 3;triangleindex < surface->mesh.num_triangles;triangleindex++, t++, e += 3)
1492                                                         {
1493                                                                 v[0] = model->brush.shadowmesh->vertex3f + e[0] * 3;
1494                                                                 v[1] = model->brush.shadowmesh->vertex3f + e[1] * 3;
1495                                                                 v[2] = model->brush.shadowmesh->vertex3f + e[2] * 3;
1496                                                                 if (PointInfrontOfTriangle(relativelightorigin, v[0], v[1], v[2]) && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0])) && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0])) && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1])) && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1])) && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2])) && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
1497                                                                 {
1498                                                                         SETPVSBIT(outsurfacepvs, surfaceindex);
1499                                                                         outsurfacelist[outnumsurfaces++] = surfaceindex;
1500                                                                         break;
1501                                                                 }
1502                                                         }
1503                                                 }
1504                                         }
1505                                 }
1506                         }
1507                 }
1508         }
1509
1510         // limit combined leaf box to light boundaries
1511         outmins[0] = max(outmins[0], lightmins[0]);
1512         outmins[1] = max(outmins[1], lightmins[1]);
1513         outmins[2] = max(outmins[2], lightmins[2]);
1514         outmaxs[0] = min(outmaxs[0], lightmaxs[0]);
1515         outmaxs[1] = min(outmaxs[1], lightmaxs[1]);
1516         outmaxs[2] = min(outmaxs[2], lightmaxs[2]);
1517
1518         *outnumclusterspointer = outnumclusters;
1519         *outnumsurfacespointer = outnumsurfaces;
1520 }
1521
1522 void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist, const vec3_t lightmins, const vec3_t lightmaxs)
1523 {
1524         model_t *model = ent->model;
1525         msurface_t *surface;
1526         int surfacelistindex;
1527         if (r_drawcollisionbrushes.integer < 2)
1528         {
1529                 R_Mesh_Matrix(&ent->matrix);
1530                 R_Shadow_PrepareShadowMark(model->brush.shadowmesh->numtriangles);
1531                 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1532                 {
1533                         surface = model->brush.data_surfaces + surfacelist[surfacelistindex];
1534                         R_Shadow_MarkVolumeFromBox(surface->num_firstshadowmeshtriangle, surface->mesh.num_triangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, relativelightorigin, lightmins, lightmaxs, surface->mins, surface->maxs);
1535                 }
1536                 R_Shadow_VolumeFromList(model->brush.shadowmesh->numverts, model->brush.shadowmesh->numtriangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, model->brush.shadowmesh->neighbor3i, relativelightorigin, lightradius + model->radius + r_shadow_projectdistance.value, numshadowmark, shadowmarklist);
1537         }
1538 }
1539
1540 void R_Q1BSP_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *lightcubemap, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int numsurfaces, const int *surfacelist)
1541 {
1542         model_t *model = ent->model;
1543         msurface_t *surface;
1544         texture_t *t;
1545         int surfacelistindex;
1546         if (r_drawcollisionbrushes.integer < 2)
1547         {
1548                 R_Mesh_Matrix(&ent->matrix);
1549                 if (!r_shadow_compilingrtlight)
1550                         R_UpdateAllTextureInfo(ent);
1551                 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1552                 {
1553                         surface = model->brush.data_surfaces + surfacelist[surfacelistindex];
1554                         if (r_shadow_compilingrtlight)
1555                         {
1556                                 // if compiling an rtlight, capture the mesh
1557                                 t = surface->texture;
1558                                 if ((t->basematerialflags & (MATERIALFLAG_WALL | MATERIALFLAG_TRANSPARENT)) == MATERIALFLAG_WALL)
1559                                         Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_light, surface->texture->skin.base, surface->texture->skin.gloss, surface->texture->skin.nmap, surface->mesh.data_vertex3f, surface->mesh.data_svector3f, surface->mesh.data_tvector3f, surface->mesh.data_normal3f, surface->mesh.data_texcoordtexture2f, surface->mesh.num_triangles, surface->mesh.data_element3i);
1560                         }
1561                         else if (ent != r_refdef.worldentity || r_worldsurfacevisible[surfacelist[surfacelistindex]])
1562                         {
1563                                 t = surface->texture->currentframe;
1564                                 // FIXME: transparent surfaces need to be lit later
1565                                 if ((t->currentmaterialflags & (MATERIALFLAG_WALL | MATERIALFLAG_TRANSPARENT)) == MATERIALFLAG_WALL)
1566                                         R_Shadow_RenderLighting(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i, surface->mesh.data_vertex3f, surface->mesh.data_svector3f, surface->mesh.data_tvector3f, surface->mesh.data_normal3f, surface->mesh.data_texcoordtexture2f, relativelightorigin, relativeeyeorigin, lightcolor, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, t->skin.base, t->skin.nmap, t->skin.gloss, lightcubemap, ambientscale, diffusescale, specularscale);
1567                         }
1568                 }
1569         }
1570 }
1571
1572 void R_DrawCollisionBrush(colbrushf_t *brush)
1573 {
1574         int i;
1575         rmeshstate_t m;
1576         memset(&m, 0, sizeof(m));
1577         m.pointer_vertex = brush->points->v;
1578         R_Mesh_State(&m);
1579         i = (int)(((size_t)brush) / sizeof(colbrushf_t));
1580         GL_Color((i & 31) * (1.0f / 32.0f), ((i >> 5) & 31) * (1.0f / 32.0f), ((i >> 10) & 31) * (1.0f / 32.0f), 0.2f);
1581         GL_LockArrays(0, brush->numpoints);
1582         R_Mesh_Draw(brush->numpoints, brush->numtriangles, brush->elements);
1583         GL_LockArrays(0, 0);
1584 }
1585
1586 void R_Q3BSP_DrawCollisionSurface(entity_render_t *ent, msurface_t *surface)
1587 {
1588         int i;
1589         rmeshstate_t m;
1590         if (!surface->mesh.num_collisiontriangles)
1591                 return;
1592         memset(&m, 0, sizeof(m));
1593         m.pointer_vertex = surface->mesh.data_collisionvertex3f;
1594         R_Mesh_State(&m);
1595         i = (int)(((size_t)surface) / sizeof(msurface_t));
1596         GL_Color((i & 31) * (1.0f / 32.0f), ((i >> 5) & 31) * (1.0f / 32.0f), ((i >> 10) & 31) * (1.0f / 32.0f), 0.2f);
1597         GL_LockArrays(0, surface->mesh.num_collisionvertices);
1598         R_Mesh_Draw(surface->mesh.num_collisionvertices, surface->mesh.num_collisiontriangles, surface->mesh.data_collisionelement3i);
1599         GL_LockArrays(0, 0);
1600 }
1601
1602 void R_Q3BSP_DrawFace_TransparentCallback(const void *voident, int surfacenumber)
1603 {
1604         const entity_render_t *ent = voident;
1605         msurface_t *surface = ent->model->brush.data_surfaces + surfacenumber;
1606         rmeshstate_t m;
1607         R_Mesh_Matrix(&ent->matrix);
1608         memset(&m, 0, sizeof(m));
1609         if ((ent->effects & EF_ADDITIVE) || (surface->texture->textureflags & Q3TEXTUREFLAG_ADDITIVE))
1610                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1611         else
1612                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1613         GL_DepthMask(false);
1614         GL_DepthTest(!(ent->effects & EF_NODEPTHTEST));
1615         m.tex[0] = R_GetTexture(surface->texture->skin.base);
1616         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
1617         // LordHavoc: quake3 was not able to do this; lit transparent surfaces
1618         if (gl_combine.integer)
1619         {
1620                 m.texrgbscale[0] = 2;
1621                 if (r_textureunits.integer >= 2)
1622                 {
1623                         m.tex[1] = R_GetTexture(surface->lightmaptexture);
1624                         m.pointer_texcoord[1] = surface->mesh.data_texcoordlightmap2f;
1625                         GL_Color(ent->colormod[0], ent->colormod[1], ent->colormod[2], ent->alpha);
1626                 }
1627                 else
1628                 {
1629                         if (ent->colormod[0] == 1 && ent->colormod[1] == 1 && ent->colormod[2] == 1 && ent->alpha == 1)
1630                                 m.pointer_color = surface->mesh.data_lightmapcolor4f;
1631                         else
1632                         {
1633                                 int i;
1634                                 for (i = 0;i < surface->mesh.num_vertices;i++)
1635                                 {
1636                                         varray_color4f[i*4+0] = surface->mesh.data_lightmapcolor4f[i*4+0] * ent->colormod[0];
1637                                         varray_color4f[i*4+1] = surface->mesh.data_lightmapcolor4f[i*4+1] * ent->colormod[1];
1638                                         varray_color4f[i*4+2] = surface->mesh.data_lightmapcolor4f[i*4+2] * ent->colormod[2];
1639                                         varray_color4f[i*4+3] = surface->mesh.data_lightmapcolor4f[i*4+3] * ent->alpha;
1640                                 }
1641                                 m.pointer_color = varray_color4f;
1642                         }
1643                 }
1644         }
1645         else
1646         {
1647                 int i;
1648                 for (i = 0;i < surface->mesh.num_vertices;i++)
1649                 {
1650                         varray_color4f[i*4+0] = surface->mesh.data_lightmapcolor4f[i*4+0] * ent->colormod[0] * 2.0f;
1651                         varray_color4f[i*4+1] = surface->mesh.data_lightmapcolor4f[i*4+1] * ent->colormod[1] * 2.0f;
1652                         varray_color4f[i*4+2] = surface->mesh.data_lightmapcolor4f[i*4+2] * ent->colormod[2] * 2.0f;
1653                         varray_color4f[i*4+3] = surface->mesh.data_lightmapcolor4f[i*4+3] * ent->alpha;
1654                 }
1655                 m.pointer_color = varray_color4f;
1656         }
1657         if (surface->texture->textureflags & (Q3TEXTUREFLAG_AUTOSPRITE | Q3TEXTUREFLAG_AUTOSPRITE2))
1658         {
1659                 int i, j;
1660                 float center[3], center2[3], forward[3], right[3], up[3], v[4][3];
1661                 matrix4x4_t matrix1, imatrix1;
1662                 R_Mesh_Matrix(&r_identitymatrix);
1663                 // a single autosprite surface can contain multiple sprites...
1664                 for (j = 0;j < surface->mesh.num_vertices - 3;j += 4)
1665                 {
1666                         VectorClear(center);
1667                         for (i = 0;i < 4;i++)
1668                                 VectorAdd(center, surface->mesh.data_vertex3f + (j+i) * 3, center);
1669                         VectorScale(center, 0.25f, center);
1670                         Matrix4x4_Transform(&ent->matrix, center, center2);
1671                         // FIXME: calculate vectors from triangle edges instead of using texture vectors as an easy way out?
1672                         Matrix4x4_FromVectors(&matrix1, surface->mesh.data_normal3f + j*3, surface->mesh.data_svector3f + j*3, surface->mesh.data_tvector3f + j*3, center);
1673                         Matrix4x4_Invert_Simple(&imatrix1, &matrix1);
1674                         for (i = 0;i < 4;i++)
1675                                 Matrix4x4_Transform(&imatrix1, surface->mesh.data_vertex3f + (j+i)*3, v[i]);
1676                         if (surface->texture->textureflags & Q3TEXTUREFLAG_AUTOSPRITE2)
1677                         {
1678                                 forward[0] = r_vieworigin[0] - center2[0];
1679                                 forward[1] = r_vieworigin[1] - center2[1];
1680                                 forward[2] = 0;
1681                                 VectorNormalize(forward);
1682                                 right[0] = forward[1];
1683                                 right[1] = -forward[0];
1684                                 right[2] = 0;
1685                                 up[0] = 0;
1686                                 up[1] = 0;
1687                                 up[2] = 1;
1688                         }
1689                         else
1690                         {
1691                                 VectorCopy(r_viewforward, forward);
1692                                 VectorCopy(r_viewright, right);
1693                                 VectorCopy(r_viewup, up);
1694                         }
1695                         for (i = 0;i < 4;i++)
1696                                 VectorMAMAMAM(1, center2, v[i][0], forward, v[i][1], right, v[i][2], up, varray_vertex3f + (i+j) * 3);
1697                 }
1698                 m.pointer_vertex = varray_vertex3f;
1699         }
1700         else
1701                 m.pointer_vertex = surface->mesh.data_vertex3f;
1702         R_Mesh_State(&m);
1703         if (surface->texture->textureflags & Q3TEXTUREFLAG_TWOSIDED)
1704                 qglDisable(GL_CULL_FACE);
1705         GL_LockArrays(0, surface->mesh.num_vertices);
1706         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1707         GL_LockArrays(0, 0);
1708         if (surface->texture->textureflags & Q3TEXTUREFLAG_TWOSIDED)
1709                 qglEnable(GL_CULL_FACE);
1710 }
1711
1712 void R_Q3BSP_DrawFaceList(entity_render_t *ent, texture_t *t, int texturenumsurfaces, msurface_t **texturesurfacelist)
1713 {
1714         int i, texturesurfaceindex;
1715         vec3_t modelorg;
1716         msurface_t *surface;
1717         qboolean dolightmap;
1718         qboolean dobase;
1719         qboolean doambient;
1720         qboolean dodetail;
1721         qboolean doglow;
1722         qboolean dofog;
1723         rmeshstate_t m;
1724         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg);
1725         c_faces += texturenumsurfaces;
1726         // gl_lightmaps debugging mode skips normal texturing
1727         if (gl_lightmaps.integer)
1728         {
1729                 GL_BlendFunc(GL_ONE, GL_ZERO);
1730                 GL_DepthMask(true);
1731                 GL_DepthTest(true);
1732                 qglDisable(GL_CULL_FACE);
1733                 GL_Color(1, 1, 1, 1);
1734                 memset(&m, 0, sizeof(m));
1735                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1736                 {
1737                         surface = texturesurfacelist[texturesurfaceindex];
1738                         m.tex[0] = R_GetTexture(surface->lightmaptexture);
1739                         m.pointer_texcoord[0] = surface->mesh.data_texcoordlightmap2f;
1740                         if (surface->lightmaptexture)
1741                         {
1742                                 GL_Color(1, 1, 1, 1);
1743                                 m.pointer_color = NULL;
1744                         }
1745                         else
1746                                 m.pointer_color = surface->mesh.data_lightmapcolor4f;
1747                         m.pointer_vertex = surface->mesh.data_vertex3f;
1748                         R_Mesh_State(&m);
1749                         GL_LockArrays(0, surface->mesh.num_vertices);
1750                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1751                         GL_LockArrays(0, 0);
1752                 }
1753                 qglEnable(GL_CULL_FACE);
1754                 return;
1755         }
1756         // transparent surfaces get sorted for later drawing
1757         if ((t->surfaceparms & Q3SURFACEPARM_TRANS) || ent->alpha < 1 || (ent->effects & EF_ADDITIVE))
1758         {
1759                 vec3_t facecenter, center;
1760                 // drawing sky transparently would be too difficult
1761                 if (t->surfaceparms & Q3SURFACEPARM_SKY)
1762                         return;
1763                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1764                 {
1765                         surface = texturesurfacelist[texturesurfaceindex];
1766                         facecenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
1767                         facecenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
1768                         facecenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
1769                         Matrix4x4_Transform(&ent->matrix, facecenter, center);
1770                         R_MeshQueue_AddTransparent(center, R_Q3BSP_DrawFace_TransparentCallback, ent, surface - ent->model->brush.data_surfaces);
1771                 }
1772                 return;
1773         }
1774         // sky surfaces draw sky if needed and render themselves as a depth mask
1775         if (t->surfaceparms & Q3SURFACEPARM_SKY)
1776         {
1777                 if (skyrendernow)
1778                 {
1779                         skyrendernow = false;
1780                         if (skyrendermasked)
1781                                 R_Sky();
1782                 }
1783                 if (!r_q3bsp_renderskydepth.integer)
1784                         return;
1785
1786                 R_Mesh_Matrix(&ent->matrix);
1787
1788                 GL_Color(fogcolor[0], fogcolor[1], fogcolor[2], 1);
1789                 if (skyrendermasked)
1790                 {
1791                         // depth-only (masking)
1792                         GL_ColorMask(0,0,0,0);
1793                         // just to make sure that braindead drivers don't draw anything
1794                         // despite that colormask...
1795                         GL_BlendFunc(GL_ZERO, GL_ONE);
1796                 }
1797                 else
1798                 {
1799                         // fog sky
1800                         GL_BlendFunc(GL_ONE, GL_ZERO);
1801                 }
1802                 GL_DepthMask(true);
1803                 GL_DepthTest(true);
1804
1805                 memset(&m, 0, sizeof(m));
1806                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1807                 {
1808                         surface = texturesurfacelist[texturesurfaceindex];
1809                         m.pointer_vertex = surface->mesh.data_vertex3f;
1810                         R_Mesh_State(&m);
1811                         GL_LockArrays(0, surface->mesh.num_vertices);
1812                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1813                         GL_LockArrays(0, 0);
1814                 }
1815                 GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
1816                 return;
1817         }
1818         // anything else is a typical wall, lightmap * texture + glow
1819         dolightmap = (ent->flags & RENDER_LIGHT);
1820         dobase = true;
1821         doambient = r_ambient.value > 0;
1822         dodetail = t->skin.detail != NULL && r_detailtextures.integer;
1823         doglow = t->skin.glow != NULL;
1824         dofog = fogenabled;
1825         if (t->textureflags & Q3TEXTUREFLAG_TWOSIDED)
1826                 qglDisable(GL_CULL_FACE);
1827         if (!dolightmap && dobase)
1828         {
1829                 dolightmap = false;
1830                 dobase = false;
1831                 GL_DepthMask(true);
1832                 GL_DepthTest(true);
1833                 GL_BlendFunc(GL_ONE, GL_ZERO);
1834                 GL_Color(ent->colormod[0], ent->colormod[1], ent->colormod[2], 1);
1835                 if (t->textureflags & Q3TEXTUREFLAG_TWOSIDED)
1836                         qglDisable(GL_CULL_FACE);
1837                 memset(&m, 0, sizeof(m));
1838                 m.tex[0] = R_GetTexture(t->skin.base);
1839                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1840                 {
1841                         surface = texturesurfacelist[texturesurfaceindex];
1842                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
1843                         m.pointer_vertex = surface->mesh.data_vertex3f;
1844                         R_Mesh_State(&m);
1845                         GL_LockArrays(0, surface->mesh.num_vertices);
1846                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1847                         GL_LockArrays(0, 0);
1848                 }
1849         }
1850         if (r_lightmapintensity <= 0 && dolightmap && dobase)
1851         {
1852                 dolightmap = false;
1853                 dobase = false;
1854                 GL_DepthMask(true);
1855                 GL_DepthTest(true);
1856                 GL_BlendFunc(GL_ONE, GL_ZERO);
1857                 GL_Color(0, 0, 0, 1);
1858                 memset(&m, 0, sizeof(m));
1859                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1860                 {
1861                         surface = texturesurfacelist[texturesurfaceindex];
1862                         m.pointer_vertex = surface->mesh.data_vertex3f;
1863                         R_Mesh_State(&m);
1864                         GL_LockArrays(0, surface->mesh.num_vertices);
1865                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1866                         GL_LockArrays(0, 0);
1867                 }
1868         }
1869         if (r_textureunits.integer >= 2 && gl_combine.integer && dolightmap && dobase)
1870         {
1871                 // dualtexture combine
1872                 dolightmap = false;
1873                 dobase = false;
1874                 GL_DepthMask(true);
1875                 GL_DepthTest(true);
1876                 GL_BlendFunc(GL_ONE, GL_ZERO);
1877                 memset(&m, 0, sizeof(m));
1878                 m.tex[0] = R_GetTexture(t->skin.base);
1879                 GL_Color(r_lightmapintensity * ent->colormod[0], r_lightmapintensity * ent->colormod[1], r_lightmapintensity * ent->colormod[2], 1);
1880                 m.pointer_color = NULL;
1881                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1882                 {
1883                         surface = texturesurfacelist[texturesurfaceindex];
1884                         if (!surface->lightmaptexture)
1885                                 continue;
1886                         m.tex[1] = R_GetTexture(surface->lightmaptexture);
1887                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
1888                         m.pointer_texcoord[1] = surface->mesh.data_texcoordlightmap2f;
1889                         m.texrgbscale[1] = 2;
1890                         m.pointer_vertex = surface->mesh.data_vertex3f;
1891                         R_Mesh_State(&m);
1892                         GL_LockArrays(0, surface->mesh.num_vertices);
1893                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1894                         GL_LockArrays(0, 0);
1895                 }
1896                 if (r_lightmapintensity == 1 && ent->colormod[0] == 1 && ent->colormod[1] == 1 && ent->colormod[2] == 1)
1897                 {
1898                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1899                         {
1900                                 surface = texturesurfacelist[texturesurfaceindex];
1901                                 if (surface->lightmaptexture)
1902                                         continue;
1903                                 m.tex[1] = R_GetTexture(surface->lightmaptexture);
1904                                 m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
1905                                 m.pointer_texcoord[1] = surface->mesh.data_texcoordlightmap2f;
1906                                 m.texrgbscale[1] = 2;
1907                                 m.pointer_color = surface->mesh.data_lightmapcolor4f;
1908                                 m.pointer_vertex = surface->mesh.data_vertex3f;
1909                                 R_Mesh_State(&m);
1910                                 GL_LockArrays(0, surface->mesh.num_vertices);
1911                                 R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1912                                 GL_LockArrays(0, 0);
1913                         }
1914                 }
1915                 else
1916                 {
1917                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1918                         {
1919                                 surface = texturesurfacelist[texturesurfaceindex];
1920                                 if (surface->lightmaptexture)
1921                                         continue;
1922                                 m.tex[1] = R_GetTexture(surface->lightmaptexture);
1923                                 m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
1924                                 m.pointer_texcoord[1] = surface->mesh.data_texcoordlightmap2f;
1925                                 m.texrgbscale[1] = 2;
1926                                 m.pointer_color = varray_color4f;
1927                                 for (i = 0;i < surface->mesh.num_vertices;i++)
1928                                 {
1929                                         varray_color4f[i*4+0] = surface->mesh.data_lightmapcolor4f[i*4+0] * ent->colormod[0] * r_lightmapintensity;
1930                                         varray_color4f[i*4+1] = surface->mesh.data_lightmapcolor4f[i*4+1] * ent->colormod[1] * r_lightmapintensity;
1931                                         varray_color4f[i*4+2] = surface->mesh.data_lightmapcolor4f[i*4+2] * ent->colormod[2] * r_lightmapintensity;
1932                                         varray_color4f[i*4+3] = surface->mesh.data_lightmapcolor4f[i*4+3];
1933                                 }
1934                                 m.pointer_vertex = surface->mesh.data_vertex3f;
1935                                 R_Mesh_State(&m);
1936                                 GL_LockArrays(0, surface->mesh.num_vertices);
1937                                 R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1938                                 GL_LockArrays(0, 0);
1939                         }
1940                 }
1941         }
1942         // single texture
1943         if (dolightmap)
1944         {
1945                 GL_DepthMask(true);
1946                 GL_DepthTest(true);
1947                 GL_BlendFunc(GL_ONE, GL_ZERO);
1948                 memset(&m, 0, sizeof(m));
1949                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1950                 {
1951                         surface = texturesurfacelist[texturesurfaceindex];
1952                         m.tex[0] = R_GetTexture(surface->lightmaptexture);
1953                         m.pointer_texcoord[0] = surface->mesh.data_texcoordlightmap2f;
1954                         if (surface->lightmaptexture)
1955                                 m.pointer_color = NULL;
1956                         else
1957                                 m.pointer_color = surface->mesh.data_lightmapcolor4f;
1958                         m.pointer_vertex = surface->mesh.data_vertex3f;
1959                         R_Mesh_State(&m);
1960                         GL_LockArrays(0, surface->mesh.num_vertices);
1961                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1962                         GL_LockArrays(0, 0);
1963                 }
1964         }
1965         if (dobase)
1966         {
1967                 GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
1968                 GL_DepthMask(false);
1969                 GL_DepthTest(true);
1970                 GL_Color(r_lightmapintensity * ent->colormod[0], r_lightmapintensity * ent->colormod[1], r_lightmapintensity * ent->colormod[2], 1);
1971                 memset(&m, 0, sizeof(m));
1972                 m.tex[0] = R_GetTexture(t->skin.base);
1973                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1974                 {
1975                         surface = texturesurfacelist[texturesurfaceindex];
1976                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
1977                         m.pointer_vertex = surface->mesh.data_vertex3f;
1978                         R_Mesh_State(&m);
1979                         GL_LockArrays(0, surface->mesh.num_vertices);
1980                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1981                         GL_LockArrays(0, 0);
1982                 }
1983         }
1984         if (doambient)
1985         {
1986                 GL_BlendFunc(GL_ONE, GL_ONE);
1987                 GL_DepthMask(false);
1988                 GL_DepthTest(true);
1989                 GL_Color(r_ambient.value * (1.0f / 128.0f) * ent->colormod[0], r_ambient.value * (1.0f / 128.0f) * ent->colormod[1], r_ambient.value * (1.0f / 128.0f) * ent->colormod[2], 1);
1990                 memset(&m, 0, sizeof(m));
1991                 m.tex[0] = R_GetTexture(t->skin.base);
1992                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1993                 {
1994                         surface = texturesurfacelist[texturesurfaceindex];
1995                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
1996                         m.pointer_vertex = surface->mesh.data_vertex3f;
1997                         R_Mesh_State(&m);
1998                         GL_LockArrays(0, surface->mesh.num_vertices);
1999                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
2000                         GL_LockArrays(0, 0);
2001                 }
2002         }
2003         if (doglow)
2004         {
2005                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2006                 GL_DepthMask(false);
2007                 GL_DepthTest(true);
2008                 GL_Color(1, 1, 1, 1);
2009                 memset(&m, 0, sizeof(m));
2010                 m.tex[0] = R_GetTexture(t->skin.glow);
2011                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2012                 {
2013                         surface = texturesurfacelist[texturesurfaceindex];
2014                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
2015                         m.pointer_vertex = surface->mesh.data_vertex3f;
2016                         R_Mesh_State(&m);
2017                         GL_LockArrays(0, surface->mesh.num_vertices);
2018                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
2019                         GL_LockArrays(0, 0);
2020                 }
2021         }
2022         if (dofog)
2023         {
2024                 float modelorg[3];
2025                 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg);
2026                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2027                 GL_DepthMask(false);
2028                 GL_DepthTest(true);
2029                 GL_Color(1, 1, 1, 1);
2030                 memset(&m, 0, sizeof(m));
2031                 m.tex[0] = R_GetTexture(t->skin.fog);
2032                 m.pointer_color = varray_color4f;
2033                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
2034                 {
2035                         surface = texturesurfacelist[texturesurfaceindex];
2036                         if (m.tex[0])
2037                                 m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
2038                         m.pointer_vertex = surface->mesh.data_vertex3f;
2039                         R_Mesh_State(&m);
2040                         RSurf_FogPassColors_Vertex3f_Color4f(surface->mesh.data_vertex3f, varray_color4f, fogcolor[0], fogcolor[1], fogcolor[2], 1, 1, surface->mesh.num_vertices, modelorg);
2041                         GL_LockArrays(0, surface->mesh.num_vertices);
2042                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
2043                         GL_LockArrays(0, 0);
2044                 }
2045         }
2046         if (t->textureflags & Q3TEXTUREFLAG_TWOSIDED)
2047                 qglEnable(GL_CULL_FACE);
2048 }
2049
2050 void R_Q3BSP_DrawFaces(entity_render_t *ent, int skyfaces)
2051 {
2052         int i, j, f, flagsmask, flags;
2053         msurface_t *surface;
2054         model_t *model = ent->model;
2055         texture_t *t;
2056         const int maxfaces = 1024;
2057         int numsurfaces = 0;
2058         msurface_t *surfacelist[1024];
2059         R_Mesh_Matrix(&ent->matrix);
2060         flagsmask = Q3SURFACEFLAG_NODRAW | Q3SURFACEFLAG_SKY;
2061         if (skyfaces)
2062                 flags = Q3SURFACEFLAG_SKY;
2063         else
2064                 flags = 0;
2065         t = NULL;
2066         f = 0;
2067         numsurfaces = 0;
2068         for (i = 0, j = model->firstmodelsurface;i < model->nummodelsurfaces;i++, j++)
2069         {
2070                 if (ent != r_refdef.worldentity || r_worldsurfacevisible[j])
2071                 {
2072                         surface = model->brush.data_surfaces + j;
2073                         if (t != surface->texture)
2074                         {
2075                                 if (numsurfaces)
2076                                 {
2077                                         R_Q3BSP_DrawFaceList(ent, t, numsurfaces, surfacelist);
2078                                         numsurfaces = 0;
2079                                 }
2080                                 t = surface->texture;
2081                                 f = t->surfaceflags & flagsmask;
2082                         }
2083                         if (f == flags)
2084                         {
2085                                 if (!surface->mesh.num_triangles)
2086                                         continue;
2087                                 surfacelist[numsurfaces++] = surface;
2088                                 if (numsurfaces >= maxfaces)
2089                                 {
2090                                         R_Q3BSP_DrawFaceList(ent, t, numsurfaces, surfacelist);
2091                                         numsurfaces = 0;
2092                                 }
2093                         }
2094                 }
2095         }
2096         if (numsurfaces)
2097                 R_Q3BSP_DrawFaceList(ent, t, numsurfaces, surfacelist);
2098 }
2099
2100 void R_Q3BSP_DrawSky(entity_render_t *ent)
2101 {
2102         if (r_drawcollisionbrushes.integer < 2)
2103                 R_Q3BSP_DrawFaces(ent, true);
2104 }
2105
2106 void R_Q3BSP_Draw(entity_render_t *ent)
2107 {
2108         if (r_drawcollisionbrushes.integer < 2)
2109                 R_Q3BSP_DrawFaces(ent, false);
2110         if (r_drawcollisionbrushes.integer >= 1)
2111         {
2112                 int i;
2113                 model_t *model = ent->model;
2114                 msurface_t *surface;
2115                 q3mbrush_t *brush;
2116                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2117                 GL_DepthMask(false);
2118                 GL_DepthTest(true);
2119                 qglPolygonOffset(r_drawcollisionbrushes_polygonfactor.value, r_drawcollisionbrushes_polygonoffset.value);
2120                 for (i = 0, brush = model->brush.data_brushes + model->firstmodelbrush;i < model->nummodelbrushes;i++, brush++)
2121                         if (brush->colbrushf && brush->colbrushf->numtriangles)
2122                                 R_DrawCollisionBrush(brush->colbrushf);
2123                 for (i = 0, surface = model->brush.data_surfaces + model->firstmodelsurface;i < model->nummodelsurfaces;i++, surface++)
2124                         if (surface->mesh.num_collisiontriangles)
2125                                 R_Q3BSP_DrawCollisionSurface(ent, surface);
2126                 qglPolygonOffset(0, 0);
2127         }
2128 }
2129
2130 void R_Q3BSP_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outclusterlist, qbyte *outclusterpvs, int *outnumclusterspointer, int *outsurfacelist, qbyte *outsurfacepvs, int *outnumsurfacespointer)
2131 {
2132         model_t *model = ent->model;
2133         vec3_t lightmins, lightmaxs;
2134         int t, leafindex, leafsurfaceindex, surfaceindex, triangleindex, outnumclusters = 0, outnumsurfaces = 0;
2135         const int *e;
2136         const float *v[3];
2137         msurface_t *surface;
2138         mleaf_t *leaf;
2139         const qbyte *pvs;
2140         lightmins[0] = relativelightorigin[0] - lightradius;
2141         lightmins[1] = relativelightorigin[1] - lightradius;
2142         lightmins[2] = relativelightorigin[2] - lightradius;
2143         lightmaxs[0] = relativelightorigin[0] + lightradius;
2144         lightmaxs[1] = relativelightorigin[1] + lightradius;
2145         lightmaxs[2] = relativelightorigin[2] + lightradius;
2146         *outnumclusterspointer = 0;
2147         *outnumsurfacespointer = 0;
2148         memset(outclusterpvs, 0, model->brush.num_pvsclusterbytes);
2149         memset(outsurfacepvs, 0, (model->nummodelsurfaces + 7) >> 3);
2150         if (model == NULL)
2151         {
2152                 VectorCopy(lightmins, outmins);
2153                 VectorCopy(lightmaxs, outmaxs);
2154                 return;
2155         }
2156         VectorCopy(relativelightorigin, outmins);
2157         VectorCopy(relativelightorigin, outmaxs);
2158         if (model->brush.GetPVS)
2159                 pvs = model->brush.GetPVS(model, relativelightorigin);
2160         else
2161                 pvs = NULL;
2162         // FIXME: use BSP recursion as lights are often small
2163         for (leafindex = 0, leaf = model->brush.data_leafs;leafindex < model->brush.num_leafs;leafindex++, leaf++)
2164         {
2165                 if (BoxesOverlap(lightmins, lightmaxs, leaf->mins, leaf->maxs) && (pvs == NULL || CHECKPVSBIT(pvs, leaf->clusterindex)))
2166                 {
2167                         outmins[0] = min(outmins[0], leaf->mins[0]);
2168                         outmins[1] = min(outmins[1], leaf->mins[1]);
2169                         outmins[2] = min(outmins[2], leaf->mins[2]);
2170                         outmaxs[0] = max(outmaxs[0], leaf->maxs[0]);
2171                         outmaxs[1] = max(outmaxs[1], leaf->maxs[1]);
2172                         outmaxs[2] = max(outmaxs[2], leaf->maxs[2]);
2173                         if (outclusterpvs)
2174                         {
2175                                 if (!CHECKPVSBIT(outclusterpvs, leaf->clusterindex))
2176                                 {
2177                                         SETPVSBIT(outclusterpvs, leaf->clusterindex);
2178                                         outclusterlist[outnumclusters++] = leaf->clusterindex;
2179                                 }
2180                         }
2181                         if (outsurfacepvs)
2182                         {
2183                                 for (leafsurfaceindex = 0;leafsurfaceindex < leaf->numleafsurfaces;leafsurfaceindex++)
2184                                 {
2185                                         surfaceindex = leaf->firstleafsurface[leafsurfaceindex];
2186                                         surface = model->brush.data_surfaces + surfaceindex;
2187                                         if (!CHECKPVSBIT(outsurfacepvs, surfaceindex))
2188                                         {
2189                                                 if (BoxesOverlap(lightmins, lightmaxs, surface->mins, surface->maxs) && !(surface->texture->surfaceparms & Q3SURFACEPARM_TRANS) && !(surface->texture->surfaceflags & (Q3SURFACEFLAG_SKY | Q3SURFACEFLAG_NODRAW)) && surface->mesh.num_triangles)
2190                                                 {
2191                                                         if (surface->texture->textureflags & Q3TEXTUREFLAG_TWOSIDED)
2192                                                         {
2193                                                                 for (triangleindex = 0, t = surface->num_firstshadowmeshtriangle, e = model->brush.shadowmesh->element3i + t * 3;triangleindex < surface->mesh.num_triangles;triangleindex++, t++, e += 3)
2194                                                                 {
2195                                                                         v[0] = model->brush.shadowmesh->vertex3f + e[0] * 3;
2196                                                                         v[1] = model->brush.shadowmesh->vertex3f + e[1] * 3;
2197                                                                         v[2] = model->brush.shadowmesh->vertex3f + e[2] * 3;
2198                                                                         if (lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0])) && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0])) && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1])) && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1])) && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2])) && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
2199                                                                         {
2200                                                                                 SETPVSBIT(outsurfacepvs, surfaceindex);
2201                                                                                 outsurfacelist[outnumsurfaces++] = surfaceindex;
2202                                                                                 break;
2203                                                                         }
2204                                                                 }
2205                                                         }
2206                                                         else
2207                                                         {
2208                                                                 for (triangleindex = 0, t = surface->num_firstshadowmeshtriangle, e = model->brush.shadowmesh->element3i + t * 3;triangleindex < surface->mesh.num_triangles;triangleindex++, t++, e += 3)
2209                                                                 {
2210                                                                         v[0] = model->brush.shadowmesh->vertex3f + e[0] * 3;
2211                                                                         v[1] = model->brush.shadowmesh->vertex3f + e[1] * 3;
2212                                                                         v[2] = model->brush.shadowmesh->vertex3f + e[2] * 3;
2213                                                                         if (PointInfrontOfTriangle(relativelightorigin, v[0], v[1], v[2]) && lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0])) && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0])) && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1])) && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1])) && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2])) && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
2214                                                                         {
2215                                                                                 SETPVSBIT(outsurfacepvs, surfaceindex);
2216                                                                                 outsurfacelist[outnumsurfaces++] = surfaceindex;
2217                                                                                 break;
2218                                                                         }
2219                                                                 }
2220                                                         }
2221                                                 }
2222                                         }
2223                                 }
2224                         }
2225                 }
2226         }
2227
2228         // limit combined leaf box to light boundaries
2229         outmins[0] = max(outmins[0], lightmins[0]);
2230         outmins[1] = max(outmins[1], lightmins[1]);
2231         outmins[2] = max(outmins[2], lightmins[2]);
2232         outmaxs[0] = min(outmaxs[0], lightmaxs[0]);
2233         outmaxs[1] = min(outmaxs[1], lightmaxs[1]);
2234         outmaxs[2] = min(outmaxs[2], lightmaxs[2]);
2235
2236         *outnumclusterspointer = outnumclusters;
2237         *outnumsurfacespointer = outnumsurfaces;
2238 }
2239
2240 void R_Q3BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist, const vec3_t lightmins, const vec3_t lightmaxs)
2241 {
2242         model_t *model = ent->model;
2243         msurface_t *surface;
2244         int surfacelistindex;
2245         if (r_drawcollisionbrushes.integer < 2)
2246         {
2247                 R_Mesh_Matrix(&ent->matrix);
2248                 R_Shadow_PrepareShadowMark(model->brush.shadowmesh->numtriangles);
2249                 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2250                 {
2251                         surface = model->brush.data_surfaces + surfacelist[surfacelistindex];
2252                         // FIXME: check some manner of surface->rendermode here?
2253                         if (!(surface->texture->surfaceflags & Q3SURFACEFLAG_NODRAW) && !(surface->texture->surfaceparms & (Q3SURFACEPARM_SKY | Q3SURFACEPARM_TRANS)) && !(surface->texture->textureflags & Q3TEXTUREFLAG_TWOSIDED))
2254                                 R_Shadow_MarkVolumeFromBox(surface->num_firstshadowmeshtriangle, surface->mesh.num_triangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, relativelightorigin, lightmins, lightmaxs, surface->mins, surface->maxs);
2255                 }
2256                 R_Shadow_VolumeFromList(model->brush.shadowmesh->numverts, model->brush.shadowmesh->numtriangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, model->brush.shadowmesh->neighbor3i, relativelightorigin, lightradius + model->radius + r_shadow_projectdistance.value, numshadowmark, shadowmarklist);
2257         }
2258 }
2259
2260 void R_Q3BSP_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *lightcubemap, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int numsurfaces, const int *surfacelist)
2261 {
2262         model_t *model = ent->model;
2263         vec3_t lightmins, lightmaxs, modelorg;
2264         msurface_t *surface;
2265         int surfacelistindex;
2266         if (r_drawcollisionbrushes.integer < 2)
2267         {
2268                 lightmins[0] = relativelightorigin[0] - lightradius;
2269                 lightmins[1] = relativelightorigin[1] - lightradius;
2270                 lightmins[2] = relativelightorigin[2] - lightradius;
2271                 lightmaxs[0] = relativelightorigin[0] + lightradius;
2272                 lightmaxs[1] = relativelightorigin[1] + lightradius;
2273                 lightmaxs[2] = relativelightorigin[2] + lightradius;
2274                 R_Mesh_Matrix(&ent->matrix);
2275                 Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg);
2276                 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
2277                 {
2278                         surface = model->brush.data_surfaces + surfacelist[surfacelistindex];
2279                         if (r_shadow_compilingrtlight)
2280                         {
2281                                 // if compiling an rtlight, capture the mesh
2282                                 Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_light, surface->texture->skin.base, surface->texture->skin.gloss, surface->texture->skin.nmap, surface->mesh.data_vertex3f, surface->mesh.data_svector3f, surface->mesh.data_tvector3f, surface->mesh.data_normal3f, surface->mesh.data_texcoordtexture2f, surface->mesh.num_triangles, surface->mesh.data_element3i);
2283                         }
2284                         else if ((ent != r_refdef.worldentity || r_worldsurfacevisible[surfacelist[surfacelistindex]]) && !(surface->texture->surfaceflags & Q3SURFACEFLAG_NODRAW) && surface->mesh.num_triangles)
2285                         {
2286                                 if (surface->texture->textureflags & Q3TEXTUREFLAG_TWOSIDED)
2287                                         qglDisable(GL_CULL_FACE);
2288                                 R_Shadow_RenderLighting(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i, surface->mesh.data_vertex3f, surface->mesh.data_svector3f, surface->mesh.data_tvector3f, surface->mesh.data_normal3f, surface->mesh.data_texcoordtexture2f, relativelightorigin, relativeeyeorigin, lightcolor, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, surface->texture->skin.base, surface->texture->skin.nmap, surface->texture->skin.gloss, lightcubemap, ambientscale, diffusescale, specularscale);
2289                                 if (surface->texture->textureflags & Q3TEXTUREFLAG_TWOSIDED)
2290                                         qglEnable(GL_CULL_FACE);
2291                         }
2292                 }
2293         }
2294 }
2295
2296 #if 0
2297 static void gl_surf_start(void)
2298 {
2299 }
2300
2301 static void gl_surf_shutdown(void)
2302 {
2303 }
2304
2305 static void gl_surf_newmap(void)
2306 {
2307 }
2308 #endif
2309
2310 void GL_Surf_Init(void)
2311 {
2312         int i;
2313         dlightdivtable[0] = 4194304;
2314         for (i = 1;i < 32768;i++)
2315                 dlightdivtable[i] = 4194304 / (i << 7);
2316
2317         Cvar_RegisterVariable(&r_ambient);
2318         Cvar_RegisterVariable(&r_drawportals);
2319         Cvar_RegisterVariable(&r_testvis);
2320         Cvar_RegisterVariable(&r_floatbuildlightmap);
2321         Cvar_RegisterVariable(&r_detailtextures);
2322         Cvar_RegisterVariable(&r_surfaceworldnode);
2323         Cvar_RegisterVariable(&r_drawcollisionbrushes_polygonfactor);
2324         Cvar_RegisterVariable(&r_drawcollisionbrushes_polygonoffset);
2325         Cvar_RegisterVariable(&r_q3bsp_renderskydepth);
2326         Cvar_RegisterVariable(&gl_lightmaps);
2327
2328         //R_RegisterModule("GL_Surf", gl_surf_start, gl_surf_shutdown, gl_surf_newmap);
2329 }
2330