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