optimizations to rendering
[xonotic/darkplaces.git] / gl_rsurf.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // r_surf.c: surface-related refresh code
21
22 #include "quakedef.h"
23
24 #define MAX_LIGHTMAP_SIZE 256
25
26 static unsigned int intblocklights[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*3]; // LordHavoc: *3 for colored lighting
27 static float floatblocklights[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*3]; // LordHavoc: *3 for colored lighting
28
29 static qbyte templight[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*4];
30
31 cvar_t r_ambient = {0, "r_ambient", "0"};
32 cvar_t r_vertexsurfaces = {0, "r_vertexsurfaces", "0"};
33 cvar_t r_dlightmap = {CVAR_SAVE, "r_dlightmap", "1"};
34 cvar_t r_drawportals = {0, "r_drawportals", "0"};
35 cvar_t r_testvis = {0, "r_testvis", "0"};
36 cvar_t r_floatbuildlightmap = {0, "r_floatbuildlightmap", "0"};
37 cvar_t r_detailtextures = {CVAR_SAVE, "r_detailtextures", "1"};
38
39 static int dlightdivtable[32768];
40
41 static int R_IntAddDynamicLights (msurface_t *surf)
42 {
43         int sdtable[256], lnum, td, maxdist, maxdist2, maxdist3, i, s, t, smax, tmax, smax3, red, green, blue, lit, dist2, impacts, impactt, subtract;
44         unsigned int *bl;
45         float dist, impact[3], local[3];
46
47         // LordHavoc: use 64bit integer...  shame it's not very standardized...
48 #if _MSC_VER || __BORLANDC__
49         __int64     k;
50 #else
51         long long   k;
52 #endif
53
54         lit = false;
55
56         smax = (surf->extents[0] >> 4) + 1;
57         tmax = (surf->extents[1] >> 4) + 1;
58         smax3 = smax * 3;
59
60         for (lnum = 0; lnum < r_numdlights; lnum++)
61         {
62                 if (!(surf->dlightbits[lnum >> 5] & (1 << (lnum & 31))))
63                         continue;                                       // not lit by this light
64
65                 softwareuntransform(r_dlight[lnum].origin, local);
66                 dist = DotProduct (local, surf->plane->normal) - surf->plane->dist;
67
68                 // for comparisons to minimum acceptable light
69                 // compensate for LIGHTOFFSET
70                 maxdist = (int) r_dlight[lnum].cullradius2 + LIGHTOFFSET;
71
72                 dist2 = dist * dist;
73                 dist2 += LIGHTOFFSET;
74                 if (dist2 >= maxdist)
75                         continue;
76
77                 if (surf->plane->type < 3)
78                 {
79                         VectorCopy(local, impact);
80                         impact[surf->plane->type] -= dist;
81                 }
82                 else
83                 {
84                         impact[0] = local[0] - surf->plane->normal[0] * dist;
85                         impact[1] = local[1] - surf->plane->normal[1] * dist;
86                         impact[2] = local[2] - surf->plane->normal[2] * dist;
87                 }
88
89                 impacts = DotProduct (impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3] - surf->texturemins[0];
90                 impactt = DotProduct (impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3] - surf->texturemins[1];
91
92                 s = bound(0, impacts, smax * 16) - impacts;
93                 t = bound(0, impactt, tmax * 16) - impactt;
94                 i = s * s + t * t + dist2;
95                 if (i > maxdist)
96                         continue;
97
98                 // reduce calculations
99                 for (s = 0, i = impacts; s < smax; s++, i -= 16)
100                         sdtable[s] = i * i + dist2;
101
102                 maxdist3 = maxdist - dist2;
103
104                 // convert to 8.8 blocklights format
105                 red = r_dlight[lnum].light[0];
106                 green = r_dlight[lnum].light[1];
107                 blue = r_dlight[lnum].light[2];
108                 subtract = (int) (r_dlight[lnum].subtract * 4194304.0f);
109                 bl = intblocklights;
110
111                 i = impactt;
112                 for (t = 0;t < tmax;t++, i -= 16)
113                 {
114                         td = i * i;
115                         // make sure some part of it is visible on this line
116                         if (td < maxdist3)
117                         {
118                                 maxdist2 = maxdist - td;
119                                 for (s = 0;s < smax;s++)
120                                 {
121                                         if (sdtable[s] < maxdist2)
122                                         {
123                                                 k = dlightdivtable[(sdtable[s] + td) >> 7] - subtract;
124                                                 if (k > 0)
125                                                 {
126                                                         bl[0] += (red   * k) >> 7;
127                                                         bl[1] += (green * k) >> 7;
128                                                         bl[2] += (blue  * k) >> 7;
129                                                         lit = true;
130                                                 }
131                                         }
132                                         bl += 3;
133                                 }
134                         }
135                         else // skip line
136                                 bl += smax3;
137                 }
138         }
139         return lit;
140 }
141
142 static int R_FloatAddDynamicLights (msurface_t *surf)
143 {
144         int lnum, s, t, smax, tmax, smax3, lit, impacts, impactt;
145         float sdtable[256], *bl, k, dist, dist2, maxdist, maxdist2, maxdist3, td1, td, red, green, blue, impact[3], local[3], subtract;
146
147         lit = false;
148
149         smax = (surf->extents[0] >> 4) + 1;
150         tmax = (surf->extents[1] >> 4) + 1;
151         smax3 = smax * 3;
152
153         for (lnum = 0; lnum < r_numdlights; lnum++)
154         {
155                 if (!(surf->dlightbits[lnum >> 5] & (1 << (lnum & 31))))
156                         continue;                                       // not lit by this light
157
158                 softwareuntransform(r_dlight[lnum].origin, local);
159                 dist = DotProduct (local, surf->plane->normal) - surf->plane->dist;
160
161                 // for comparisons to minimum acceptable light
162                 // compensate for LIGHTOFFSET
163                 maxdist = (int) r_dlight[lnum].cullradius2 + LIGHTOFFSET;
164
165                 dist2 = dist * dist;
166                 dist2 += LIGHTOFFSET;
167                 if (dist2 >= maxdist)
168                         continue;
169
170                 if (surf->plane->type < 3)
171                 {
172                         VectorCopy(local, impact);
173                         impact[surf->plane->type] -= dist;
174                 }
175                 else
176                 {
177                         impact[0] = local[0] - surf->plane->normal[0] * dist;
178                         impact[1] = local[1] - surf->plane->normal[1] * dist;
179                         impact[2] = local[2] - surf->plane->normal[2] * dist;
180                 }
181
182                 impacts = DotProduct (impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3] - surf->texturemins[0];
183                 impactt = DotProduct (impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3] - surf->texturemins[1];
184
185                 td = bound(0, impacts, smax * 16) - impacts;
186                 td1 = bound(0, impactt, tmax * 16) - impactt;
187                 td = td * td + td1 * td1 + dist2;
188                 if (td > maxdist)
189                         continue;
190
191                 // reduce calculations
192                 for (s = 0, td1 = impacts; s < smax; s++, td1 -= 16.0f)
193                         sdtable[s] = td1 * td1 + dist2;
194
195                 maxdist3 = maxdist - dist2;
196
197                 // convert to 8.8 blocklights format
198                 red = r_dlight[lnum].light[0];
199                 green = r_dlight[lnum].light[1];
200                 blue = r_dlight[lnum].light[2];
201                 subtract = r_dlight[lnum].subtract * 32768.0f;
202                 bl = floatblocklights;
203
204                 td1 = impactt;
205                 for (t = 0;t < tmax;t++, td1 -= 16.0f)
206                 {
207                         td = td1 * td1;
208                         // make sure some part of it is visible on this line
209                         if (td < maxdist3)
210                         {
211                                 maxdist2 = maxdist - td;
212                                 for (s = 0;s < smax;s++)
213                                 {
214                                         if (sdtable[s] < maxdist2)
215                                         {
216                                                 k = (32768.0f / (sdtable[s] + td)) - subtract;
217                                                 bl[0] += red   * k;
218                                                 bl[1] += green * k;
219                                                 bl[2] += blue  * k;
220                                                 lit = true;
221                                         }
222                                         bl += 3;
223                                 }
224                         }
225                         else // skip line
226                                 bl += smax3;
227                 }
228         }
229         return lit;
230 }
231
232 /*
233 ===============
234 R_BuildLightMap
235
236 Combine and scale multiple lightmaps into the 8.8 format in blocklights
237 ===============
238 */
239 static void R_BuildLightMap (const entity_render_t *ent, msurface_t *surf, int dlightchanged)
240 {
241         if (!r_floatbuildlightmap.integer)
242         {
243                 int smax, tmax, i, j, size, size3, shift, maps, stride, l;
244                 unsigned int *bl, scale;
245                 qbyte *lightmap, *out, *stain;
246
247                 // update cached lighting info
248                 surf->cached_dlight = 0;
249                 surf->cached_lightscalebit = lightscalebit;
250                 surf->cached_ambient = r_ambient.value;
251                 surf->cached_light[0] = d_lightstylevalue[surf->styles[0]];
252                 surf->cached_light[1] = d_lightstylevalue[surf->styles[1]];
253                 surf->cached_light[2] = d_lightstylevalue[surf->styles[2]];
254                 surf->cached_light[3] = d_lightstylevalue[surf->styles[3]];
255
256                 smax = (surf->extents[0]>>4)+1;
257                 tmax = (surf->extents[1]>>4)+1;
258                 size = smax*tmax;
259                 size3 = size*3;
260                 lightmap = surf->samples;
261
262         // set to full bright if no light data
263                 bl = intblocklights;
264                 if ((ent->effects & EF_FULLBRIGHT) || !ent->model->lightdata)
265                 {
266                         for (i = 0;i < size3;i++)
267                                 bl[i] = 255*256;
268                 }
269                 else
270                 {
271         // clear to no light
272                         j = r_ambient.value * 512.0f; // would be 128.0f logically, but using 512.0f to match winquake style
273                         if (j)
274                         {
275                                 for (i = 0;i < size3;i++)
276                                         *bl++ = j;
277                         }
278                         else
279                                 memset(bl, 0, size*3*sizeof(unsigned int));
280
281                         if (surf->dlightframe == r_framecount && r_dlightmap.integer)
282                         {
283                                 surf->cached_dlight = R_IntAddDynamicLights(surf);
284                                 if (surf->cached_dlight)
285                                         c_light_polys++;
286                                 else if (dlightchanged)
287                                         return; // don't upload if only updating dlights and none mattered
288                         }
289
290         // add all the lightmaps
291                         if (lightmap)
292                         {
293                                 bl = intblocklights;
294                                 for (maps = 0;maps < MAXLIGHTMAPS && surf->styles[maps] != 255;maps++, lightmap += size3)
295                                         for (scale = d_lightstylevalue[surf->styles[maps]], i = 0;i < size3;i++)
296                                                 bl[i] += lightmap[i] * scale;
297                         }
298                 }
299
300                 stain = surf->stainsamples;
301                 bl = intblocklights;
302                 out = templight;
303                 // deal with lightmap brightness scale
304                 shift = 7 + lightscalebit + 8;
305                 if (ent->model->lightmaprgba)
306                 {
307                         stride = (surf->lightmaptexturestride - smax) * 4;
308                         for (i = 0;i < tmax;i++, out += stride)
309                         {
310                                 for (j = 0;j < smax;j++)
311                                 {
312                                         l = (*bl++ * *stain++) >> shift;*out++ = min(l, 255);
313                                         l = (*bl++ * *stain++) >> shift;*out++ = min(l, 255);
314                                         l = (*bl++ * *stain++) >> shift;*out++ = min(l, 255);
315                                         *out++ = 255;
316                                 }
317                         }
318                 }
319                 else
320                 {
321                         stride = (surf->lightmaptexturestride - smax) * 3;
322                         for (i = 0;i < tmax;i++, out += stride)
323                         {
324                                 for (j = 0;j < smax;j++)
325                                 {
326                                         l = (*bl++ * *stain++) >> shift;*out++ = min(l, 255);
327                                         l = (*bl++ * *stain++) >> shift;*out++ = min(l, 255);
328                                         l = (*bl++ * *stain++) >> shift;*out++ = min(l, 255);
329                                 }
330                         }
331                 }
332
333                 R_UpdateTexture(surf->lightmaptexture, templight);
334         }
335         else
336         {
337                 int smax, tmax, i, j, size, size3, maps, stride, l;
338                 float *bl, scale;
339                 qbyte *lightmap, *out, *stain;
340
341                 // update cached lighting info
342                 surf->cached_dlight = 0;
343                 surf->cached_lightscalebit = lightscalebit;
344                 surf->cached_ambient = r_ambient.value;
345                 surf->cached_light[0] = d_lightstylevalue[surf->styles[0]];
346                 surf->cached_light[1] = d_lightstylevalue[surf->styles[1]];
347                 surf->cached_light[2] = d_lightstylevalue[surf->styles[2]];
348                 surf->cached_light[3] = d_lightstylevalue[surf->styles[3]];
349
350                 smax = (surf->extents[0]>>4)+1;
351                 tmax = (surf->extents[1]>>4)+1;
352                 size = smax*tmax;
353                 size3 = size*3;
354                 lightmap = surf->samples;
355
356         // set to full bright if no light data
357                 bl = floatblocklights;
358                 if ((ent->effects & EF_FULLBRIGHT) || !ent->model->lightdata)
359                         j = 255*256;
360                 else
361                         j = r_ambient.value * 512.0f; // would be 128.0f logically, but using 512.0f to match winquake style
362
363                 // clear to no light
364                 if (j)
365                 {
366                         for (i = 0;i < size3;i++)
367                                 *bl++ = j;
368                 }
369                 else
370                         memset(bl, 0, size*3*sizeof(float));
371
372                 if (surf->dlightframe == r_framecount && r_dlightmap.integer)
373                 {
374                         surf->cached_dlight = R_FloatAddDynamicLights(surf);
375                         if (surf->cached_dlight)
376                                 c_light_polys++;
377                         else if (dlightchanged)
378                                 return; // don't upload if only updating dlights and none mattered
379                 }
380
381                 // add all the lightmaps
382                 if (lightmap)
383                 {
384                         bl = floatblocklights;
385                         for (maps = 0;maps < MAXLIGHTMAPS && surf->styles[maps] != 255;maps++, lightmap += size3)
386                                 for (scale = d_lightstylevalue[surf->styles[maps]], i = 0;i < size3;i++)
387                                         bl[i] += lightmap[i] * scale;
388                 }
389
390                 stain = surf->stainsamples;
391                 bl = floatblocklights;
392                 out = templight;
393                 // deal with lightmap brightness scale
394                 scale = 1.0f / (1 << (7 + lightscalebit + 8));
395                 if (ent->model->lightmaprgba)
396                 {
397                         stride = (surf->lightmaptexturestride - smax) * 4;
398                         for (i = 0;i < tmax;i++, out += stride)
399                         {
400                                 for (j = 0;j < smax;j++)
401                                 {
402                                         l = *bl++ * *stain++ * scale;*out++ = min(l, 255);
403                                         l = *bl++ * *stain++ * scale;*out++ = min(l, 255);
404                                         l = *bl++ * *stain++ * scale;*out++ = min(l, 255);
405                                         *out++ = 255;
406                                 }
407                         }
408                 }
409                 else
410                 {
411                         stride = (surf->lightmaptexturestride - smax) * 3;
412                         for (i = 0;i < tmax;i++, out += stride)
413                         {
414                                 for (j = 0;j < smax;j++)
415                                 {
416                                         l = *bl++ * *stain++ * scale;*out++ = min(l, 255);
417                                         l = *bl++ * *stain++ * scale;*out++ = min(l, 255);
418                                         l = *bl++ * *stain++ * scale;*out++ = min(l, 255);
419                                 }
420                         }
421                 }
422
423                 R_UpdateTexture(surf->lightmaptexture, templight);
424         }
425 }
426
427 void R_StainNode (mnode_t *node, model_t *model, vec3_t origin, float radius, int icolor[8])
428 {
429         float ndist;
430         msurface_t *surf, *endsurf;
431         int sdtable[256], td, maxdist, maxdist2, maxdist3, i, s, t, smax, tmax, smax3, dist2, impacts, impactt, subtract, a, stained, cr, cg, cb, ca, ratio;
432         qbyte *bl;
433         vec3_t impact;
434         // LordHavoc: use 64bit integer...  shame it's not very standardized...
435 #if _MSC_VER || __BORLANDC__
436         __int64     k;
437 #else
438         long long   k;
439 #endif
440
441
442         // for comparisons to minimum acceptable light
443         // compensate for 256 offset
444         maxdist = radius * radius + 256.0f;
445
446         // clamp radius to avoid exceeding 32768 entry division table
447         if (maxdist > 4194304)
448                 maxdist = 4194304;
449
450         subtract = (int) ((1.0f / maxdist) * 4194304.0f);
451
452 loc0:
453         if (node->contents < 0)
454                 return;
455         ndist = PlaneDiff(origin, node->plane);
456         if (ndist > radius)
457         {
458                 node = node->children[0];
459                 goto loc0;
460         }
461         if (ndist < -radius)
462         {
463                 node = node->children[1];
464                 goto loc0;
465         }
466
467         dist2 = ndist * ndist + 256.0f;
468         if (dist2 < maxdist)
469         {
470                 maxdist3 = maxdist - dist2;
471
472                 if (node->plane->type < 3)
473                 {
474                         VectorCopy(origin, impact);
475                         impact[node->plane->type] -= ndist;
476                 }
477                 else
478                 {
479                         impact[0] = origin[0] - node->plane->normal[0] * ndist;
480                         impact[1] = origin[1] - node->plane->normal[1] * ndist;
481                         impact[2] = origin[2] - node->plane->normal[2] * ndist;
482                 }
483
484                 for (surf = model->surfaces + node->firstsurface, endsurf = surf + node->numsurfaces;surf < endsurf;surf++)
485                 {
486                         if (surf->stainsamples)
487                         {
488                                 smax = (surf->extents[0] >> 4) + 1;
489                                 tmax = (surf->extents[1] >> 4) + 1;
490
491                                 impacts = DotProduct (impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3] - surf->texturemins[0];
492                                 impactt = DotProduct (impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3] - surf->texturemins[1];
493
494                                 s = bound(0, impacts, smax * 16) - impacts;
495                                 t = bound(0, impactt, tmax * 16) - impactt;
496                                 i = s * s + t * t + dist2;
497                                 if (i > maxdist)
498                                         continue;
499
500                                 // reduce calculations
501                                 for (s = 0, i = impacts; s < smax; s++, i -= 16)
502                                         sdtable[s] = i * i + dist2;
503
504                                 // convert to 8.8 blocklights format
505                                 bl = surf->stainsamples;
506                                 smax3 = smax * 3;
507                                 stained = false;
508
509                                 i = impactt;
510                                 for (t = 0;t < tmax;t++, i -= 16)
511                                 {
512                                         td = i * i;
513                                         // make sure some part of it is visible on this line
514                                         if (td < maxdist3)
515                                         {
516                                                 maxdist2 = maxdist - td;
517                                                 for (s = 0;s < smax;s++)
518                                                 {
519                                                         if (sdtable[s] < maxdist2)
520                                                         {
521                                                                 k = dlightdivtable[(sdtable[s] + td) >> 7] - subtract;
522                                                                 if (k > 0)
523                                                                 {
524                                                                         ratio = rand() & 255;
525                                                                         ca = (((icolor[7] - icolor[3]) * ratio) >> 8) + icolor[3];
526                                                                         a = (ca * k) >> 8;
527                                                                         if (a > 0)
528                                                                         {
529                                                                                 a = bound(0, a, 256);
530                                                                                 cr = (((icolor[4] - icolor[0]) * ratio) >> 8) + icolor[0];
531                                                                                 cg = (((icolor[5] - icolor[1]) * ratio) >> 8) + icolor[1];
532                                                                                 cb = (((icolor[6] - icolor[2]) * ratio) >> 8) + icolor[2];
533                                                                                 bl[0] = (qbyte) ((((cr - (int) bl[0]) * a) >> 8) + (int) bl[0]);
534                                                                                 bl[1] = (qbyte) ((((cg - (int) bl[1]) * a) >> 8) + (int) bl[1]);
535                                                                                 bl[2] = (qbyte) ((((cb - (int) bl[2]) * a) >> 8) + (int) bl[2]);
536                                                                                 stained = true;
537                                                                         }
538                                                                 }
539                                                         }
540                                                         bl += 3;
541                                                 }
542                                         }
543                                         else // skip line
544                                                 bl += smax3;
545                                 }
546                                 // force lightmap upload
547                                 if (stained)
548                                         surf->cached_dlight = true;
549                         }
550                 }
551         }
552
553         if (node->children[0]->contents >= 0)
554         {
555                 if (node->children[1]->contents >= 0)
556                 {
557                         R_StainNode(node->children[0], model, origin, radius, icolor);
558                         node = node->children[1];
559                         goto loc0;
560                 }
561                 else
562                 {
563                         node = node->children[0];
564                         goto loc0;
565                 }
566         }
567         else if (node->children[1]->contents >= 0)
568         {
569                 node = node->children[1];
570                 goto loc0;
571         }
572 }
573
574 void R_Stain (vec3_t origin, float radius, int cr1, int cg1, int cb1, int ca1, int cr2, int cg2, int cb2, int ca2)
575 {
576         int n, icolor[8];
577         entity_render_t *ent;
578         model_t *model;
579         vec3_t org;
580         icolor[0] = cr1;
581         icolor[1] = cg1;
582         icolor[2] = cb1;
583         icolor[3] = ca1;
584         icolor[4] = cr2;
585         icolor[5] = cg2;
586         icolor[6] = cb2;
587         icolor[7] = ca2;
588
589         model = cl.worldmodel;
590         R_StainNode(model->nodes + model->hulls[0].firstclipnode, model, origin, radius, icolor);
591
592         // look for embedded bmodels
593         for (n = 0;n < cl_num_brushmodel_entities;n++)
594         {
595                 ent = cl_brushmodel_entities[n];
596                 model = ent->model;
597                 if (model && model->name[0] == '*')
598                 {
599                         Mod_CheckLoaded(model);
600                         if (model->type == mod_brush)
601                         {
602                                 Matrix4x4_Transform(&ent->inversematrix, origin, org);
603                                 R_StainNode(model->nodes + model->hulls[0].firstclipnode, model, org, radius, icolor);
604                         }
605                 }
606         }
607 }
608
609
610 /*
611 =============================================================
612
613         BRUSH MODELS
614
615 =============================================================
616 */
617
618 static void RSurf_CopyXYZ(const surfvertex_t *in, float *out, int numverts)
619 {
620         int i;
621         for (i = 0;i < numverts;i++, in++, out += 4)
622         {
623                 VectorCopy(in->v, out);
624                 out[3] = 1;
625         }
626 }
627
628 static void RSurf_CopyST(const surfvertex_t *in, float *out, int numverts)
629 {
630         int i;
631         for (i = 0;i < numverts;i++, in++, out += 2)
632         {
633                 out[0] = in->st[0];
634                 out[1] = in->st[1];
635         }
636 }
637
638 static void RSurf_CopyUV(const surfvertex_t *in, float *out, int numverts)
639 {
640         int i;
641         for (i = 0;i < numverts;i++, in++, out += 2)
642         {
643                 out[0] = in->uv[0];
644                 out[1] = in->uv[1];
645         }
646 }
647
648 static void RSurf_CopyAB(const surfvertex_t *in, float *out, int numverts)
649 {
650         int i;
651         for (i = 0;i < numverts;i++, in++, out += 2)
652         {
653                 out[0] = in->ab[0];
654                 out[1] = in->ab[1];
655         }
656 }
657
658 static void RSurf_AddLightmapToVertexColors(const surfvertex_t *in, float *c, int numverts, const qbyte *samples, int size3, const qbyte *styles)
659 {
660         int i;
661         float scale;
662         const qbyte *lm;
663         if (styles[0] != 255)
664         {
665                 for (i = 0;i < numverts;i++, in++, c += 4)
666                 {
667                         lm = samples + in->lightmapoffset;
668                         scale = d_lightstylevalue[styles[0]] * (1.0f / 32768.0f);
669                         VectorMA(c, scale, lm, c);
670                         if (styles[1] != 255)
671                         {
672                                 lm += size3;
673                                 scale = d_lightstylevalue[styles[1]] * (1.0f / 32768.0f);
674                                 VectorMA(c, scale, lm, c);
675                                 if (styles[2] != 255)
676                                 {
677                                         lm += size3;
678                                         scale = d_lightstylevalue[styles[2]] * (1.0f / 32768.0f);
679                                         VectorMA(c, scale, lm, c);
680                                         if (styles[3] != 255)
681                                         {
682                                                 lm += size3;
683                                                 scale = d_lightstylevalue[styles[3]] * (1.0f / 32768.0f);
684                                                 VectorMA(c, scale, lm, c);
685                                         }
686                                 }
687                         }
688                 }
689         }
690 }
691
692 static void RSurf_FogColors(const float *v, float *c, float colorscale, int numverts, const float *modelorg)
693 {
694         int i;
695         float diff[3], f;
696         if (fogenabled)
697         {
698                 for (i = 0;i < numverts;i++, v += 4, c += 4)
699                 {
700                         VectorSubtract(v, modelorg, diff);
701                         f = colorscale * (1 - exp(fogdensity/DotProduct(diff, diff)));
702                         VectorScale(c, f, c);
703                 }
704         }
705         else if (colorscale != 1)
706                 for (i = 0;i < numverts;i++, c += 4)
707                         VectorScale(c, colorscale, c);
708 }
709
710 static void RSurf_FoggedColors(const float *v, float *c, float r, float g, float b, float a, float colorscale, int numverts, const float *modelorg)
711 {
712         int i;
713         float diff[3], f;
714         r *= colorscale;
715         g *= colorscale;
716         b *= colorscale;
717         if (fogenabled)
718         {
719                 for (i = 0;i < numverts;i++, v += 4, c += 4)
720                 {
721                         VectorSubtract(v, modelorg, diff);
722                         f = 1 - exp(fogdensity/DotProduct(diff, diff));
723                         c[0] = r * f;
724                         c[1] = g * f;
725                         c[2] = b * f;
726                         c[3] = a;
727                 }
728         }
729         else
730         {
731                 for (i = 0;i < numverts;i++, c += 4)
732                 {
733                         c[0] = r;
734                         c[1] = g;
735                         c[2] = b;
736                         c[3] = a;
737                 }
738         }
739 }
740
741 static void RSurf_FogPassColors(const float *v, float *c, float r, float g, float b, float a, float colorscale, int numverts, const float *modelorg)
742 {
743         int i;
744         float diff[3], f;
745         r *= colorscale;
746         g *= colorscale;
747         b *= colorscale;
748         for (i = 0;i < numverts;i++, v += 4, c += 4)
749         {
750                 VectorSubtract(v, modelorg, diff);
751                 f = exp(fogdensity/DotProduct(diff, diff));
752                 c[0] = r;
753                 c[1] = g;
754                 c[2] = b;
755                 c[3] = a * f;
756         }
757 }
758
759 static void RSurf_ScaleColors(float *c, float scale, int numverts)
760 {
761         int i;
762         if (scale != 1)
763                 for (i = 0;i < numverts;i++, c += 4)
764                         VectorScale(c, scale, c);
765 }
766
767 static int RSurf_LightSeparate(const matrix4x4_t *matrix, const int *dlightbits, int numverts, const float *vert, float *color)
768 {
769         float f;
770         const float *v;
771         float *c;
772         int i, l, lit = false;
773         rdlight_t *rd;
774         vec3_t lightorigin;
775         for (l = 0;l < r_numdlights;l++)
776         {
777                 if (dlightbits[l >> 5] & (1 << (l & 31)))
778                 {
779                         rd = &r_dlight[l];
780                         Matrix4x4_Transform(matrix, rd->origin, lightorigin);
781                         for (i = 0, v = vert, c = color;i < numverts;i++, v += 4, c += 4)
782                         {
783                                 f = VectorDistance2(v, lightorigin) + LIGHTOFFSET;
784                                 if (f < rd->cullradius2)
785                                 {
786                                         f = (1.0f / f) - rd->subtract;
787                                         VectorMA(c, f, rd->light, c);
788                                         lit = true;
789                                 }
790                         }
791                 }
792         }
793         return lit;
794 }
795
796 // note: this untransforms lights to do the checking,
797 // and takes surf->mesh->vertex data
798 static int RSurf_LightCheck(const int *dlightbits, surfmesh_t *mesh)
799 {
800         int i, l;
801         rdlight_t *rd;
802         vec3_t lightorigin;
803         surfvertex_t *sv;
804         for (l = 0;l < r_numdlights;l++)
805         {
806                 if (dlightbits[l >> 5] & (1 << (l & 31)))
807                 {
808                         rd = &r_dlight[l];
809                         softwareuntransform(rd->origin, lightorigin);
810                         for (i = 0, sv = mesh->vertex;i < mesh->numverts;i++, sv++)
811                                 if (VectorDistance2(sv->v, lightorigin) < rd->cullradius2)
812                                         return true;
813                 }
814         }
815         return false;
816 }
817
818 static void RSurfShader_Sky(const entity_render_t *ent, const msurface_t *firstsurf)
819 {
820         const msurface_t *surf;
821         surfmesh_t *mesh;
822         rmeshbufferinfo_t m;
823
824         // LordHavoc: HalfLife maps have freaky skypolys...
825         if (ent->model->ishlbsp)
826                 return;
827
828         if (skyrendernow)
829         {
830                 skyrendernow = false;
831                 if (skyrendermasked)
832                         R_Sky();
833         }
834
835         // draw depth-only polys
836         memset(&m, 0, sizeof(m));
837         if (skyrendermasked)
838         {
839                 m.blendfunc1 = GL_ZERO;
840                 m.blendfunc2 = GL_ONE;
841         }
842         else
843         {
844                 // fog sky
845                 m.blendfunc1 = GL_ONE;
846                 m.blendfunc2 = GL_ZERO;
847         }
848         m.depthwrite = true;
849         m.matrix = ent->matrix;
850         for (surf = firstsurf;surf;surf = surf->chain)
851         {
852                 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
853                 {
854                         m.numtriangles = mesh->numtriangles;
855                         m.numverts = mesh->numverts;
856                         if (R_Mesh_Draw_GetBuffer(&m, false))
857                         {
858                                 memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
859                                 RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
860                                 if (skyrendermasked)
861                                         memset(m.color, 0, m.numverts * sizeof(float[4]));
862                                 else
863                                         R_FillColors(m.color, m.numverts, fogcolor[0] * m.colorscale, fogcolor[1] * m.colorscale, fogcolor[2] * m.colorscale, 1);
864                                 R_Mesh_Render();
865                         }
866                 }
867         }
868 }
869
870 static void RSurfShader_Water_Callback(const void *calldata1, int calldata2)
871 {
872         const entity_render_t *ent = calldata1;
873         msurface_t *surf = ent->model->surfaces + calldata2;
874         float f;
875         surfmesh_t *mesh;
876         rmeshbufferinfo_t m;
877         float alpha = ent->alpha * (surf->flags & SURF_DRAWNOALPHA ? 1 : r_wateralpha.value);
878         float modelorg[3];
879         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
880
881         memset(&m, 0, sizeof(m));
882         if (ent->effects & EF_ADDITIVE)
883         {
884                 m.blendfunc1 = GL_SRC_ALPHA;
885                 m.blendfunc2 = GL_ONE;
886         }
887         else if (surf->currenttexture->fogtexture != NULL || alpha < 1)
888         {
889                 m.blendfunc1 = GL_SRC_ALPHA;
890                 m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
891         }
892         else
893         {
894                 m.blendfunc1 = GL_ONE;
895                 m.blendfunc2 = GL_ZERO;
896         }
897         m.tex[0] = R_GetTexture(surf->currenttexture->texture);
898         m.matrix = ent->matrix;
899         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
900         {
901                 m.numtriangles = mesh->numtriangles;
902                 m.numverts = mesh->numverts;
903                 if (R_Mesh_Draw_GetBuffer(&m, true))
904                 {
905                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
906                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
907                         RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
908                         f = surf->flags & SURF_DRAWFULLBRIGHT ? 1.0f : ((surf->flags & SURF_LIGHTMAP) ? 0 : 0.5f);
909                         R_FillColors(m.color, m.numverts, f, f, f, alpha);
910                         if (!(surf->flags & SURF_DRAWFULLBRIGHT || ent->effects & EF_FULLBRIGHT))
911                         {
912                                 if (surf->dlightframe == r_framecount)
913                                         RSurf_LightSeparate(&ent->inversematrix, surf->dlightbits, m.numverts, m.vertex, m.color);
914                                 if (surf->flags & SURF_LIGHTMAP)
915                                         RSurf_AddLightmapToVertexColors(mesh->vertex, m.color, m.numverts, surf->samples, ((surf->extents[0]>>4)+1)*((surf->extents[1]>>4)+1)*3, surf->styles);
916                         }
917                         RSurf_FogColors(m.vertex, m.color, m.colorscale, m.numverts, modelorg);
918                         R_Mesh_Render();
919                 }
920         }
921
922         if (fogenabled)
923         {
924                 memset(&m, 0, sizeof(m));
925                 m.blendfunc1 = GL_SRC_ALPHA;
926                 m.blendfunc2 = GL_ONE;
927                 m.tex[0] = R_GetTexture(surf->currenttexture->fogtexture);
928                 m.matrix = ent->matrix;
929                 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
930                 {
931                         m.numtriangles = mesh->numtriangles;
932                         m.numverts = mesh->numverts;
933                         if (R_Mesh_Draw_GetBuffer(&m, false))
934                         {
935                                 memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
936                                 RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
937                                 if (m.tex[0])
938                                         RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
939                                 RSurf_FogPassColors(m.vertex, m.color, fogcolor[0], fogcolor[1], fogcolor[2], alpha, m.colorscale, m.numverts, modelorg);
940                                 R_Mesh_Render();
941                         }
942                 }
943         }
944 }
945
946 static void RSurfShader_Water(const entity_render_t *ent, const msurface_t *firstsurf)
947 {
948         const msurface_t *surf;
949         vec3_t center;
950         for (surf = firstsurf;surf;surf = surf->chain)
951         {
952                 if ((r_wateralpha.value < 1 && !(surf->flags & SURF_DRAWNOALPHA)) || ent->effects & EF_ADDITIVE || surf->currenttexture->fogtexture)
953                 {
954                         Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
955                         R_MeshQueue_AddTransparent(center, RSurfShader_Water_Callback, ent, surf - ent->model->surfaces);
956                 }
957                 else
958                         R_MeshQueue_Add(RSurfShader_Water_Callback, ent, surf - ent->model->surfaces);
959         }
960 }
961
962 static void RSurfShader_Wall_Pass_BaseVertex(const entity_render_t *ent, const msurface_t *surf)
963 {
964         float base;
965         surfmesh_t *mesh;
966         rmeshbufferinfo_t m;
967         float modelorg[3];
968         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
969         memset(&m, 0, sizeof(m));
970         if (ent->effects & EF_ADDITIVE)
971         {
972                 m.blendfunc1 = GL_SRC_ALPHA;
973                 m.blendfunc2 = GL_ONE;
974         }
975         else if (surf->currenttexture->fogtexture != NULL || ent->alpha < 1)
976         {
977                 m.blendfunc1 = GL_SRC_ALPHA;
978                 m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
979         }
980         else
981         {
982                 m.blendfunc1 = GL_ONE;
983                 m.blendfunc2 = GL_ZERO;
984         }
985         m.tex[0] = R_GetTexture(surf->currenttexture->texture);
986         base = ent->effects & EF_FULLBRIGHT ? 2.0f : r_ambient.value * (1.0f / 64.0f);
987         m.matrix = ent->matrix;
988         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
989         {
990                 m.numtriangles = mesh->numtriangles;
991                 m.numverts = mesh->numverts;
992                 if (R_Mesh_Draw_GetBuffer(&m, true))
993                 {
994                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
995                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
996                         RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
997                         R_FillColors(m.color, m.numverts, base, base, base, ent->alpha);
998                         if (!(ent->effects & EF_FULLBRIGHT))
999                         {
1000                                 if (surf->dlightframe == r_framecount)
1001                                         RSurf_LightSeparate(&ent->inversematrix, surf->dlightbits, m.numverts, m.vertex, m.color);
1002                                 if (surf->flags & SURF_LIGHTMAP)
1003                                         RSurf_AddLightmapToVertexColors(mesh->vertex, m.color, m.numverts, surf->samples, ((surf->extents[0]>>4)+1)*((surf->extents[1]>>4)+1)*3, surf->styles);
1004                         }
1005                         RSurf_FogColors(m.vertex, m.color, m.colorscale, m.numverts, modelorg);
1006                         R_Mesh_Render();
1007                 }
1008         }
1009 }
1010
1011 static void RSurfShader_Wall_Pass_BaseFullbright(const entity_render_t *ent, const msurface_t *surf)
1012 {
1013         surfmesh_t *mesh;
1014         rmeshbufferinfo_t m;
1015         float modelorg[3];
1016         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
1017         memset(&m, 0, sizeof(m));
1018         if (ent->effects & EF_ADDITIVE)
1019         {
1020                 m.blendfunc1 = GL_SRC_ALPHA;
1021                 m.blendfunc2 = GL_ONE;
1022         }
1023         else if (surf->currenttexture->fogtexture != NULL || ent->alpha < 1)
1024         {
1025                 m.blendfunc1 = GL_SRC_ALPHA;
1026                 m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
1027         }
1028         else
1029         {
1030                 m.blendfunc1 = GL_ONE;
1031                 m.blendfunc2 = GL_ZERO;
1032         }
1033         m.tex[0] = R_GetTexture(surf->currenttexture->texture);
1034         m.matrix = ent->matrix;
1035         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1036         {
1037                 m.numtriangles = mesh->numtriangles;
1038                 m.numverts = mesh->numverts;
1039                 if (R_Mesh_Draw_GetBuffer(&m, false))
1040                 {
1041                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1042                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1043                         RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1044                         RSurf_FoggedColors(m.vertex, m.color, 1, 1, 1, ent->alpha, m.colorscale, m.numverts, modelorg);
1045                         R_Mesh_Render();
1046                 }
1047         }
1048 }
1049
1050 static void RSurfShader_Wall_Pass_Glow(const entity_render_t *ent, const msurface_t *surf)
1051 {
1052         surfmesh_t *mesh;
1053         rmeshbufferinfo_t m;
1054         float modelorg[3];
1055         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
1056         memset(&m, 0, sizeof(m));
1057         m.blendfunc1 = GL_SRC_ALPHA;
1058         m.blendfunc2 = GL_ONE;
1059         m.tex[0] = R_GetTexture(surf->currenttexture->glowtexture);
1060         m.matrix = ent->matrix;
1061         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1062         {
1063                 m.numtriangles = mesh->numtriangles;
1064                 m.numverts = mesh->numverts;
1065                 if (R_Mesh_Draw_GetBuffer(&m, false))
1066                 {
1067                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1068                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1069                         RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1070                         RSurf_FoggedColors(m.vertex, m.color, 1, 1, 1, ent->alpha, m.colorscale, m.numverts, modelorg);
1071                         R_Mesh_Render();
1072                 }
1073         }
1074 }
1075
1076 static void RSurfShader_Wall_Pass_Fog(const entity_render_t *ent, const msurface_t *surf)
1077 {
1078         surfmesh_t *mesh;
1079         rmeshbufferinfo_t m;
1080         float modelorg[3];
1081         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
1082         memset(&m, 0, sizeof(m));
1083         m.blendfunc1 = GL_SRC_ALPHA;
1084         m.blendfunc2 = GL_ONE;
1085         m.matrix = ent->matrix;
1086         m.tex[0] = R_GetTexture(surf->currenttexture->fogtexture);
1087         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1088         {
1089                 m.numtriangles = mesh->numtriangles;
1090                 m.numverts = mesh->numverts;
1091                 if (R_Mesh_Draw_GetBuffer(&m, false))
1092                 {
1093                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1094                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1095                         if (m.tex[0])
1096                                 RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1097                         RSurf_FogPassColors(m.vertex, m.color, fogcolor[0], fogcolor[1], fogcolor[2], ent->alpha, m.colorscale, m.numverts, modelorg);
1098                         R_Mesh_Render();
1099                 }
1100         }
1101 }
1102
1103 static void RSurfShader_OpaqueWall_Pass_TripleTexCombine(const entity_render_t *ent, const msurface_t *surf)
1104 {
1105         surfmesh_t *mesh;
1106         rmeshbufferinfo_t m;
1107         float cl;
1108         memset(&m, 0, sizeof(m));
1109         m.blendfunc1 = GL_ONE;
1110         m.blendfunc2 = GL_ZERO;
1111         m.tex[0] = R_GetTexture(surf->currenttexture->texture);
1112         m.texrgbscale[0] = 1.0f;
1113         m.tex[1] = R_GetTexture(surf->lightmaptexture);
1114         m.texrgbscale[1] = 4.0f;
1115         m.tex[2] = R_GetTexture(surf->currenttexture->detailtexture);
1116         m.texrgbscale[2] = 2.0f;
1117         m.matrix = ent->matrix;
1118         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1119         {
1120                 m.numtriangles = mesh->numtriangles;
1121                 m.numverts = mesh->numverts;
1122                 if (R_Mesh_Draw_GetBuffer(&m, false))
1123                 {
1124                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1125                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1126                         cl = (float) (1 << lightscalebit) * m.colorscale;
1127                         R_FillColors(m.color, m.numverts, cl, cl, cl, 1);
1128                         RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1129                         RSurf_CopyUV(mesh->vertex, m.texcoords[1], m.numverts);
1130                         RSurf_CopyAB(mesh->vertex, m.texcoords[2], m.numverts);
1131                         R_Mesh_Render();
1132                 }
1133         }
1134 }
1135
1136 static void RSurfShader_OpaqueWall_Pass_BaseMTex(const entity_render_t *ent, const msurface_t *surf)
1137 {
1138         surfmesh_t *mesh;
1139         rmeshbufferinfo_t m;
1140         float cl;
1141         memset(&m, 0, sizeof(m));
1142         m.blendfunc1 = GL_ONE;
1143         m.blendfunc2 = GL_ZERO;
1144         m.tex[0] = R_GetTexture(surf->currenttexture->texture);
1145         m.tex[1] = R_GetTexture(surf->lightmaptexture);
1146         m.matrix = ent->matrix;
1147         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1148         {
1149                 m.numtriangles = mesh->numtriangles;
1150                 m.numverts = mesh->numverts;
1151                 if (R_Mesh_Draw_GetBuffer(&m, true))
1152                 {
1153                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1154                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1155                         cl = (float) (1 << lightscalebit) * m.colorscale;
1156                         R_FillColors(m.color, m.numverts, cl, cl, cl, 1);
1157                         RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1158                         RSurf_CopyUV(mesh->vertex, m.texcoords[1], m.numverts);
1159                         R_Mesh_Render();
1160                 }
1161         }
1162 }
1163
1164 static void RSurfShader_OpaqueWall_Pass_BaseTexture(const entity_render_t *ent, const msurface_t *surf)
1165 {
1166         surfmesh_t *mesh;
1167         rmeshbufferinfo_t m;
1168         float cl;
1169         memset(&m, 0, sizeof(m));
1170         m.blendfunc1 = GL_ONE;
1171         m.blendfunc2 = GL_ZERO;
1172         m.tex[0] = R_GetTexture(surf->currenttexture->texture);
1173         m.matrix = ent->matrix;
1174         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1175         {
1176                 m.numtriangles = mesh->numtriangles;
1177                 m.numverts = mesh->numverts;
1178                 if (R_Mesh_Draw_GetBuffer(&m, false))
1179                 {
1180                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1181                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1182                         cl = m.colorscale;
1183                         R_FillColors(m.color, m.numverts, cl, cl, cl, 1);
1184                         RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1185                         R_Mesh_Render();
1186                 }
1187         }
1188 }
1189
1190 static void RSurfShader_OpaqueWall_Pass_BaseLightmap(const entity_render_t *ent, const msurface_t *surf)
1191 {
1192         surfmesh_t *mesh;
1193         rmeshbufferinfo_t m;
1194         float cl;
1195         memset(&m, 0, sizeof(m));
1196         m.blendfunc1 = GL_ZERO;
1197         m.blendfunc2 = GL_SRC_COLOR;
1198         m.tex[0] = R_GetTexture(surf->lightmaptexture);
1199         m.matrix = ent->matrix;
1200         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1201         {
1202                 m.numtriangles = mesh->numtriangles;
1203                 m.numverts = mesh->numverts;
1204                 if (R_Mesh_Draw_GetBuffer(&m, true))
1205                 {
1206                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1207                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1208                         cl = (float) (1 << lightscalebit) * m.colorscale;
1209                         R_FillColors(m.color, m.numverts, cl, cl, cl, 1);
1210                         RSurf_CopyUV(mesh->vertex, m.texcoords[0], m.numverts);
1211                         R_Mesh_Render();
1212                 }
1213         }
1214 }
1215
1216 static void RSurfShader_OpaqueWall_Pass_Light(const entity_render_t *ent, const msurface_t *surf)
1217 {
1218         surfmesh_t *mesh;
1219         rmeshbufferinfo_t m;
1220
1221         if (surf->dlightframe != r_framecount)
1222                 return;
1223         if (ent->effects & EF_FULLBRIGHT)
1224                 return;
1225
1226         memset(&m, 0, sizeof(m));
1227         m.blendfunc1 = GL_SRC_ALPHA;
1228         m.blendfunc2 = GL_ONE;
1229         m.tex[0] = R_GetTexture(surf->currenttexture->texture);
1230         m.matrix = ent->matrix;
1231         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1232         {
1233                 if (RSurf_LightCheck(surf->dlightbits, mesh))
1234                 {
1235                         m.numtriangles = mesh->numtriangles;
1236                         m.numverts = mesh->numverts;
1237                         if (R_Mesh_Draw_GetBuffer(&m, true))
1238                         {
1239                                 memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1240                                 RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1241                                 RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1242                                 R_FillColors(m.color, m.numverts, 0, 0, 0, 1);
1243                                 RSurf_LightSeparate(&ent->inversematrix, surf->dlightbits, m.numverts, m.vertex, m.color);
1244                                 RSurf_ScaleColors(m.color, m.colorscale, m.numverts);
1245                                 R_Mesh_Render();
1246                         }
1247                 }
1248         }
1249 }
1250
1251 static void RSurfShader_OpaqueWall_Pass_Fog(const entity_render_t *ent, const msurface_t *surf)
1252 {
1253         surfmesh_t *mesh;
1254         rmeshbufferinfo_t m;
1255         float modelorg[3];
1256         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
1257         memset(&m, 0, sizeof(m));
1258         m.blendfunc1 = GL_SRC_ALPHA;
1259         m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
1260         m.tex[0] = R_GetTexture(surf->currenttexture->fogtexture);
1261         m.matrix = ent->matrix;
1262         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1263         {
1264                 m.numtriangles = mesh->numtriangles;
1265                 m.numverts = mesh->numverts;
1266                 if (R_Mesh_Draw_GetBuffer(&m, false))
1267                 {
1268                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1269                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1270                         if (m.tex[0])
1271                                 RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1272                         RSurf_FogPassColors(m.vertex, m.color, fogcolor[0], fogcolor[1], fogcolor[2], 1, m.colorscale, m.numverts, modelorg);
1273                         R_Mesh_Render();
1274                 }
1275         }
1276 }
1277
1278 static void RSurfShader_OpaqueWall_Pass_BaseDetail(const entity_render_t *ent, const msurface_t *surf)
1279 {
1280         surfmesh_t *mesh;
1281         rmeshbufferinfo_t m;
1282         memset(&m, 0, sizeof(m));
1283         m.blendfunc1 = GL_DST_COLOR;
1284         m.blendfunc2 = GL_SRC_COLOR;
1285         m.tex[0] = R_GetTexture(surf->currenttexture->detailtexture);
1286         m.matrix = ent->matrix;
1287         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1288         {
1289                 m.numtriangles = mesh->numtriangles;
1290                 m.numverts = mesh->numverts;
1291                 if (R_Mesh_Draw_GetBuffer(&m, false))
1292                 {
1293                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1294                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1295                         R_FillColors(m.color, m.numverts, 1, 1, 1, 1);
1296                         RSurf_CopyAB(mesh->vertex, m.texcoords[0], m.numverts);
1297                         R_Mesh_Render();
1298                 }
1299         }
1300 }
1301
1302 static void RSurfShader_OpaqueWall_Pass_Glow(const entity_render_t *ent, const msurface_t *surf)
1303 {
1304         surfmesh_t *mesh;
1305         rmeshbufferinfo_t m;
1306         memset(&m, 0, sizeof(m));
1307         m.blendfunc1 = GL_SRC_ALPHA;
1308         m.blendfunc2 = GL_ONE;
1309         m.tex[0] = R_GetTexture(surf->currenttexture->glowtexture);
1310         m.matrix = ent->matrix;
1311         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1312         {
1313                 m.numtriangles = mesh->numtriangles;
1314                 m.numverts = mesh->numverts;
1315                 if (R_Mesh_Draw_GetBuffer(&m, false))
1316                 {
1317                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1318                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1319                         R_FillColors(m.color, m.numverts, m.colorscale, m.colorscale, m.colorscale, 1);
1320                         RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1321                         R_Mesh_Render();
1322                 }
1323         }
1324 }
1325
1326 static void RSurfShader_Wall_Fullbright_Callback(const void *calldata1, int calldata2)
1327 {
1328         const entity_render_t *ent = calldata1;
1329         const msurface_t *surf = ent->model->surfaces + calldata2;
1330         RSurfShader_Wall_Pass_BaseFullbright(ent, surf);
1331         if (surf->currenttexture->glowtexture)
1332                 RSurfShader_Wall_Pass_Glow(ent, surf);
1333         if (fogenabled)
1334                 RSurfShader_Wall_Pass_Fog(ent, surf);
1335 }
1336
1337 static void RSurfShader_Wall_Fullbright(const entity_render_t *ent, const msurface_t *firstsurf)
1338 {
1339         const msurface_t *surf;
1340         vec3_t center;
1341         if (ent->effects & EF_ADDITIVE || ent->alpha < 1)
1342         {
1343                 for (surf = firstsurf;surf;surf = surf->chain)
1344                 {
1345                         c_brush_polys++;
1346                         Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
1347                         R_MeshQueue_AddTransparent(center, RSurfShader_Wall_Fullbright_Callback, ent, surf - ent->model->surfaces);
1348                 }
1349         }
1350         else
1351         {
1352                 for (surf = firstsurf;surf;surf = surf->chain)
1353                 {
1354                         c_brush_polys++;
1355                         if (surf->currenttexture->fogtexture != NULL)
1356                         {
1357                                 Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
1358                                 R_MeshQueue_AddTransparent(center, RSurfShader_Wall_Fullbright_Callback, ent, surf - ent->model->surfaces);
1359                         }
1360                         else
1361                                 RSurfShader_Wall_Pass_BaseFullbright(ent, surf);
1362                 }
1363                 for (surf = firstsurf;surf;surf = surf->chain)
1364                         if (surf->currenttexture->glowtexture)
1365                                 if (surf->currenttexture->fogtexture == NULL)
1366                                         RSurfShader_Wall_Pass_Glow(ent, surf);
1367                 if (fogenabled)
1368                         for (surf = firstsurf;surf;surf = surf->chain)
1369                                 if (surf->currenttexture->fogtexture == NULL)
1370                                         RSurfShader_Wall_Pass_Fog(ent, surf);
1371         }
1372 }
1373
1374 static void RSurfShader_Wall_Vertex_Callback(const void *calldata1, int calldata2)
1375 {
1376         const entity_render_t *ent = calldata1;
1377         const msurface_t *surf = ent->model->surfaces + calldata2;
1378         RSurfShader_Wall_Pass_BaseVertex(ent, surf);
1379         if (surf->currenttexture->glowtexture)
1380                 RSurfShader_Wall_Pass_Glow(ent, surf);
1381         if (fogenabled)
1382                 RSurfShader_Wall_Pass_Fog(ent, surf);
1383 }
1384
1385 static void RSurfShader_Wall_Vertex(const entity_render_t *ent, const msurface_t *firstsurf)
1386 {
1387         const msurface_t *surf;
1388         vec3_t center;
1389         if (ent->effects & EF_ADDITIVE || ent->alpha < 1)
1390         {
1391                 for (surf = firstsurf;surf;surf = surf->chain)
1392                 {
1393                         c_brush_polys++;
1394                         Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
1395                         R_MeshQueue_AddTransparent(center, RSurfShader_Wall_Vertex_Callback, ent, surf - ent->model->surfaces);
1396                 }
1397         }
1398         else
1399         {
1400                 for (surf = firstsurf;surf;surf = surf->chain)
1401                 {
1402                         c_brush_polys++;
1403                         if (surf->currenttexture->fogtexture != NULL)
1404                         {
1405                                 Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
1406                                 R_MeshQueue_AddTransparent(center, RSurfShader_Wall_Vertex_Callback, ent, surf - ent->model->surfaces);
1407                         }
1408                         else
1409                                 RSurfShader_Wall_Pass_BaseVertex(ent, surf);
1410                 }
1411                 for (surf = firstsurf;surf;surf = surf->chain)
1412                         if (surf->currenttexture->glowtexture)
1413                                 if (surf->currenttexture->fogtexture == NULL)
1414                                         RSurfShader_Wall_Pass_Glow(ent, surf);
1415                 if (fogenabled)
1416                         for (surf = firstsurf;surf;surf = surf->chain)
1417                                 if (surf->currenttexture->fogtexture == NULL)
1418                                         RSurfShader_Wall_Pass_Fog(ent, surf);
1419         }
1420 }
1421
1422 static void RSurfShader_Wall_Lightmap(const entity_render_t *ent, const msurface_t *firstsurf)
1423 {
1424         const msurface_t *surf;
1425         vec3_t center;
1426         if (ent->alpha < 1 || ent->effects & EF_ADDITIVE)
1427         {
1428                 for (surf = firstsurf;surf;surf = surf->chain)
1429                 {
1430                         c_brush_polys++;
1431                         Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
1432                         R_MeshQueue_AddTransparent(center, RSurfShader_Wall_Vertex_Callback, ent, surf - ent->model->surfaces);
1433                 }
1434         }
1435         else if (r_vertexsurfaces.integer || ent->alpha < 1 || ent->effects & EF_ADDITIVE)
1436         {
1437                 for (surf = firstsurf;surf;surf = surf->chain)
1438                 {
1439                         c_brush_polys++;
1440                         if (surf->currenttexture->fogtexture != NULL)
1441                         {
1442                                 Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
1443                                 R_MeshQueue_AddTransparent(center, RSurfShader_Wall_Vertex_Callback, ent, surf - ent->model->surfaces);
1444                         }
1445                         else
1446                                 RSurfShader_Wall_Pass_BaseVertex(ent, surf);
1447                 }
1448                 for (surf = firstsurf;surf;surf = surf->chain)
1449                         if (surf->currenttexture->glowtexture)
1450                                 if (surf->currenttexture->fogtexture == NULL)
1451                                         RSurfShader_Wall_Pass_Glow(ent, surf);
1452                 if (fogenabled)
1453                         for (surf = firstsurf;surf;surf = surf->chain)
1454                                 if (surf->currenttexture->fogtexture == NULL)
1455                                         RSurfShader_Wall_Pass_Fog(ent, surf);
1456         }
1457         else
1458         {
1459                 if (r_textureunits.integer >= 2)
1460                 {
1461                         if (r_textureunits.integer >= 3 && gl_combine.integer && r_detailtextures.integer)
1462                         {
1463                                 for (surf = firstsurf;surf;surf = surf->chain)
1464                                 {
1465                                         c_brush_polys++;
1466                                         if (surf->currenttexture->fogtexture != NULL)
1467                                         {
1468                                                 Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
1469                                                 R_MeshQueue_AddTransparent(center, RSurfShader_Wall_Vertex_Callback, ent, surf - ent->model->surfaces);
1470                                         }
1471                                         else
1472                                                 RSurfShader_OpaqueWall_Pass_TripleTexCombine(ent, surf);
1473                                 }
1474                         }
1475                         else
1476                         {
1477                                 for (surf = firstsurf;surf;surf = surf->chain)
1478                                 {
1479                                         c_brush_polys++;
1480                                         if (surf->currenttexture->fogtexture != NULL)
1481                                         {
1482                                                 Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
1483                                                 R_MeshQueue_AddTransparent(center, RSurfShader_Wall_Vertex_Callback, ent, surf - ent->model->surfaces);
1484                                         }
1485                                         else
1486                                                 RSurfShader_OpaqueWall_Pass_BaseMTex(ent, surf);
1487                                 }
1488                                 if (r_detailtextures.integer)
1489                                         for (surf = firstsurf;surf;surf = surf->chain)
1490                                                 if (surf->currenttexture->fogtexture == NULL)
1491                                                         RSurfShader_OpaqueWall_Pass_BaseDetail(ent, surf);
1492                         }
1493                 }
1494                 else
1495                 {
1496                         for (surf = firstsurf;surf;surf = surf->chain)
1497                         {
1498                                 c_brush_polys++;
1499                                 if (surf->currenttexture->fogtexture != NULL)
1500                                 {
1501                                         Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
1502                                         R_MeshQueue_AddTransparent(center, RSurfShader_Wall_Vertex_Callback, ent, surf - ent->model->surfaces);
1503                                 }
1504                                 else
1505                                         RSurfShader_OpaqueWall_Pass_BaseTexture(ent, surf);
1506                         }
1507                         for (surf = firstsurf;surf;surf = surf->chain)
1508                                 if (surf->currenttexture->fogtexture == NULL)
1509                                         RSurfShader_OpaqueWall_Pass_BaseLightmap(ent, surf);
1510                         if (r_detailtextures.integer)
1511                                 for (surf = firstsurf;surf;surf = surf->chain)
1512                                         if (surf->currenttexture->fogtexture == NULL)
1513                                                 RSurfShader_OpaqueWall_Pass_BaseDetail(ent, surf);
1514                 }
1515                 if (!r_dlightmap.integer)
1516                         for (surf = firstsurf;surf;surf = surf->chain)
1517                                 if (surf->dlightframe == r_framecount)
1518                                         if (surf->currenttexture->fogtexture == NULL)
1519                                                 RSurfShader_OpaqueWall_Pass_Light(ent, surf);
1520                 for (surf = firstsurf;surf;surf = surf->chain)
1521                         if (surf->currenttexture->glowtexture)
1522                                 if (surf->currenttexture->fogtexture == NULL)
1523                                         RSurfShader_OpaqueWall_Pass_Glow(ent, surf);
1524                 if (fogenabled)
1525                         for (surf = firstsurf;surf;surf = surf->chain)
1526                                 if (surf->currenttexture->fogtexture == NULL)
1527                                         RSurfShader_OpaqueWall_Pass_Fog(ent, surf);
1528         }
1529 }
1530
1531 /*
1532 =============================================================
1533
1534         WORLD MODEL
1535
1536 =============================================================
1537 */
1538
1539 static void R_SolidWorldNode (entity_render_t *ent)
1540 {
1541         if (r_viewleaf->contents != CONTENTS_SOLID)
1542         {
1543                 int portalstack;
1544                 mportal_t *p, *pstack[8192];
1545                 msurface_t *surf, **mark, **endmark;
1546                 mleaf_t *leaf;
1547                 // LordHavoc: portal-passage worldnode; follows portals leading
1548                 // outward from viewleaf, if a portal leads offscreen it is not
1549                 // followed, in indoor maps this can often cull a great deal of
1550                 // geometry away when pvs data is not present (useful with pvs as well)
1551
1552                 leaf = r_viewleaf;
1553                 leaf->worldnodeframe = r_framecount;
1554                 portalstack = 0;
1555         loc0:
1556                 c_leafs++;
1557
1558                 leaf->visframe = r_framecount;
1559
1560                 if (leaf->nummarksurfaces)
1561                 {
1562                         mark = leaf->firstmarksurface;
1563                         endmark = mark + leaf->nummarksurfaces;
1564                         do
1565                         {
1566                                 surf = *mark++;
1567                                 // make sure surfaces are only processed once
1568                                 if (surf->worldnodeframe == r_framecount)
1569                                         continue;
1570                                 surf->worldnodeframe = r_framecount;
1571                                 if (PlaneDist(r_origin, surf->plane) < surf->plane->dist)
1572                                 {
1573                                         if (surf->flags & SURF_PLANEBACK)
1574                                                 surf->visframe = r_framecount;
1575                                 }
1576                                 else
1577                                 {
1578                                         if (!(surf->flags & SURF_PLANEBACK))
1579                                                 surf->visframe = r_framecount;
1580                                 }
1581                         }
1582                         while (mark < endmark);
1583                 }
1584
1585                 // follow portals into other leafs
1586                 p = leaf->portals;
1587                 for (;p;p = p->next)
1588                 {
1589                         if (DotProduct(r_origin, p->plane.normal) < p->plane.dist)
1590                         {
1591                                 leaf = p->past;
1592                                 if (leaf->worldnodeframe != r_framecount)
1593                                 {
1594                                         leaf->worldnodeframe = r_framecount;
1595                                         if (leaf->contents != CONTENTS_SOLID)
1596                                         {
1597                                                 if (R_NotCulledBox(leaf->mins, leaf->maxs))
1598                                                 {
1599                                                         p->visframe = r_framecount;
1600                                                         pstack[portalstack++] = p;
1601                                                         goto loc0;
1602
1603         loc1:
1604                                                         p = pstack[--portalstack];
1605                                                 }
1606                                         }
1607                                 }
1608                         }
1609                 }
1610
1611                 if (portalstack)
1612                         goto loc1;
1613         }
1614         else
1615         {
1616                 mnode_t *nodestack[8192], *node = cl.worldmodel->nodes;
1617                 int nodestackpos = 0;
1618                 // LordHavoc: recursive descending worldnode; if portals are not
1619                 // available, this is a good last resort, can cull large amounts of
1620                 // geometry, but is more time consuming than portal-passage and renders
1621                 // things behind walls
1622
1623 loc2:
1624                 if (R_NotCulledBox(node->mins, node->maxs))
1625                 {
1626                         if (node->numsurfaces)
1627                         {
1628                                 msurface_t *surf = cl.worldmodel->surfaces + node->firstsurface, *surfend = surf + node->numsurfaces;
1629                                 if (PlaneDiff (r_origin, node->plane) < 0)
1630                                 {
1631                                         for (;surf < surfend;surf++)
1632                                         {
1633                                                 if (surf->flags & SURF_PLANEBACK)
1634                                                         surf->visframe = r_framecount;
1635                                         }
1636                                 }
1637                                 else
1638                                 {
1639                                         for (;surf < surfend;surf++)
1640                                         {
1641                                                 if (!(surf->flags & SURF_PLANEBACK))
1642                                                         surf->visframe = r_framecount;
1643                                         }
1644                                 }
1645                         }
1646
1647                         // recurse down the children
1648                         if (node->children[0]->contents >= 0)
1649                         {
1650                                 if (node->children[1]->contents >= 0)
1651                                 {
1652                                         if (nodestackpos < 8192)
1653                                                 nodestack[nodestackpos++] = node->children[1];
1654                                         node = node->children[0];
1655                                         goto loc2;
1656                                 }
1657                                 else
1658                                         ((mleaf_t *)node->children[1])->visframe = r_framecount;
1659                                 node = node->children[0];
1660                                 goto loc2;
1661                         }
1662                         else
1663                         {
1664                                 ((mleaf_t *)node->children[0])->visframe = r_framecount;
1665                                 if (node->children[1]->contents >= 0)
1666                                 {
1667                                         node = node->children[1];
1668                                         goto loc2;
1669                                 }
1670                                 else if (nodestackpos > 0)
1671                                 {
1672                                         ((mleaf_t *)node->children[1])->visframe = r_framecount;
1673                                         node = nodestack[--nodestackpos];
1674                                         goto loc2;
1675                                 }
1676                         }
1677                 }
1678                 else if (nodestackpos > 0)
1679                 {
1680                         node = nodestack[--nodestackpos];
1681                         goto loc2;
1682                 }
1683         }
1684 }
1685
1686 static void R_PVSWorldNode()
1687 {
1688         int portalstack, i;
1689         mportal_t *p, *pstack[8192];
1690         msurface_t *surf, **mark, **endmark;
1691         mleaf_t *leaf;
1692         qbyte *worldvis;
1693
1694         worldvis = Mod_LeafPVS (r_viewleaf, cl.worldmodel);
1695
1696         leaf = r_viewleaf;
1697         leaf->worldnodeframe = r_framecount;
1698         portalstack = 0;
1699 loc0:
1700         c_leafs++;
1701
1702         leaf->visframe = r_framecount;
1703
1704         if (leaf->nummarksurfaces)
1705         {
1706                 mark = leaf->firstmarksurface;
1707                 endmark = mark + leaf->nummarksurfaces;
1708                 do
1709                 {
1710                         surf = *mark++;
1711                         // make sure surfaces are only processed once
1712                         if (surf->worldnodeframe == r_framecount)
1713                                 continue;
1714                         surf->worldnodeframe = r_framecount;
1715                         if (PlaneDist(r_origin, surf->plane) < surf->plane->dist)
1716                         {
1717                                 if (surf->flags & SURF_PLANEBACK)
1718                                         surf->visframe = r_framecount;
1719                         }
1720                         else
1721                         {
1722                                 if (!(surf->flags & SURF_PLANEBACK))
1723                                         surf->visframe = r_framecount;
1724                         }
1725                 }
1726                 while (mark < endmark);
1727         }
1728
1729         // follow portals into other leafs
1730         for (p = leaf->portals;p;p = p->next)
1731         {
1732                 if (DotProduct(r_origin, p->plane.normal) < p->plane.dist)
1733                 {
1734                         leaf = p->past;
1735                         if (leaf->worldnodeframe != r_framecount)
1736                         {
1737                                 leaf->worldnodeframe = r_framecount;
1738                                 if (leaf->contents != CONTENTS_SOLID)
1739                                 {
1740                                         i = (leaf - cl.worldmodel->leafs) - 1;
1741                                         if (worldvis[i>>3] & (1<<(i&7)))
1742                                         {
1743                                                 if (R_NotCulledBox(leaf->mins, leaf->maxs))
1744                                                 {
1745                                                         pstack[portalstack++] = p;
1746                                                         goto loc0;
1747
1748 loc1:
1749                                                         p = pstack[--portalstack];
1750                                                 }
1751                                         }
1752                                 }
1753                         }
1754                 }
1755         }
1756
1757         if (portalstack)
1758                 goto loc1;
1759 }
1760
1761 Cshader_t Cshader_wall_vertex = {{NULL, RSurfShader_Wall_Vertex}, NULL};
1762 Cshader_t Cshader_wall_lightmap = {{NULL, RSurfShader_Wall_Lightmap}, NULL};
1763 Cshader_t Cshader_wall_fullbright = {{NULL, RSurfShader_Wall_Fullbright}, NULL};
1764 Cshader_t Cshader_water = {{NULL, RSurfShader_Water}, NULL};
1765 Cshader_t Cshader_sky = {{RSurfShader_Sky, NULL}, NULL};
1766
1767 int Cshader_count = 5;
1768 Cshader_t *Cshaders[5] =
1769 {
1770         &Cshader_wall_vertex,
1771         &Cshader_wall_lightmap,
1772         &Cshader_wall_fullbright,
1773         &Cshader_water,
1774         &Cshader_sky
1775 };
1776
1777 void R_PrepareSurfaces(entity_render_t *ent)
1778 {
1779         int i, alttextures, texframe, framecount;
1780         texture_t *t;
1781         model_t *model;
1782         msurface_t *surf;
1783
1784         for (i = 0;i < Cshader_count;i++)
1785                 Cshaders[i]->chain = NULL;
1786
1787         model = ent->model;
1788         alttextures = ent->frame != 0;
1789         texframe = (int)(cl.time * 5.0f);
1790
1791         for (i = 0;i < model->nummodelsurfaces;i++)
1792         {
1793                 surf = model->modelsortedsurfaces[i];
1794                 if (surf->visframe == r_framecount)
1795                 {
1796                         if (surf->insertframe != r_framecount)
1797                         {
1798                                 surf->insertframe = r_framecount;
1799                                 c_faces++;
1800                                 t = surf->texinfo->texture;
1801                                 if (t->animated)
1802                                 {
1803                                         framecount = t->anim_total[alttextures];
1804                                         if (framecount >= 2)
1805                                                 surf->currenttexture = t->anim_frames[alttextures][texframe % framecount];
1806                                         else
1807                                                 surf->currenttexture = t->anim_frames[alttextures][0];
1808                                 }
1809                                 else
1810                                         surf->currenttexture = t;
1811                         }
1812
1813                         surf->chain = surf->shader->chain;
1814                         surf->shader->chain = surf;
1815                 }
1816         }
1817 }
1818
1819 void R_DrawSurfaces (entity_render_t *ent, int type)
1820 {
1821         int                     i;
1822         Cshader_t       *shader;
1823
1824         for (i = 0;i < Cshader_count;i++)
1825         {
1826                 shader = Cshaders[i];
1827                 if (shader->chain && shader->shaderfunc[type])
1828                         shader->shaderfunc[type](ent, shader->chain);
1829         }
1830 }
1831
1832 static void R_DrawPortal_Callback(const void *calldata1, int calldata2)
1833 {
1834         int i;
1835         float *v;
1836         rmeshbufferinfo_t m;
1837         const entity_render_t *ent = calldata1;
1838         const mportal_t *portal = ent->model->portals + calldata2;
1839         memset(&m, 0, sizeof(m));
1840         m.blendfunc1 = GL_SRC_ALPHA;
1841         m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
1842         m.numverts = portal->numpoints;
1843         m.numtriangles = portal->numpoints - 2;
1844         m.matrix = ent->matrix;
1845         if (R_Mesh_Draw_GetBuffer(&m, false))
1846         {
1847                 for (i = 0;i < m.numtriangles;i++)
1848                 {
1849                         m.index[i * 3 + 0] = 0;
1850                         m.index[i * 3 + 1] = i + 1;
1851                         m.index[i * 3 + 2] = i + 2;
1852                 }
1853                 i = portal - ent->model->portals;
1854                 R_FillColors(m.color, m.numverts,
1855                         ((i & 0x0007) >> 0) * (1.0f / 7.0f) * m.colorscale,
1856                         ((i & 0x0038) >> 3) * (1.0f / 7.0f) * m.colorscale,
1857                         ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * m.colorscale,
1858                         0.125f);
1859                 if (PlaneDiff(r_origin, (&portal->plane)) > 0)
1860                 {
1861                         for (i = portal->numpoints - 1, v = m.vertex;i >= 0;i--, v += 4)
1862                                 VectorCopy(portal->points[i].position, v);
1863                 }
1864                 else
1865                         for (i = 0, v = m.vertex;i < portal->numpoints;i++, v += 4)
1866                                 VectorCopy(portal->points[i].position, v);
1867                 R_Mesh_Render();
1868         }
1869 }
1870
1871 void R_DrawPortals(entity_render_t *ent)
1872 {
1873         int i;
1874         mportal_t *portal, *endportal;
1875         float temp[3], center[3], f;
1876
1877         if (r_drawportals.integer < 1)
1878                 return;
1879
1880         for (portal = ent->model->portals, endportal = portal + ent->model->numportals;portal < endportal;portal++)
1881         {
1882                 if (portal->here->visframe == r_framecount || portal->past->visframe == r_framecount)
1883                 {
1884                         VectorClear(temp);
1885                         for (i = 0;i < portal->numpoints;i++)
1886                                 VectorAdd(temp, portal->points[i].position, temp);
1887                         f = ixtable[portal->numpoints];
1888                         VectorScale(temp, f, temp);
1889                         Matrix4x4_Transform(&ent->matrix, temp, center);
1890                         R_MeshQueue_AddTransparent(center, R_DrawPortal_Callback, ent, portal - ent->model->portals);
1891                 }
1892         }
1893 }
1894
1895 void R_SetupForBModelRendering(entity_render_t *ent)
1896 {
1897         int                     i;
1898         msurface_t      *surf;
1899         model_t         *model;
1900         vec3_t          modelorg;
1901
1902         // because bmodels can be reused, we have to decide which things to render
1903         // from scratch every time
1904
1905         model = ent->model;
1906
1907         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
1908         for (i = 0;i < model->nummodelsurfaces;i++)
1909         {
1910                 surf = model->modelsortedsurfaces[i];
1911                 if (((surf->flags & SURF_PLANEBACK) == 0) == (PlaneDiff(modelorg, surf->plane) >= 0))
1912                         surf->visframe = r_framecount;
1913                 else
1914                         surf->visframe = -1;
1915                 surf->worldnodeframe = -1;
1916                 surf->lightframe = -1;
1917                 surf->dlightframe = -1;
1918                 surf->insertframe = -1;
1919         }
1920 }
1921
1922 void R_SurfMarkLights (entity_render_t *ent)
1923 {
1924         int                     i;
1925         msurface_t      *surf;
1926
1927         if (r_dynamic.integer)
1928                 R_MarkLights(ent);
1929
1930         if (!r_vertexsurfaces.integer)
1931         {
1932                 for (i = 0;i < ent->model->nummodelsurfaces;i++)
1933                 {
1934                         surf = ent->model->modelsortedsurfaces[i];
1935                         if (surf->visframe == r_framecount && surf->lightmaptexture != NULL)
1936                         {
1937                                 if (surf->cached_dlight
1938                                  || surf->cached_ambient != r_ambient.value
1939                                  || surf->cached_lightscalebit != lightscalebit)
1940                                         R_BuildLightMap(ent, surf, false); // base lighting changed
1941                                 else if (r_dynamic.integer)
1942                                 {
1943                                         if  (surf->styles[0] != 255 && (d_lightstylevalue[surf->styles[0]] != surf->cached_light[0]
1944                                          || (surf->styles[1] != 255 && (d_lightstylevalue[surf->styles[1]] != surf->cached_light[1]
1945                                          || (surf->styles[2] != 255 && (d_lightstylevalue[surf->styles[2]] != surf->cached_light[2]
1946                                          || (surf->styles[3] != 255 && (d_lightstylevalue[surf->styles[3]] != surf->cached_light[3]))))))))
1947                                                 R_BuildLightMap(ent, surf, false); // base lighting changed
1948                                         else if (surf->dlightframe == r_framecount && r_dlightmap.integer)
1949                                                 R_BuildLightMap(ent, surf, true); // only dlights
1950                                 }
1951                         }
1952                 }
1953         }
1954 }
1955
1956 /*
1957 =============
1958 R_DrawWorld
1959 =============
1960 */
1961 void R_DrawWorld (entity_render_t *ent)
1962 {
1963         // there is only one instance of the world, but it can be rendered in
1964         // multiple stages
1965         if (r_viewleaf->contents == CONTENTS_SOLID || r_novis.integer || r_viewleaf->compressed_vis == NULL)
1966                 R_SolidWorldNode (ent);
1967         else
1968                 R_PVSWorldNode (ent);
1969 }
1970
1971 /*
1972 =================
1973 R_DrawBrushModel
1974 =================
1975 */
1976 void R_DrawBrushModelSky (entity_render_t *ent)
1977 {
1978         R_SetupForBModelRendering(ent);
1979
1980         R_PrepareSurfaces(ent);
1981         R_DrawSurfaces(ent, SHADERSTAGE_SKY);
1982 }
1983
1984 void R_DrawBrushModelNormal (entity_render_t *ent)
1985 {
1986         c_bmodels++;
1987
1988         // have to flush queue because of possible lightmap reuse
1989         R_Mesh_Render();
1990
1991         R_SetupForBModelRendering(ent);
1992
1993         R_SurfMarkLights(ent);
1994
1995         R_PrepareSurfaces(ent);
1996
1997         if (!skyrendermasked)
1998                 R_DrawSurfaces(ent, SHADERSTAGE_SKY);
1999         R_DrawSurfaces(ent, SHADERSTAGE_NORMAL);
2000 }
2001
2002 static void gl_surf_start(void)
2003 {
2004 }
2005
2006 static void gl_surf_shutdown(void)
2007 {
2008 }
2009
2010 static void gl_surf_newmap(void)
2011 {
2012 }
2013
2014 void GL_Surf_Init(void)
2015 {
2016         int i;
2017         dlightdivtable[0] = 4194304;
2018         for (i = 1;i < 32768;i++)
2019                 dlightdivtable[i] = 4194304 / (i << 7);
2020
2021         Cvar_RegisterVariable(&r_ambient);
2022         Cvar_RegisterVariable(&r_vertexsurfaces);
2023         Cvar_RegisterVariable(&r_dlightmap);
2024         Cvar_RegisterVariable(&r_drawportals);
2025         Cvar_RegisterVariable(&r_testvis);
2026         Cvar_RegisterVariable(&r_floatbuildlightmap);
2027         Cvar_RegisterVariable(&r_detailtextures);
2028
2029         R_RegisterModule("GL_Surf", gl_surf_start, gl_surf_shutdown, gl_surf_newmap);
2030 }
2031