]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_rsurf.c
most of the framework for hardware accelerated transforms is back, just the actual...
[divverent/darkplaces.git] / gl_rsurf.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // r_surf.c: surface-related refresh code
21
22 #include "quakedef.h"
23
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 * f;
753                 c[1] = g * f;
754                 c[2] = b * f;
755                 c[3] = a;
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                 R_Sky();
832         }
833
834         // draw depth-only polys
835         memset(&m, 0, sizeof(m));
836         m.blendfunc1 = GL_ZERO;
837         m.blendfunc2 = GL_ONE;
838         m.depthwrite = true;
839         m.matrix = ent->matrix;
840         for (surf = firstsurf;surf;surf = surf->chain)
841         {
842                 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
843                 {
844                         m.numtriangles = mesh->numtriangles;
845                         m.numverts = mesh->numverts;
846                         if (R_Mesh_Draw_GetBuffer(&m, false))
847                         {
848                                 memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
849                                 RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
850                                 memset(m.color, 0, m.numverts * sizeof(float[4]));
851                                 R_Mesh_Render();
852                         }
853                 }
854         }
855 }
856
857 static void RSurfShader_Water_Callback(const void *calldata1, int calldata2)
858 {
859         const entity_render_t *ent = calldata1;
860         msurface_t *surf = ent->model->surfaces + calldata2;
861         float f;
862         surfmesh_t *mesh;
863         rmeshbufferinfo_t m;
864         float alpha = ent->alpha * (surf->flags & SURF_DRAWNOALPHA ? 1 : r_wateralpha.value);
865         float modelorg[3];
866         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
867
868         memset(&m, 0, sizeof(m));
869         if (ent->effects & EF_ADDITIVE)
870         {
871                 m.blendfunc1 = GL_SRC_ALPHA;
872                 m.blendfunc2 = GL_ONE;
873         }
874         else if (surf->currenttexture->fogtexture != NULL || alpha < 1)
875         {
876                 m.blendfunc1 = GL_SRC_ALPHA;
877                 m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
878         }
879         else
880         {
881                 m.blendfunc1 = GL_ONE;
882                 m.blendfunc2 = GL_ZERO;
883         }
884         m.tex[0] = R_GetTexture(surf->currenttexture->texture);
885         m.matrix = ent->matrix;
886         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
887         {
888                 m.numtriangles = mesh->numtriangles;
889                 m.numverts = mesh->numverts;
890                 if (R_Mesh_Draw_GetBuffer(&m, true))
891                 {
892                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
893                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
894                         RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
895                         f = surf->flags & SURF_DRAWFULLBRIGHT ? 1.0f : ((surf->flags & SURF_LIGHTMAP) ? 0 : 0.5f);
896                         R_FillColors(m.color, m.numverts, f, f, f, alpha);
897                         if (!(surf->flags & SURF_DRAWFULLBRIGHT || ent->effects & EF_FULLBRIGHT))
898                         {
899                                 if (surf->dlightframe == r_framecount)
900                                         RSurf_LightSeparate(&ent->inversematrix, surf->dlightbits, m.numverts, m.vertex, m.color);
901                                 if (surf->flags & SURF_LIGHTMAP)
902                                         RSurf_AddLightmapToVertexColors(mesh->vertex, m.color, m.numverts, surf->samples, ((surf->extents[0]>>4)+1)*((surf->extents[1]>>4)+1)*3, surf->styles);
903                         }
904                         RSurf_FogColors(m.vertex, m.color, m.colorscale, m.numverts, modelorg);
905                         R_Mesh_Render();
906                 }
907         }
908
909         if (fogenabled)
910         {
911                 memset(&m, 0, sizeof(m));
912                 m.blendfunc1 = GL_SRC_ALPHA;
913                 m.blendfunc2 = GL_ONE;
914                 m.tex[0] = R_GetTexture(surf->currenttexture->fogtexture);
915                 m.matrix = ent->matrix;
916                 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
917                 {
918                         m.numtriangles = mesh->numtriangles;
919                         m.numverts = mesh->numverts;
920                         if (R_Mesh_Draw_GetBuffer(&m, false))
921                         {
922                                 memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
923                                 RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
924                                 if (m.tex[0])
925                                         RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
926                                 RSurf_FogPassColors(m.vertex, m.color, fogcolor[0], fogcolor[1], fogcolor[2], alpha, m.colorscale, m.numverts, modelorg);
927                                 R_Mesh_Render();
928                         }
929                 }
930         }
931 }
932
933 static void RSurfShader_Water(const entity_render_t *ent, const msurface_t *firstsurf)
934 {
935         const msurface_t *surf;
936         for (surf = firstsurf;surf;surf = surf->chain)
937         {
938                 if ((r_wateralpha.value < 1 && !(surf->flags & SURF_DRAWNOALPHA)) || ent->effects & EF_ADDITIVE || surf->currenttexture->fogtexture)
939                         R_MeshQueue_AddTransparent(surf->poly_center, RSurfShader_Water_Callback, ent, surf - ent->model->surfaces);
940                 else
941                         R_MeshQueue_Add(RSurfShader_Water_Callback, ent, surf - ent->model->surfaces);
942         }
943 }
944
945 static void RSurfShader_Wall_Pass_BaseVertex(const entity_render_t *ent, const msurface_t *surf)
946 {
947         float base;
948         surfmesh_t *mesh;
949         rmeshbufferinfo_t m;
950         float modelorg[3];
951         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
952         memset(&m, 0, sizeof(m));
953         if (ent->effects & EF_ADDITIVE)
954         {
955                 m.transparent = true;
956                 m.blendfunc1 = GL_SRC_ALPHA;
957                 m.blendfunc2 = GL_ONE;
958         }
959         else if (surf->currenttexture->fogtexture != NULL || ent->alpha != 1)
960         {
961                 m.transparent = true;
962                 m.blendfunc1 = GL_SRC_ALPHA;
963                 m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
964         }
965         else
966         {
967                 m.blendfunc1 = GL_ONE;
968                 m.blendfunc2 = GL_ZERO;
969         }
970         m.tex[0] = R_GetTexture(surf->currenttexture->texture);
971         base = ent->effects & EF_FULLBRIGHT ? 2.0f : r_ambient.value * (1.0f / 64.0f);
972         m.matrix = ent->matrix;
973         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
974         {
975                 m.numtriangles = mesh->numtriangles;
976                 m.numverts = mesh->numverts;
977                 if (R_Mesh_Draw_GetBuffer(&m, true))
978                 {
979                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
980                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
981                         RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
982                         R_FillColors(m.color, m.numverts, base, base, base, ent->alpha);
983                         if (!(ent->effects & EF_FULLBRIGHT))
984                         {
985                                 if (surf->dlightframe == r_framecount)
986                                         RSurf_LightSeparate(&ent->inversematrix, surf->dlightbits, m.numverts, m.vertex, m.color);
987                                 if (surf->flags & SURF_LIGHTMAP)
988                                         RSurf_AddLightmapToVertexColors(mesh->vertex, m.color, m.numverts, surf->samples, ((surf->extents[0]>>4)+1)*((surf->extents[1]>>4)+1)*3, surf->styles);
989                         }
990                         RSurf_FogColors(m.vertex, m.color, m.colorscale, m.numverts, modelorg);
991                         R_Mesh_Render();
992                 }
993         }
994 }
995
996 static void RSurfShader_Wall_Pass_BaseFullbright(const entity_render_t *ent, const msurface_t *surf)
997 {
998         surfmesh_t *mesh;
999         rmeshbufferinfo_t m;
1000         float modelorg[3];
1001         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
1002         memset(&m, 0, sizeof(m));
1003         if (ent->effects & EF_ADDITIVE)
1004         {
1005                 m.transparent = true;
1006                 m.blendfunc1 = GL_SRC_ALPHA;
1007                 m.blendfunc2 = GL_ONE;
1008         }
1009         else if (surf->currenttexture->fogtexture != NULL || ent->alpha != 1)
1010         {
1011                 m.transparent = true;
1012                 m.blendfunc1 = GL_SRC_ALPHA;
1013                 m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
1014         }
1015         else
1016         {
1017                 m.blendfunc1 = GL_ONE;
1018                 m.blendfunc2 = GL_ZERO;
1019         }
1020         m.tex[0] = R_GetTexture(surf->currenttexture->texture);
1021         m.matrix = ent->matrix;
1022         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1023         {
1024                 m.numtriangles = mesh->numtriangles;
1025                 m.numverts = mesh->numverts;
1026                 if (R_Mesh_Draw_GetBuffer(&m, false))
1027                 {
1028                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1029                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1030                         RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1031                         RSurf_FoggedColors(m.vertex, m.color, 1, 1, 1, ent->alpha, m.colorscale, m.numverts, modelorg);
1032                         R_Mesh_Render();
1033                 }
1034         }
1035 }
1036
1037 static void RSurfShader_Wall_Pass_Glow(const entity_render_t *ent, const msurface_t *surf)
1038 {
1039         surfmesh_t *mesh;
1040         rmeshbufferinfo_t m;
1041         float modelorg[3];
1042         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
1043         memset(&m, 0, sizeof(m));
1044         m.transparent = ent->effects & EF_ADDITIVE || surf->currenttexture->fogtexture != NULL || ent->alpha != 1;
1045         m.blendfunc1 = GL_SRC_ALPHA;
1046         m.blendfunc2 = GL_ONE;
1047         m.tex[0] = R_GetTexture(surf->currenttexture->glowtexture);
1048         m.matrix = ent->matrix;
1049         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1050         {
1051                 m.numtriangles = mesh->numtriangles;
1052                 m.numverts = mesh->numverts;
1053                 if (R_Mesh_Draw_GetBuffer(&m, false))
1054                 {
1055                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1056                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1057                         RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1058                         RSurf_FoggedColors(m.vertex, m.color, 1, 1, 1, ent->alpha, m.colorscale, m.numverts, modelorg);
1059                         R_Mesh_Render();
1060                 }
1061         }
1062 }
1063
1064 static void RSurfShader_Wall_Pass_Fog(const entity_render_t *ent, const msurface_t *surf)
1065 {
1066         surfmesh_t *mesh;
1067         rmeshbufferinfo_t m;
1068         float modelorg[3];
1069         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
1070         memset(&m, 0, sizeof(m));
1071         m.transparent = ent->effects & EF_ADDITIVE || surf->currenttexture->fogtexture != NULL || ent->alpha != 1;
1072         m.blendfunc1 = GL_SRC_ALPHA;
1073         m.blendfunc2 = GL_ONE;
1074         m.matrix = ent->matrix;
1075         m.tex[0] = R_GetTexture(surf->currenttexture->fogtexture);
1076         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1077         {
1078                 m.numtriangles = mesh->numtriangles;
1079                 m.numverts = mesh->numverts;
1080                 if (R_Mesh_Draw_GetBuffer(&m, false))
1081                 {
1082                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1083                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1084                         if (m.tex[0])
1085                                 RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1086                         RSurf_FogPassColors(m.vertex, m.color, fogcolor[0], fogcolor[1], fogcolor[2], ent->alpha, m.colorscale, m.numverts, modelorg);
1087                         R_Mesh_Render();
1088                 }
1089         }
1090 }
1091
1092 static void RSurfShader_OpaqueWall_Pass_TripleTexCombine(const entity_render_t *ent, const msurface_t *surf)
1093 {
1094         surfmesh_t *mesh;
1095         rmeshbufferinfo_t m;
1096         float cl;
1097         memset(&m, 0, sizeof(m));
1098         m.blendfunc1 = GL_ONE;
1099         m.blendfunc2 = GL_ZERO;
1100         m.tex[0] = R_GetTexture(surf->currenttexture->texture);
1101         m.texrgbscale[0] = 1.0f;
1102         m.tex[1] = R_GetTexture(surf->lightmaptexture);
1103         m.texrgbscale[1] = 4.0f;
1104         m.tex[2] = R_GetTexture(surf->currenttexture->detailtexture);
1105         m.texrgbscale[2] = 2.0f;
1106         m.matrix = ent->matrix;
1107         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1108         {
1109                 m.numtriangles = mesh->numtriangles;
1110                 m.numverts = mesh->numverts;
1111                 if (R_Mesh_Draw_GetBuffer(&m, false))
1112                 {
1113                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1114                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1115                         cl = (float) (1 << lightscalebit) * m.colorscale;
1116                         R_FillColors(m.color, m.numverts, cl, cl, cl, 1);
1117                         RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1118                         RSurf_CopyUV(mesh->vertex, m.texcoords[1], m.numverts);
1119                         RSurf_CopyAB(mesh->vertex, m.texcoords[2], m.numverts);
1120                         R_Mesh_Render();
1121                 }
1122         }
1123 }
1124
1125 static void RSurfShader_OpaqueWall_Pass_BaseMTex(const entity_render_t *ent, const msurface_t *surf)
1126 {
1127         surfmesh_t *mesh;
1128         rmeshbufferinfo_t m;
1129         float cl;
1130         memset(&m, 0, sizeof(m));
1131         m.blendfunc1 = GL_ONE;
1132         m.blendfunc2 = GL_ZERO;
1133         m.tex[0] = R_GetTexture(surf->currenttexture->texture);
1134         m.tex[1] = R_GetTexture(surf->lightmaptexture);
1135         m.matrix = ent->matrix;
1136         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1137         {
1138                 m.numtriangles = mesh->numtriangles;
1139                 m.numverts = mesh->numverts;
1140                 if (R_Mesh_Draw_GetBuffer(&m, true))
1141                 {
1142                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1143                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1144                         cl = (float) (1 << lightscalebit) * m.colorscale;
1145                         R_FillColors(m.color, m.numverts, cl, cl, cl, 1);
1146                         RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1147                         RSurf_CopyUV(mesh->vertex, m.texcoords[1], m.numverts);
1148                         R_Mesh_Render();
1149                 }
1150         }
1151 }
1152
1153 static void RSurfShader_OpaqueWall_Pass_BaseTexture(const entity_render_t *ent, const msurface_t *surf)
1154 {
1155         surfmesh_t *mesh;
1156         rmeshbufferinfo_t m;
1157         float cl;
1158         memset(&m, 0, sizeof(m));
1159         m.blendfunc1 = GL_ONE;
1160         m.blendfunc2 = GL_ZERO;
1161         m.tex[0] = R_GetTexture(surf->currenttexture->texture);
1162         m.matrix = ent->matrix;
1163         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1164         {
1165                 m.numtriangles = mesh->numtriangles;
1166                 m.numverts = mesh->numverts;
1167                 if (R_Mesh_Draw_GetBuffer(&m, false))
1168                 {
1169                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1170                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1171                         cl = m.colorscale;
1172                         R_FillColors(m.color, m.numverts, cl, cl, cl, 1);
1173                         RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1174                         R_Mesh_Render();
1175                 }
1176         }
1177 }
1178
1179 static void RSurfShader_OpaqueWall_Pass_BaseLightmap(const entity_render_t *ent, const msurface_t *surf)
1180 {
1181         surfmesh_t *mesh;
1182         rmeshbufferinfo_t m;
1183         float cl;
1184         memset(&m, 0, sizeof(m));
1185         m.blendfunc1 = GL_ZERO;
1186         m.blendfunc2 = GL_SRC_COLOR;
1187         m.tex[0] = R_GetTexture(surf->lightmaptexture);
1188         m.matrix = ent->matrix;
1189         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1190         {
1191                 m.numtriangles = mesh->numtriangles;
1192                 m.numverts = mesh->numverts;
1193                 if (R_Mesh_Draw_GetBuffer(&m, true))
1194                 {
1195                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1196                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1197                         cl = (float) (1 << lightscalebit) * m.colorscale;
1198                         R_FillColors(m.color, m.numverts, cl, cl, cl, 1);
1199                         RSurf_CopyUV(mesh->vertex, m.texcoords[0], m.numverts);
1200                         R_Mesh_Render();
1201                 }
1202         }
1203 }
1204
1205 static void RSurfShader_OpaqueWall_Pass_Light(const entity_render_t *ent, const msurface_t *surf)
1206 {
1207         surfmesh_t *mesh;
1208         rmeshbufferinfo_t m;
1209
1210         if (surf->dlightframe != r_framecount)
1211                 return;
1212         if (ent->effects & EF_FULLBRIGHT)
1213                 return;
1214
1215         memset(&m, 0, sizeof(m));
1216         m.blendfunc1 = GL_SRC_ALPHA;
1217         m.blendfunc2 = GL_ONE;
1218         m.tex[0] = R_GetTexture(surf->currenttexture->texture);
1219         m.matrix = ent->matrix;
1220         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1221         {
1222                 if (RSurf_LightCheck(surf->dlightbits, mesh))
1223                 {
1224                         m.numtriangles = mesh->numtriangles;
1225                         m.numverts = mesh->numverts;
1226                         if (R_Mesh_Draw_GetBuffer(&m, true))
1227                         {
1228                                 memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1229                                 RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1230                                 RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1231                                 R_FillColors(m.color, m.numverts, 0, 0, 0, 1);
1232                                 RSurf_LightSeparate(&ent->inversematrix, surf->dlightbits, m.numverts, m.vertex, m.color);
1233                                 RSurf_ScaleColors(m.color, m.colorscale, m.numverts);
1234                                 R_Mesh_Render();
1235                         }
1236                 }
1237         }
1238 }
1239
1240 static void RSurfShader_OpaqueWall_Pass_Fog(const entity_render_t *ent, const msurface_t *surf)
1241 {
1242         surfmesh_t *mesh;
1243         rmeshbufferinfo_t m;
1244         float modelorg[3];
1245         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
1246         memset(&m, 0, sizeof(m));
1247         m.blendfunc1 = GL_SRC_ALPHA;
1248         m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
1249         m.tex[0] = R_GetTexture(surf->currenttexture->fogtexture);
1250         m.matrix = ent->matrix;
1251         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1252         {
1253                 m.numtriangles = mesh->numtriangles;
1254                 m.numverts = mesh->numverts;
1255                 if (R_Mesh_Draw_GetBuffer(&m, false))
1256                 {
1257                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1258                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1259                         if (m.tex[0])
1260                                 RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1261                         RSurf_FogPassColors(m.vertex, m.color, fogcolor[0], fogcolor[1], fogcolor[2], 1, m.colorscale, m.numverts, modelorg);
1262                         R_Mesh_Render();
1263                 }
1264         }
1265 }
1266
1267 static void RSurfShader_OpaqueWall_Pass_BaseDetail(const entity_render_t *ent, const msurface_t *surf)
1268 {
1269         surfmesh_t *mesh;
1270         rmeshbufferinfo_t m;
1271         memset(&m, 0, sizeof(m));
1272         m.blendfunc1 = GL_DST_COLOR;
1273         m.blendfunc2 = GL_SRC_COLOR;
1274         m.tex[0] = R_GetTexture(surf->currenttexture->detailtexture);
1275         m.matrix = ent->matrix;
1276         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1277         {
1278                 m.numtriangles = mesh->numtriangles;
1279                 m.numverts = mesh->numverts;
1280                 if (R_Mesh_Draw_GetBuffer(&m, false))
1281                 {
1282                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1283                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1284                         R_FillColors(m.color, m.numverts, 1, 1, 1, 1);
1285                         RSurf_CopyAB(mesh->vertex, m.texcoords[0], m.numverts);
1286                         R_Mesh_Render();
1287                 }
1288         }
1289 }
1290
1291 static void RSurfShader_OpaqueWall_Pass_Glow(const entity_render_t *ent, const msurface_t *surf)
1292 {
1293         surfmesh_t *mesh;
1294         rmeshbufferinfo_t m;
1295         memset(&m, 0, sizeof(m));
1296         m.blendfunc1 = GL_SRC_ALPHA;
1297         m.blendfunc2 = GL_ONE;
1298         m.tex[0] = R_GetTexture(surf->currenttexture->glowtexture);
1299         m.matrix = ent->matrix;
1300         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1301         {
1302                 m.numtriangles = mesh->numtriangles;
1303                 m.numverts = mesh->numverts;
1304                 if (R_Mesh_Draw_GetBuffer(&m, false))
1305                 {
1306                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1307                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1308                         R_FillColors(m.color, m.numverts, m.colorscale, m.colorscale, m.colorscale, 1);
1309                         RSurf_CopyAB(mesh->vertex, m.texcoords[0], m.numverts);
1310                         R_Mesh_Render();
1311                 }
1312         }
1313 }
1314
1315 static void RSurfShader_Wall_Fullbright(const entity_render_t *ent, const msurface_t *firstsurf)
1316 {
1317         const msurface_t *surf;
1318         for (surf = firstsurf;surf;surf = surf->chain)
1319         {
1320                 c_brush_polys++;
1321                 RSurfShader_Wall_Pass_BaseFullbright(ent, surf);
1322         }
1323         for (surf = firstsurf;surf;surf = surf->chain)
1324                 if (surf->currenttexture->glowtexture)
1325                         RSurfShader_Wall_Pass_Glow(ent, surf);
1326         if (fogenabled)
1327                 for (surf = firstsurf;surf;surf = surf->chain)
1328                         RSurfShader_Wall_Pass_Fog(ent, surf);
1329 }
1330
1331 static void RSurfShader_Wall_Vertex(const entity_render_t *ent, const msurface_t *firstsurf)
1332 {
1333         const msurface_t *surf;
1334         for (surf = firstsurf;surf;surf = surf->chain)
1335         {
1336                 c_brush_polys++;
1337                 RSurfShader_Wall_Pass_BaseVertex(ent, surf);
1338         }
1339         for (surf = firstsurf;surf;surf = surf->chain)
1340                 if (surf->currenttexture->glowtexture)
1341                         RSurfShader_Wall_Pass_Glow(ent, surf);
1342         if (fogenabled)
1343                 for (surf = firstsurf;surf;surf = surf->chain)
1344                         RSurfShader_Wall_Pass_Fog(ent, surf);
1345 }
1346
1347 static void RSurfShader_Wall_Lightmap(const entity_render_t *ent, const msurface_t *firstsurf)
1348 {
1349         const msurface_t *surf;
1350         if (r_vertexsurfaces.integer || firstsurf->currenttexture->fogtexture != NULL || ent->alpha != 1 || ent->effects & EF_ADDITIVE)
1351         {
1352                 for (surf = firstsurf;surf;surf = surf->chain)
1353                 {
1354                         c_brush_polys++;
1355                         RSurfShader_Wall_Pass_BaseVertex(ent, surf);
1356                 }
1357                 for (surf = firstsurf;surf;surf = surf->chain)
1358                         if (surf->currenttexture->glowtexture)
1359                                 RSurfShader_Wall_Pass_Glow(ent, surf);
1360                 if (fogenabled)
1361                         for (surf = firstsurf;surf;surf = surf->chain)
1362                                 RSurfShader_Wall_Pass_Fog(ent, surf);
1363         }
1364         else
1365         {
1366                 if (r_textureunits.integer >= 2)
1367                 {
1368                         if (r_textureunits.integer >= 3 && gl_combine.integer && r_detailtextures.integer)
1369                         {
1370                                 for (surf = firstsurf;surf;surf = surf->chain)
1371                                 {
1372                                         c_brush_polys++;
1373                                         RSurfShader_OpaqueWall_Pass_TripleTexCombine(ent, surf);
1374                                 }
1375                         }
1376                         else
1377                         {
1378                                 for (surf = firstsurf;surf;surf = surf->chain)
1379                                 {
1380                                         c_brush_polys++;
1381                                         RSurfShader_OpaqueWall_Pass_BaseMTex(ent, surf);
1382                                 }
1383                                 if (r_detailtextures.integer)
1384                                         for (surf = firstsurf;surf;surf = surf->chain)
1385                                                 RSurfShader_OpaqueWall_Pass_BaseDetail(ent, surf);
1386                         }
1387                 }
1388                 else
1389                 {
1390                         for (surf = firstsurf;surf;surf = surf->chain)
1391                         {
1392                                 c_brush_polys++;
1393                                 RSurfShader_OpaqueWall_Pass_BaseTexture(ent, surf);
1394                         }
1395                         for (surf = firstsurf;surf;surf = surf->chain)
1396                                 RSurfShader_OpaqueWall_Pass_BaseLightmap(ent, surf);
1397                         if (r_detailtextures.integer)
1398                                 for (surf = firstsurf;surf;surf = surf->chain)
1399                                         RSurfShader_OpaqueWall_Pass_BaseDetail(ent, surf);
1400                 }
1401                 if (!r_dlightmap.integer)
1402                         for (surf = firstsurf;surf;surf = surf->chain)
1403                                 if (surf->dlightframe == r_framecount)
1404                                         RSurfShader_OpaqueWall_Pass_Light(ent, surf);
1405                 for (surf = firstsurf;surf;surf = surf->chain)
1406                         if (surf->currenttexture->glowtexture)
1407                                 RSurfShader_OpaqueWall_Pass_Glow(ent, surf);
1408                 if (fogenabled)
1409                         for (surf = firstsurf;surf;surf = surf->chain)
1410                                 RSurfShader_OpaqueWall_Pass_Fog(ent, surf);
1411         }
1412 }
1413
1414 /*
1415 =============================================================
1416
1417         WORLD MODEL
1418
1419 =============================================================
1420 */
1421
1422 static void R_SolidWorldNode (entity_render_t *ent)
1423 {
1424         if (r_viewleaf->contents != CONTENTS_SOLID)
1425         {
1426                 int portalstack;
1427                 mportal_t *p, *pstack[8192];
1428                 msurface_t *surf, **mark, **endmark;
1429                 mleaf_t *leaf;
1430                 // LordHavoc: portal-passage worldnode; follows portals leading
1431                 // outward from viewleaf, if a portal leads offscreen it is not
1432                 // followed, in indoor maps this can often cull a great deal of
1433                 // geometry away when pvs data is not present (useful with pvs as well)
1434
1435                 leaf = r_viewleaf;
1436                 leaf->worldnodeframe = r_framecount;
1437                 portalstack = 0;
1438         loc0:
1439                 c_leafs++;
1440
1441                 leaf->visframe = r_framecount;
1442
1443                 if (leaf->nummarksurfaces)
1444                 {
1445                         mark = leaf->firstmarksurface;
1446                         endmark = mark + leaf->nummarksurfaces;
1447                         do
1448                         {
1449                                 surf = *mark++;
1450                                 // make sure surfaces are only processed once
1451                                 if (surf->worldnodeframe == r_framecount)
1452                                         continue;
1453                                 surf->worldnodeframe = r_framecount;
1454                                 if (PlaneDist(r_origin, surf->plane) < surf->plane->dist)
1455                                 {
1456                                         if (surf->flags & SURF_PLANEBACK)
1457                                                 surf->visframe = r_framecount;
1458                                 }
1459                                 else
1460                                 {
1461                                         if (!(surf->flags & SURF_PLANEBACK))
1462                                                 surf->visframe = r_framecount;
1463                                 }
1464                         }
1465                         while (mark < endmark);
1466                 }
1467
1468                 // follow portals into other leafs
1469                 p = leaf->portals;
1470                 for (;p;p = p->next)
1471                 {
1472                         if (DotProduct(r_origin, p->plane.normal) < p->plane.dist)
1473                         {
1474                                 leaf = p->past;
1475                                 if (leaf->worldnodeframe != r_framecount)
1476                                 {
1477                                         leaf->worldnodeframe = r_framecount;
1478                                         if (leaf->contents != CONTENTS_SOLID)
1479                                         {
1480                                                 if (R_NotCulledBox(leaf->mins, leaf->maxs))
1481                                                 {
1482                                                         p->visframe = r_framecount;
1483                                                         pstack[portalstack++] = p;
1484                                                         goto loc0;
1485
1486         loc1:
1487                                                         p = pstack[--portalstack];
1488                                                 }
1489                                         }
1490                                 }
1491                         }
1492                 }
1493
1494                 if (portalstack)
1495                         goto loc1;
1496         }
1497         else
1498         {
1499                 mnode_t *nodestack[8192], *node = cl.worldmodel->nodes;
1500                 int nodestackpos = 0;
1501                 // LordHavoc: recursive descending worldnode; if portals are not
1502                 // available, this is a good last resort, can cull large amounts of
1503                 // geometry, but is more time consuming than portal-passage and renders
1504                 // things behind walls
1505
1506 loc2:
1507                 if (R_NotCulledBox(node->mins, node->maxs))
1508                 {
1509                         if (node->numsurfaces)
1510                         {
1511                                 msurface_t *surf = cl.worldmodel->surfaces + node->firstsurface, *surfend = surf + node->numsurfaces;
1512                                 if (PlaneDiff (r_origin, node->plane) < 0)
1513                                 {
1514                                         for (;surf < surfend;surf++)
1515                                         {
1516                                                 if (surf->flags & SURF_PLANEBACK)
1517                                                         surf->visframe = r_framecount;
1518                                         }
1519                                 }
1520                                 else
1521                                 {
1522                                         for (;surf < surfend;surf++)
1523                                         {
1524                                                 if (!(surf->flags & SURF_PLANEBACK))
1525                                                         surf->visframe = r_framecount;
1526                                         }
1527                                 }
1528                         }
1529
1530                         // recurse down the children
1531                         if (node->children[0]->contents >= 0)
1532                         {
1533                                 if (node->children[1]->contents >= 0)
1534                                 {
1535                                         if (nodestackpos < 8192)
1536                                                 nodestack[nodestackpos++] = node->children[1];
1537                                         node = node->children[0];
1538                                         goto loc2;
1539                                 }
1540                                 else
1541                                         ((mleaf_t *)node->children[1])->visframe = r_framecount;
1542                                 node = node->children[0];
1543                                 goto loc2;
1544                         }
1545                         else
1546                         {
1547                                 ((mleaf_t *)node->children[0])->visframe = r_framecount;
1548                                 if (node->children[1]->contents >= 0)
1549                                 {
1550                                         node = node->children[1];
1551                                         goto loc2;
1552                                 }
1553                                 else if (nodestackpos > 0)
1554                                 {
1555                                         ((mleaf_t *)node->children[1])->visframe = r_framecount;
1556                                         node = nodestack[--nodestackpos];
1557                                         goto loc2;
1558                                 }
1559                         }
1560                 }
1561                 else if (nodestackpos > 0)
1562                 {
1563                         node = nodestack[--nodestackpos];
1564                         goto loc2;
1565                 }
1566         }
1567 }
1568
1569 static int r_portalframecount = 0;
1570
1571 static void R_PVSWorldNode()
1572 {
1573         int portalstack, i;
1574         mportal_t *p, *pstack[8192];
1575         msurface_t *surf, **mark, **endmark;
1576         mleaf_t *leaf;
1577         qbyte *worldvis;
1578
1579         worldvis = Mod_LeafPVS (r_viewleaf, cl.worldmodel);
1580
1581         leaf = r_viewleaf;
1582         leaf->worldnodeframe = r_framecount;
1583         portalstack = 0;
1584 loc0:
1585         c_leafs++;
1586
1587         leaf->visframe = r_framecount;
1588
1589         if (leaf->nummarksurfaces)
1590         {
1591                 mark = leaf->firstmarksurface;
1592                 endmark = mark + leaf->nummarksurfaces;
1593                 do
1594                 {
1595                         surf = *mark++;
1596                         // make sure surfaces are only processed once
1597                         if (surf->worldnodeframe == r_framecount)
1598                                 continue;
1599                         surf->worldnodeframe = r_framecount;
1600                         if (PlaneDist(r_origin, surf->plane) < surf->plane->dist)
1601                         {
1602                                 if (surf->flags & SURF_PLANEBACK)
1603                                         surf->visframe = r_framecount;
1604                         }
1605                         else
1606                         {
1607                                 if (!(surf->flags & SURF_PLANEBACK))
1608                                         surf->visframe = r_framecount;
1609                         }
1610                 }
1611                 while (mark < endmark);
1612         }
1613
1614         // follow portals into other leafs
1615         for (p = leaf->portals;p;p = p->next)
1616         {
1617                 if (DotProduct(r_origin, p->plane.normal) < p->plane.dist)
1618                 {
1619                         leaf = p->past;
1620                         if (leaf->worldnodeframe != r_framecount)
1621                         {
1622                                 leaf->worldnodeframe = r_framecount;
1623                                 if (leaf->contents != CONTENTS_SOLID)
1624                                 {
1625                                         i = (leaf - cl.worldmodel->leafs) - 1;
1626                                         if (worldvis[i>>3] & (1<<(i&7)))
1627                                         {
1628                                                 if (R_NotCulledBox(leaf->mins, leaf->maxs))
1629                                                 {
1630                                                         pstack[portalstack++] = p;
1631                                                         goto loc0;
1632
1633 loc1:
1634                                                         p = pstack[--portalstack];
1635                                                 }
1636                                         }
1637                                 }
1638                         }
1639                 }
1640         }
1641
1642         if (portalstack)
1643                 goto loc1;
1644 }
1645
1646 Cshader_t Cshader_wall_vertex = {{NULL, RSurfShader_Wall_Vertex}, NULL};
1647 Cshader_t Cshader_wall_lightmap = {{NULL, RSurfShader_Wall_Lightmap}, NULL};
1648 Cshader_t Cshader_wall_fullbright = {{NULL, RSurfShader_Wall_Fullbright}, NULL};
1649 Cshader_t Cshader_water = {{NULL, RSurfShader_Water}, NULL};
1650 Cshader_t Cshader_sky = {{RSurfShader_Sky, NULL}, NULL};
1651
1652 int Cshader_count = 5;
1653 Cshader_t *Cshaders[5] =
1654 {
1655         &Cshader_wall_vertex,
1656         &Cshader_wall_lightmap,
1657         &Cshader_wall_fullbright,
1658         &Cshader_water,
1659         &Cshader_sky
1660 };
1661
1662 void R_PrepareSurfaces(entity_render_t *ent)
1663 {
1664         int i, alttextures, texframe, framecount;
1665         texture_t *t;
1666         model_t *model;
1667         msurface_t *surf;
1668
1669         for (i = 0;i < Cshader_count;i++)
1670                 Cshaders[i]->chain = NULL;
1671
1672         model = ent->model;
1673         alttextures = ent->frame != 0;
1674         texframe = (int)(cl.time * 5.0f);
1675
1676         for (i = 0;i < model->nummodelsurfaces;i++)
1677         {
1678                 surf = model->modelsortedsurfaces[i];
1679                 if (surf->visframe == r_framecount)
1680                 {
1681                         if (surf->insertframe != r_framecount)
1682                         {
1683                                 surf->insertframe = r_framecount;
1684                                 c_faces++;
1685                                 t = surf->texinfo->texture;
1686                                 if (t->animated)
1687                                 {
1688                                         framecount = t->anim_total[alttextures];
1689                                         if (framecount >= 2)
1690                                                 surf->currenttexture = t->anim_frames[alttextures][texframe % framecount];
1691                                         else
1692                                                 surf->currenttexture = t->anim_frames[alttextures][0];
1693                                 }
1694                                 else
1695                                         surf->currenttexture = t;
1696                         }
1697
1698                         surf->chain = surf->shader->chain;
1699                         surf->shader->chain = surf;
1700                 }
1701         }
1702 }
1703
1704 void R_DrawSurfaces (entity_render_t *ent, int type)
1705 {
1706         int                     i;
1707         Cshader_t       *shader;
1708
1709         for (i = 0;i < Cshader_count;i++)
1710         {
1711                 shader = Cshaders[i];
1712                 if (shader->chain && shader->shaderfunc[type])
1713                         shader->shaderfunc[type](ent, shader->chain);
1714         }
1715 }
1716
1717 void R_DrawPortals(entity_render_t *ent)
1718 {
1719         int drawportals, i;
1720         float *v;
1721         mportal_t *portal, *endportal;
1722         rmeshbufferinfo_t m;
1723         drawportals = r_drawportals.integer;
1724
1725         if (drawportals < 1)
1726                 return;
1727
1728         for (portal = cl.worldmodel->portals, endportal = portal + cl.worldmodel->numportals;portal < endportal;portal++)
1729         {
1730                 if (portal->visframe == r_portalframecount)
1731                 {
1732                         memset(&m, 0, sizeof(m));
1733                         m.transparent = true;
1734                         m.blendfunc1 = GL_SRC_ALPHA;
1735                         m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
1736                         m.numverts = portal->numpoints;
1737                         m.numtriangles = portal->numpoints - 2;
1738                         Matrix4x4_CreateIdentity(&m.matrix);
1739                         if (R_Mesh_Draw_GetBuffer(&m, false))
1740                         {
1741                                 for (i = 0;i < m.numtriangles;i++)
1742                                 {
1743                                         m.index[i * 3 + 0] = 0;
1744                                         m.index[i * 3 + 1] = i + 1;
1745                                         m.index[i * 3 + 2] = i + 2;
1746                                 }
1747                                 i = portal - cl.worldmodel->portals;
1748                                 R_FillColors(m.color, m.numverts,
1749                                         ((i & 0x0007) >> 0) * (1.0f / 7.0f) * m.colorscale,
1750                                         ((i & 0x0038) >> 3) * (1.0f / 7.0f) * m.colorscale,
1751                                         ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * m.colorscale,
1752                                         0.125f);
1753                                 if (PlaneDiff(r_origin, (&portal->plane)) > 0)
1754                                 {
1755                                         for (i = portal->numpoints - 1, v = m.vertex;i >= 0;i--, v += 4)
1756                                                 VectorCopy(portal->points[i].position, v);
1757                                 }
1758                                 else
1759                                         for (i = 0, v = m.vertex;i < portal->numpoints;i++, v += 4)
1760                                                 VectorCopy(portal->points[i].position, v);
1761                                 R_Mesh_Render();
1762                         }
1763                 }
1764         }
1765 }
1766
1767 void R_SetupForBModelRendering(entity_render_t *ent)
1768 {
1769         int                     i;
1770         msurface_t      *surf;
1771         model_t         *model;
1772         vec3_t          modelorg;
1773
1774         // because bmodels can be reused, we have to decide which things to render
1775         // from scratch every time
1776
1777         model = ent->model;
1778
1779         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
1780         for (i = 0;i < model->nummodelsurfaces;i++)
1781         {
1782                 surf = model->modelsortedsurfaces[i];
1783                 if (((surf->flags & SURF_PLANEBACK) == 0) == (PlaneDiff(modelorg, surf->plane) >= 0))
1784                         surf->visframe = r_framecount;
1785                 else
1786                         surf->visframe = -1;
1787                 surf->worldnodeframe = -1;
1788                 surf->lightframe = -1;
1789                 surf->dlightframe = -1;
1790                 surf->insertframe = -1;
1791         }
1792 }
1793
1794 void R_SetupForWorldRendering(entity_render_t *ent)
1795 {
1796         // there is only one instance of the world, but it can be rendered in
1797         // multiple stages
1798 }
1799
1800 static void R_SurfMarkLights (entity_render_t *ent)
1801 {
1802         int                     i;
1803         msurface_t      *surf;
1804
1805         if (r_dynamic.integer)
1806                 R_MarkLights(ent);
1807
1808         if (!r_vertexsurfaces.integer)
1809         {
1810                 for (i = 0;i < ent->model->nummodelsurfaces;i++)
1811                 {
1812                         surf = ent->model->modelsortedsurfaces[i];
1813                         if (surf->visframe == r_framecount && surf->lightmaptexture != NULL)
1814                         {
1815                                 if (surf->cached_dlight
1816                                  || surf->cached_ambient != r_ambient.value
1817                                  || surf->cached_lightscalebit != lightscalebit)
1818                                         R_BuildLightMap(ent, surf, false); // base lighting changed
1819                                 else if (r_dynamic.integer)
1820                                 {
1821                                         if  (surf->styles[0] != 255 && (d_lightstylevalue[surf->styles[0]] != surf->cached_light[0]
1822                                          || (surf->styles[1] != 255 && (d_lightstylevalue[surf->styles[1]] != surf->cached_light[1]
1823                                          || (surf->styles[2] != 255 && (d_lightstylevalue[surf->styles[2]] != surf->cached_light[2]
1824                                          || (surf->styles[3] != 255 && (d_lightstylevalue[surf->styles[3]] != surf->cached_light[3]))))))))
1825                                                 R_BuildLightMap(ent, surf, false); // base lighting changed
1826                                         else if (surf->dlightframe == r_framecount && r_dlightmap.integer)
1827                                                 R_BuildLightMap(ent, surf, true); // only dlights
1828                                 }
1829                         }
1830                 }
1831         }
1832 }
1833
1834 void R_MarkWorldLights(entity_render_t *ent)
1835 {
1836         R_SetupForWorldRendering(ent);
1837         R_SurfMarkLights(ent);
1838 }
1839
1840 /*
1841 =============
1842 R_DrawWorld
1843 =============
1844 */
1845 void R_DrawWorld (entity_render_t *ent)
1846 {
1847         R_SetupForWorldRendering(ent);
1848
1849         if (r_viewleaf->contents == CONTENTS_SOLID || r_novis.integer || r_viewleaf->compressed_vis == NULL)
1850                 R_SolidWorldNode (ent);
1851         else
1852                 R_PVSWorldNode (ent);
1853 }
1854
1855 /*
1856 =================
1857 R_DrawBrushModel
1858 =================
1859 */
1860 void R_DrawBrushModelSky (entity_render_t *ent)
1861 {
1862         R_SetupForBModelRendering(ent);
1863
1864         R_PrepareSurfaces(ent);
1865         R_DrawSurfaces(ent, SHADERSTAGE_SKY);
1866 }
1867
1868 void R_DrawBrushModelNormal (entity_render_t *ent)
1869 {
1870         c_bmodels++;
1871
1872         // have to flush queue because of possible lightmap reuse
1873         R_Mesh_Render();
1874
1875         R_SetupForBModelRendering(ent);
1876
1877         R_SurfMarkLights(ent);
1878
1879         R_PrepareSurfaces(ent);
1880
1881         if (!skyrendermasked)
1882                 R_DrawSurfaces(ent, SHADERSTAGE_SKY);
1883         R_DrawSurfaces(ent, SHADERSTAGE_NORMAL);
1884 }
1885
1886 static void gl_surf_start(void)
1887 {
1888 }
1889
1890 static void gl_surf_shutdown(void)
1891 {
1892 }
1893
1894 static void gl_surf_newmap(void)
1895 {
1896 }
1897
1898 void GL_Surf_Init(void)
1899 {
1900         int i;
1901         dlightdivtable[0] = 4194304;
1902         for (i = 1;i < 32768;i++)
1903                 dlightdivtable[i] = 4194304 / (i << 7);
1904
1905         Cvar_RegisterVariable(&r_ambient);
1906         Cvar_RegisterVariable(&r_vertexsurfaces);
1907         Cvar_RegisterVariable(&r_dlightmap);
1908         Cvar_RegisterVariable(&r_drawportals);
1909         Cvar_RegisterVariable(&r_testvis);
1910         Cvar_RegisterVariable(&r_floatbuildlightmap);
1911         Cvar_RegisterVariable(&r_detailtextures);
1912
1913         R_RegisterModule("GL_Surf", gl_surf_start, gl_surf_shutdown, gl_surf_newmap);
1914 }
1915