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