]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rsurf.c
08620f340d2b18f0bb91c6423142434b1615d7cd
[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 * 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         vec3_t center;
937         for (surf = firstsurf;surf;surf = surf->chain)
938         {
939                 if ((r_wateralpha.value < 1 && !(surf->flags & SURF_DRAWNOALPHA)) || ent->effects & EF_ADDITIVE || surf->currenttexture->fogtexture)
940                 {
941                         Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
942                         R_MeshQueue_AddTransparent(center, RSurfShader_Water_Callback, ent, surf - ent->model->surfaces);
943                 }
944                 else
945                         R_MeshQueue_Add(RSurfShader_Water_Callback, ent, surf - ent->model->surfaces);
946         }
947 }
948
949 static void RSurfShader_Wall_Pass_BaseVertex(const entity_render_t *ent, const msurface_t *surf)
950 {
951         float base;
952         surfmesh_t *mesh;
953         rmeshbufferinfo_t m;
954         float modelorg[3];
955         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
956         memset(&m, 0, sizeof(m));
957         if (ent->effects & EF_ADDITIVE)
958         {
959                 m.blendfunc1 = GL_SRC_ALPHA;
960                 m.blendfunc2 = GL_ONE;
961         }
962         else if (surf->currenttexture->fogtexture != NULL || ent->alpha < 1)
963         {
964                 m.blendfunc1 = GL_SRC_ALPHA;
965                 m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
966         }
967         else
968         {
969                 m.blendfunc1 = GL_ONE;
970                 m.blendfunc2 = GL_ZERO;
971         }
972         m.tex[0] = R_GetTexture(surf->currenttexture->texture);
973         base = ent->effects & EF_FULLBRIGHT ? 2.0f : r_ambient.value * (1.0f / 64.0f);
974         m.matrix = ent->matrix;
975         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
976         {
977                 m.numtriangles = mesh->numtriangles;
978                 m.numverts = mesh->numverts;
979                 if (R_Mesh_Draw_GetBuffer(&m, true))
980                 {
981                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
982                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
983                         RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
984                         R_FillColors(m.color, m.numverts, base, base, base, ent->alpha);
985                         if (!(ent->effects & EF_FULLBRIGHT))
986                         {
987                                 if (surf->dlightframe == r_framecount)
988                                         RSurf_LightSeparate(&ent->inversematrix, surf->dlightbits, m.numverts, m.vertex, m.color);
989                                 if (surf->flags & SURF_LIGHTMAP)
990                                         RSurf_AddLightmapToVertexColors(mesh->vertex, m.color, m.numverts, surf->samples, ((surf->extents[0]>>4)+1)*((surf->extents[1]>>4)+1)*3, surf->styles);
991                         }
992                         RSurf_FogColors(m.vertex, m.color, m.colorscale, m.numverts, modelorg);
993                         R_Mesh_Render();
994                 }
995         }
996 }
997
998 static void RSurfShader_Wall_Pass_BaseFullbright(const entity_render_t *ent, const msurface_t *surf)
999 {
1000         surfmesh_t *mesh;
1001         rmeshbufferinfo_t m;
1002         float modelorg[3];
1003         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
1004         memset(&m, 0, sizeof(m));
1005         if (ent->effects & EF_ADDITIVE)
1006         {
1007                 m.blendfunc1 = GL_SRC_ALPHA;
1008                 m.blendfunc2 = GL_ONE;
1009         }
1010         else if (surf->currenttexture->fogtexture != NULL || ent->alpha < 1)
1011         {
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.blendfunc1 = GL_SRC_ALPHA;
1045         m.blendfunc2 = GL_ONE;
1046         m.tex[0] = R_GetTexture(surf->currenttexture->glowtexture);
1047         m.matrix = ent->matrix;
1048         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1049         {
1050                 m.numtriangles = mesh->numtriangles;
1051                 m.numverts = mesh->numverts;
1052                 if (R_Mesh_Draw_GetBuffer(&m, false))
1053                 {
1054                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1055                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1056                         RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1057                         RSurf_FoggedColors(m.vertex, m.color, 1, 1, 1, ent->alpha, m.colorscale, m.numverts, modelorg);
1058                         R_Mesh_Render();
1059                 }
1060         }
1061 }
1062
1063 static void RSurfShader_Wall_Pass_Fog(const entity_render_t *ent, const msurface_t *surf)
1064 {
1065         surfmesh_t *mesh;
1066         rmeshbufferinfo_t m;
1067         float modelorg[3];
1068         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
1069         memset(&m, 0, sizeof(m));
1070         m.blendfunc1 = GL_SRC_ALPHA;
1071         m.blendfunc2 = GL_ONE;
1072         m.matrix = ent->matrix;
1073         m.tex[0] = R_GetTexture(surf->currenttexture->fogtexture);
1074         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1075         {
1076                 m.numtriangles = mesh->numtriangles;
1077                 m.numverts = mesh->numverts;
1078                 if (R_Mesh_Draw_GetBuffer(&m, false))
1079                 {
1080                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1081                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1082                         if (m.tex[0])
1083                                 RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1084                         RSurf_FogPassColors(m.vertex, m.color, fogcolor[0], fogcolor[1], fogcolor[2], ent->alpha, m.colorscale, m.numverts, modelorg);
1085                         R_Mesh_Render();
1086                 }
1087         }
1088 }
1089
1090 static void RSurfShader_OpaqueWall_Pass_TripleTexCombine(const entity_render_t *ent, const msurface_t *surf)
1091 {
1092         surfmesh_t *mesh;
1093         rmeshbufferinfo_t m;
1094         float cl;
1095         memset(&m, 0, sizeof(m));
1096         m.blendfunc1 = GL_ONE;
1097         m.blendfunc2 = GL_ZERO;
1098         m.tex[0] = R_GetTexture(surf->currenttexture->texture);
1099         m.texrgbscale[0] = 1.0f;
1100         m.tex[1] = R_GetTexture(surf->lightmaptexture);
1101         m.texrgbscale[1] = 4.0f;
1102         m.tex[2] = R_GetTexture(surf->currenttexture->detailtexture);
1103         m.texrgbscale[2] = 2.0f;
1104         m.matrix = ent->matrix;
1105         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1106         {
1107                 m.numtriangles = mesh->numtriangles;
1108                 m.numverts = mesh->numverts;
1109                 if (R_Mesh_Draw_GetBuffer(&m, false))
1110                 {
1111                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1112                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1113                         cl = (float) (1 << lightscalebit) * m.colorscale;
1114                         R_FillColors(m.color, m.numverts, cl, cl, cl, 1);
1115                         RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1116                         RSurf_CopyUV(mesh->vertex, m.texcoords[1], m.numverts);
1117                         RSurf_CopyAB(mesh->vertex, m.texcoords[2], m.numverts);
1118                         R_Mesh_Render();
1119                 }
1120         }
1121 }
1122
1123 static void RSurfShader_OpaqueWall_Pass_BaseMTex(const entity_render_t *ent, const msurface_t *surf)
1124 {
1125         surfmesh_t *mesh;
1126         rmeshbufferinfo_t m;
1127         float cl;
1128         memset(&m, 0, sizeof(m));
1129         m.blendfunc1 = GL_ONE;
1130         m.blendfunc2 = GL_ZERO;
1131         m.tex[0] = R_GetTexture(surf->currenttexture->texture);
1132         m.tex[1] = R_GetTexture(surf->lightmaptexture);
1133         m.matrix = ent->matrix;
1134         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1135         {
1136                 m.numtriangles = mesh->numtriangles;
1137                 m.numverts = mesh->numverts;
1138                 if (R_Mesh_Draw_GetBuffer(&m, true))
1139                 {
1140                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1141                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1142                         cl = (float) (1 << lightscalebit) * m.colorscale;
1143                         R_FillColors(m.color, m.numverts, cl, cl, cl, 1);
1144                         RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1145                         RSurf_CopyUV(mesh->vertex, m.texcoords[1], m.numverts);
1146                         R_Mesh_Render();
1147                 }
1148         }
1149 }
1150
1151 static void RSurfShader_OpaqueWall_Pass_BaseTexture(const entity_render_t *ent, const msurface_t *surf)
1152 {
1153         surfmesh_t *mesh;
1154         rmeshbufferinfo_t m;
1155         float cl;
1156         memset(&m, 0, sizeof(m));
1157         m.blendfunc1 = GL_ONE;
1158         m.blendfunc2 = GL_ZERO;
1159         m.tex[0] = R_GetTexture(surf->currenttexture->texture);
1160         m.matrix = ent->matrix;
1161         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1162         {
1163                 m.numtriangles = mesh->numtriangles;
1164                 m.numverts = mesh->numverts;
1165                 if (R_Mesh_Draw_GetBuffer(&m, false))
1166                 {
1167                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1168                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1169                         cl = m.colorscale;
1170                         R_FillColors(m.color, m.numverts, cl, cl, cl, 1);
1171                         RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1172                         R_Mesh_Render();
1173                 }
1174         }
1175 }
1176
1177 static void RSurfShader_OpaqueWall_Pass_BaseLightmap(const entity_render_t *ent, const msurface_t *surf)
1178 {
1179         surfmesh_t *mesh;
1180         rmeshbufferinfo_t m;
1181         float cl;
1182         memset(&m, 0, sizeof(m));
1183         m.blendfunc1 = GL_ZERO;
1184         m.blendfunc2 = GL_SRC_COLOR;
1185         m.tex[0] = R_GetTexture(surf->lightmaptexture);
1186         m.matrix = ent->matrix;
1187         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1188         {
1189                 m.numtriangles = mesh->numtriangles;
1190                 m.numverts = mesh->numverts;
1191                 if (R_Mesh_Draw_GetBuffer(&m, true))
1192                 {
1193                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1194                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1195                         cl = (float) (1 << lightscalebit) * m.colorscale;
1196                         R_FillColors(m.color, m.numverts, cl, cl, cl, 1);
1197                         RSurf_CopyUV(mesh->vertex, m.texcoords[0], m.numverts);
1198                         R_Mesh_Render();
1199                 }
1200         }
1201 }
1202
1203 static void RSurfShader_OpaqueWall_Pass_Light(const entity_render_t *ent, const msurface_t *surf)
1204 {
1205         surfmesh_t *mesh;
1206         rmeshbufferinfo_t m;
1207
1208         if (surf->dlightframe != r_framecount)
1209                 return;
1210         if (ent->effects & EF_FULLBRIGHT)
1211                 return;
1212
1213         memset(&m, 0, sizeof(m));
1214         m.blendfunc1 = GL_SRC_ALPHA;
1215         m.blendfunc2 = GL_ONE;
1216         m.tex[0] = R_GetTexture(surf->currenttexture->texture);
1217         m.matrix = ent->matrix;
1218         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1219         {
1220                 if (RSurf_LightCheck(surf->dlightbits, mesh))
1221                 {
1222                         m.numtriangles = mesh->numtriangles;
1223                         m.numverts = mesh->numverts;
1224                         if (R_Mesh_Draw_GetBuffer(&m, true))
1225                         {
1226                                 memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1227                                 RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1228                                 RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1229                                 R_FillColors(m.color, m.numverts, 0, 0, 0, 1);
1230                                 RSurf_LightSeparate(&ent->inversematrix, surf->dlightbits, m.numverts, m.vertex, m.color);
1231                                 RSurf_ScaleColors(m.color, m.colorscale, m.numverts);
1232                                 R_Mesh_Render();
1233                         }
1234                 }
1235         }
1236 }
1237
1238 static void RSurfShader_OpaqueWall_Pass_Fog(const entity_render_t *ent, const msurface_t *surf)
1239 {
1240         surfmesh_t *mesh;
1241         rmeshbufferinfo_t m;
1242         float modelorg[3];
1243         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
1244         memset(&m, 0, sizeof(m));
1245         m.blendfunc1 = GL_SRC_ALPHA;
1246         m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
1247         m.tex[0] = R_GetTexture(surf->currenttexture->fogtexture);
1248         m.matrix = ent->matrix;
1249         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1250         {
1251                 m.numtriangles = mesh->numtriangles;
1252                 m.numverts = mesh->numverts;
1253                 if (R_Mesh_Draw_GetBuffer(&m, false))
1254                 {
1255                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1256                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1257                         if (m.tex[0])
1258                                 RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1259                         RSurf_FogPassColors(m.vertex, m.color, fogcolor[0], fogcolor[1], fogcolor[2], 1, m.colorscale, m.numverts, modelorg);
1260                         R_Mesh_Render();
1261                 }
1262         }
1263 }
1264
1265 static void RSurfShader_OpaqueWall_Pass_BaseDetail(const entity_render_t *ent, const msurface_t *surf)
1266 {
1267         surfmesh_t *mesh;
1268         rmeshbufferinfo_t m;
1269         memset(&m, 0, sizeof(m));
1270         m.blendfunc1 = GL_DST_COLOR;
1271         m.blendfunc2 = GL_SRC_COLOR;
1272         m.tex[0] = R_GetTexture(surf->currenttexture->detailtexture);
1273         m.matrix = ent->matrix;
1274         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1275         {
1276                 m.numtriangles = mesh->numtriangles;
1277                 m.numverts = mesh->numverts;
1278                 if (R_Mesh_Draw_GetBuffer(&m, false))
1279                 {
1280                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1281                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1282                         R_FillColors(m.color, m.numverts, 1, 1, 1, 1);
1283                         RSurf_CopyAB(mesh->vertex, m.texcoords[0], m.numverts);
1284                         R_Mesh_Render();
1285                 }
1286         }
1287 }
1288
1289 static void RSurfShader_OpaqueWall_Pass_Glow(const entity_render_t *ent, const msurface_t *surf)
1290 {
1291         surfmesh_t *mesh;
1292         rmeshbufferinfo_t m;
1293         memset(&m, 0, sizeof(m));
1294         m.blendfunc1 = GL_SRC_ALPHA;
1295         m.blendfunc2 = GL_ONE;
1296         m.tex[0] = R_GetTexture(surf->currenttexture->glowtexture);
1297         m.matrix = ent->matrix;
1298         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
1299         {
1300                 m.numtriangles = mesh->numtriangles;
1301                 m.numverts = mesh->numverts;
1302                 if (R_Mesh_Draw_GetBuffer(&m, false))
1303                 {
1304                         memcpy(m.index, mesh->index, m.numtriangles * sizeof(int[3]));
1305                         RSurf_CopyXYZ(mesh->vertex, m.vertex, m.numverts);
1306                         R_FillColors(m.color, m.numverts, m.colorscale, m.colorscale, m.colorscale, 1);
1307                         RSurf_CopyST(mesh->vertex, m.texcoords[0], m.numverts);
1308                         R_Mesh_Render();
1309                 }
1310         }
1311 }
1312
1313 static void RSurfShader_Wall_Fullbright_Callback(const void *calldata1, int calldata2)
1314 {
1315         const entity_render_t *ent = calldata1;
1316         const msurface_t *surf = ent->model->surfaces + calldata2;
1317         RSurfShader_Wall_Pass_BaseFullbright(ent, surf);
1318         if (surf->currenttexture->glowtexture)
1319                 RSurfShader_Wall_Pass_Glow(ent, surf);
1320         if (fogenabled)
1321                 RSurfShader_Wall_Pass_Fog(ent, surf);
1322 }
1323
1324 static void RSurfShader_Wall_Fullbright(const entity_render_t *ent, const msurface_t *firstsurf)
1325 {
1326         const msurface_t *surf;
1327         vec3_t center;
1328         if (ent->effects & EF_ADDITIVE || ent->alpha < 1)
1329         {
1330                 for (surf = firstsurf;surf;surf = surf->chain)
1331                 {
1332                         c_brush_polys++;
1333                         Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
1334                         R_MeshQueue_AddTransparent(center, RSurfShader_Wall_Fullbright_Callback, ent, surf - ent->model->surfaces);
1335                 }
1336         }
1337         else
1338         {
1339                 for (surf = firstsurf;surf;surf = surf->chain)
1340                 {
1341                         c_brush_polys++;
1342                         if (surf->currenttexture->fogtexture != NULL)
1343                         {
1344                                 Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
1345                                 R_MeshQueue_AddTransparent(center, RSurfShader_Wall_Fullbright_Callback, ent, surf - ent->model->surfaces);
1346                         }
1347                         else
1348                                 RSurfShader_Wall_Pass_BaseFullbright(ent, surf);
1349                 }
1350                 for (surf = firstsurf;surf;surf = surf->chain)
1351                         if (surf->currenttexture->glowtexture)
1352                                 if (surf->currenttexture->fogtexture == NULL)
1353                                         RSurfShader_Wall_Pass_Glow(ent, surf);
1354                 if (fogenabled)
1355                         for (surf = firstsurf;surf;surf = surf->chain)
1356                                 if (surf->currenttexture->fogtexture == NULL)
1357                                         RSurfShader_Wall_Pass_Fog(ent, surf);
1358         }
1359 }
1360
1361 static void RSurfShader_Wall_Vertex_Callback(const void *calldata1, int calldata2)
1362 {
1363         const entity_render_t *ent = calldata1;
1364         const msurface_t *surf = ent->model->surfaces + calldata2;
1365         RSurfShader_Wall_Pass_BaseVertex(ent, surf);
1366         if (surf->currenttexture->glowtexture)
1367                 RSurfShader_Wall_Pass_Glow(ent, surf);
1368         if (fogenabled)
1369                 RSurfShader_Wall_Pass_Fog(ent, surf);
1370 }
1371
1372 static void RSurfShader_Wall_Vertex(const entity_render_t *ent, const msurface_t *firstsurf)
1373 {
1374         const msurface_t *surf;
1375         vec3_t center;
1376         if (ent->effects & EF_ADDITIVE || ent->alpha < 1)
1377         {
1378                 for (surf = firstsurf;surf;surf = surf->chain)
1379                 {
1380                         c_brush_polys++;
1381                         Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
1382                         R_MeshQueue_AddTransparent(center, RSurfShader_Wall_Vertex_Callback, ent, surf - ent->model->surfaces);
1383                 }
1384         }
1385         else
1386         {
1387                 for (surf = firstsurf;surf;surf = surf->chain)
1388                 {
1389                         c_brush_polys++;
1390                         if (surf->currenttexture->fogtexture != NULL)
1391                         {
1392                                 Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
1393                                 R_MeshQueue_AddTransparent(center, RSurfShader_Wall_Vertex_Callback, ent, surf - ent->model->surfaces);
1394                         }
1395                         else
1396                                 RSurfShader_Wall_Pass_BaseVertex(ent, surf);
1397                 }
1398                 for (surf = firstsurf;surf;surf = surf->chain)
1399                         if (surf->currenttexture->glowtexture)
1400                                 if (surf->currenttexture->fogtexture == NULL)
1401                                         RSurfShader_Wall_Pass_Glow(ent, surf);
1402                 if (fogenabled)
1403                         for (surf = firstsurf;surf;surf = surf->chain)
1404                                 if (surf->currenttexture->fogtexture == NULL)
1405                                         RSurfShader_Wall_Pass_Fog(ent, surf);
1406         }
1407 }
1408
1409 static void RSurfShader_Wall_Lightmap(const entity_render_t *ent, const msurface_t *firstsurf)
1410 {
1411         const msurface_t *surf;
1412         vec3_t center;
1413         if (ent->alpha < 1 || ent->effects & EF_ADDITIVE)
1414         {
1415                 for (surf = firstsurf;surf;surf = surf->chain)
1416                 {
1417                         c_brush_polys++;
1418                         Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
1419                         R_MeshQueue_AddTransparent(center, RSurfShader_Wall_Vertex_Callback, ent, surf - ent->model->surfaces);
1420                 }
1421         }
1422         else if (r_vertexsurfaces.integer || ent->alpha < 1 || ent->effects & EF_ADDITIVE)
1423         {
1424                 for (surf = firstsurf;surf;surf = surf->chain)
1425                 {
1426                         c_brush_polys++;
1427                         if (surf->currenttexture->fogtexture != NULL)
1428                         {
1429                                 Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
1430                                 R_MeshQueue_AddTransparent(center, RSurfShader_Wall_Vertex_Callback, ent, surf - ent->model->surfaces);
1431                         }
1432                         else
1433                                 RSurfShader_Wall_Pass_BaseVertex(ent, surf);
1434                 }
1435                 for (surf = firstsurf;surf;surf = surf->chain)
1436                         if (surf->currenttexture->glowtexture)
1437                                 if (surf->currenttexture->fogtexture == NULL)
1438                                         RSurfShader_Wall_Pass_Glow(ent, surf);
1439                 if (fogenabled)
1440                         for (surf = firstsurf;surf;surf = surf->chain)
1441                                 if (surf->currenttexture->fogtexture == NULL)
1442                                         RSurfShader_Wall_Pass_Fog(ent, surf);
1443         }
1444         else
1445         {
1446                 if (r_textureunits.integer >= 2)
1447                 {
1448                         if (r_textureunits.integer >= 3 && gl_combine.integer && r_detailtextures.integer)
1449                         {
1450                                 for (surf = firstsurf;surf;surf = surf->chain)
1451                                 {
1452                                         c_brush_polys++;
1453                                         if (surf->currenttexture->fogtexture != NULL)
1454                                         {
1455                                                 Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
1456                                                 R_MeshQueue_AddTransparent(center, RSurfShader_Wall_Vertex_Callback, ent, surf - ent->model->surfaces);
1457                                         }
1458                                         else
1459                                                 RSurfShader_OpaqueWall_Pass_TripleTexCombine(ent, surf);
1460                                 }
1461                         }
1462                         else
1463                         {
1464                                 for (surf = firstsurf;surf;surf = surf->chain)
1465                                 {
1466                                         c_brush_polys++;
1467                                         if (surf->currenttexture->fogtexture != NULL)
1468                                         {
1469                                                 Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
1470                                                 R_MeshQueue_AddTransparent(center, RSurfShader_Wall_Vertex_Callback, ent, surf - ent->model->surfaces);
1471                                         }
1472                                         else
1473                                                 RSurfShader_OpaqueWall_Pass_BaseMTex(ent, surf);
1474                                 }
1475                                 if (r_detailtextures.integer)
1476                                         for (surf = firstsurf;surf;surf = surf->chain)
1477                                                 if (surf->currenttexture->fogtexture == NULL)
1478                                                         RSurfShader_OpaqueWall_Pass_BaseDetail(ent, surf);
1479                         }
1480                 }
1481                 else
1482                 {
1483                         for (surf = firstsurf;surf;surf = surf->chain)
1484                         {
1485                                 c_brush_polys++;
1486                                 if (surf->currenttexture->fogtexture != NULL)
1487                                 {
1488                                         Matrix4x4_Transform(&ent->matrix, surf->poly_center, center);
1489                                         R_MeshQueue_AddTransparent(center, RSurfShader_Wall_Vertex_Callback, ent, surf - ent->model->surfaces);
1490                                 }
1491                                 else
1492                                         RSurfShader_OpaqueWall_Pass_BaseTexture(ent, surf);
1493                         }
1494                         for (surf = firstsurf;surf;surf = surf->chain)
1495                                 if (surf->currenttexture->fogtexture == NULL)
1496                                         RSurfShader_OpaqueWall_Pass_BaseLightmap(ent, surf);
1497                         if (r_detailtextures.integer)
1498                                 for (surf = firstsurf;surf;surf = surf->chain)
1499                                         if (surf->currenttexture->fogtexture == NULL)
1500                                                 RSurfShader_OpaqueWall_Pass_BaseDetail(ent, surf);
1501                 }
1502                 if (!r_dlightmap.integer)
1503                         for (surf = firstsurf;surf;surf = surf->chain)
1504                                 if (surf->dlightframe == r_framecount)
1505                                         if (surf->currenttexture->fogtexture == NULL)
1506                                                 RSurfShader_OpaqueWall_Pass_Light(ent, surf);
1507                 for (surf = firstsurf;surf;surf = surf->chain)
1508                         if (surf->currenttexture->glowtexture)
1509                                 if (surf->currenttexture->fogtexture == NULL)
1510                                         RSurfShader_OpaqueWall_Pass_Glow(ent, surf);
1511                 if (fogenabled)
1512                         for (surf = firstsurf;surf;surf = surf->chain)
1513                                 if (surf->currenttexture->fogtexture == NULL)
1514                                         RSurfShader_OpaqueWall_Pass_Fog(ent, surf);
1515         }
1516 }
1517
1518 /*
1519 =============================================================
1520
1521         WORLD MODEL
1522
1523 =============================================================
1524 */
1525
1526 static void R_SolidWorldNode (entity_render_t *ent)
1527 {
1528         if (r_viewleaf->contents != CONTENTS_SOLID)
1529         {
1530                 int portalstack;
1531                 mportal_t *p, *pstack[8192];
1532                 msurface_t *surf, **mark, **endmark;
1533                 mleaf_t *leaf;
1534                 // LordHavoc: portal-passage worldnode; follows portals leading
1535                 // outward from viewleaf, if a portal leads offscreen it is not
1536                 // followed, in indoor maps this can often cull a great deal of
1537                 // geometry away when pvs data is not present (useful with pvs as well)
1538
1539                 leaf = r_viewleaf;
1540                 leaf->worldnodeframe = r_framecount;
1541                 portalstack = 0;
1542         loc0:
1543                 c_leafs++;
1544
1545                 leaf->visframe = r_framecount;
1546
1547                 if (leaf->nummarksurfaces)
1548                 {
1549                         mark = leaf->firstmarksurface;
1550                         endmark = mark + leaf->nummarksurfaces;
1551                         do
1552                         {
1553                                 surf = *mark++;
1554                                 // make sure surfaces are only processed once
1555                                 if (surf->worldnodeframe == r_framecount)
1556                                         continue;
1557                                 surf->worldnodeframe = r_framecount;
1558                                 if (PlaneDist(r_origin, surf->plane) < surf->plane->dist)
1559                                 {
1560                                         if (surf->flags & SURF_PLANEBACK)
1561                                                 surf->visframe = r_framecount;
1562                                 }
1563                                 else
1564                                 {
1565                                         if (!(surf->flags & SURF_PLANEBACK))
1566                                                 surf->visframe = r_framecount;
1567                                 }
1568                         }
1569                         while (mark < endmark);
1570                 }
1571
1572                 // follow portals into other leafs
1573                 p = leaf->portals;
1574                 for (;p;p = p->next)
1575                 {
1576                         if (DotProduct(r_origin, p->plane.normal) < p->plane.dist)
1577                         {
1578                                 leaf = p->past;
1579                                 if (leaf->worldnodeframe != r_framecount)
1580                                 {
1581                                         leaf->worldnodeframe = r_framecount;
1582                                         if (leaf->contents != CONTENTS_SOLID)
1583                                         {
1584                                                 if (R_NotCulledBox(leaf->mins, leaf->maxs))
1585                                                 {
1586                                                         p->visframe = r_framecount;
1587                                                         pstack[portalstack++] = p;
1588                                                         goto loc0;
1589
1590         loc1:
1591                                                         p = pstack[--portalstack];
1592                                                 }
1593                                         }
1594                                 }
1595                         }
1596                 }
1597
1598                 if (portalstack)
1599                         goto loc1;
1600         }
1601         else
1602         {
1603                 mnode_t *nodestack[8192], *node = cl.worldmodel->nodes;
1604                 int nodestackpos = 0;
1605                 // LordHavoc: recursive descending worldnode; if portals are not
1606                 // available, this is a good last resort, can cull large amounts of
1607                 // geometry, but is more time consuming than portal-passage and renders
1608                 // things behind walls
1609
1610 loc2:
1611                 if (R_NotCulledBox(node->mins, node->maxs))
1612                 {
1613                         if (node->numsurfaces)
1614                         {
1615                                 msurface_t *surf = cl.worldmodel->surfaces + node->firstsurface, *surfend = surf + node->numsurfaces;
1616                                 if (PlaneDiff (r_origin, node->plane) < 0)
1617                                 {
1618                                         for (;surf < surfend;surf++)
1619                                         {
1620                                                 if (surf->flags & SURF_PLANEBACK)
1621                                                         surf->visframe = r_framecount;
1622                                         }
1623                                 }
1624                                 else
1625                                 {
1626                                         for (;surf < surfend;surf++)
1627                                         {
1628                                                 if (!(surf->flags & SURF_PLANEBACK))
1629                                                         surf->visframe = r_framecount;
1630                                         }
1631                                 }
1632                         }
1633
1634                         // recurse down the children
1635                         if (node->children[0]->contents >= 0)
1636                         {
1637                                 if (node->children[1]->contents >= 0)
1638                                 {
1639                                         if (nodestackpos < 8192)
1640                                                 nodestack[nodestackpos++] = node->children[1];
1641                                         node = node->children[0];
1642                                         goto loc2;
1643                                 }
1644                                 else
1645                                         ((mleaf_t *)node->children[1])->visframe = r_framecount;
1646                                 node = node->children[0];
1647                                 goto loc2;
1648                         }
1649                         else
1650                         {
1651                                 ((mleaf_t *)node->children[0])->visframe = r_framecount;
1652                                 if (node->children[1]->contents >= 0)
1653                                 {
1654                                         node = node->children[1];
1655                                         goto loc2;
1656                                 }
1657                                 else if (nodestackpos > 0)
1658                                 {
1659                                         ((mleaf_t *)node->children[1])->visframe = r_framecount;
1660                                         node = nodestack[--nodestackpos];
1661                                         goto loc2;
1662                                 }
1663                         }
1664                 }
1665                 else if (nodestackpos > 0)
1666                 {
1667                         node = nodestack[--nodestackpos];
1668                         goto loc2;
1669                 }
1670         }
1671 }
1672
1673 static void R_PVSWorldNode()
1674 {
1675         int portalstack, i;
1676         mportal_t *p, *pstack[8192];
1677         msurface_t *surf, **mark, **endmark;
1678         mleaf_t *leaf;
1679         qbyte *worldvis;
1680
1681         worldvis = Mod_LeafPVS (r_viewleaf, cl.worldmodel);
1682
1683         leaf = r_viewleaf;
1684         leaf->worldnodeframe = r_framecount;
1685         portalstack = 0;
1686 loc0:
1687         c_leafs++;
1688
1689         leaf->visframe = r_framecount;
1690
1691         if (leaf->nummarksurfaces)
1692         {
1693                 mark = leaf->firstmarksurface;
1694                 endmark = mark + leaf->nummarksurfaces;
1695                 do
1696                 {
1697                         surf = *mark++;
1698                         // make sure surfaces are only processed once
1699                         if (surf->worldnodeframe == r_framecount)
1700                                 continue;
1701                         surf->worldnodeframe = r_framecount;
1702                         if (PlaneDist(r_origin, surf->plane) < surf->plane->dist)
1703                         {
1704                                 if (surf->flags & SURF_PLANEBACK)
1705                                         surf->visframe = r_framecount;
1706                         }
1707                         else
1708                         {
1709                                 if (!(surf->flags & SURF_PLANEBACK))
1710                                         surf->visframe = r_framecount;
1711                         }
1712                 }
1713                 while (mark < endmark);
1714         }
1715
1716         // follow portals into other leafs
1717         for (p = leaf->portals;p;p = p->next)
1718         {
1719                 if (DotProduct(r_origin, p->plane.normal) < p->plane.dist)
1720                 {
1721                         leaf = p->past;
1722                         if (leaf->worldnodeframe != r_framecount)
1723                         {
1724                                 leaf->worldnodeframe = r_framecount;
1725                                 if (leaf->contents != CONTENTS_SOLID)
1726                                 {
1727                                         i = (leaf - cl.worldmodel->leafs) - 1;
1728                                         if (worldvis[i>>3] & (1<<(i&7)))
1729                                         {
1730                                                 if (R_NotCulledBox(leaf->mins, leaf->maxs))
1731                                                 {
1732                                                         pstack[portalstack++] = p;
1733                                                         goto loc0;
1734
1735 loc1:
1736                                                         p = pstack[--portalstack];
1737                                                 }
1738                                         }
1739                                 }
1740                         }
1741                 }
1742         }
1743
1744         if (portalstack)
1745                 goto loc1;
1746 }
1747
1748 Cshader_t Cshader_wall_vertex = {{NULL, RSurfShader_Wall_Vertex}, NULL};
1749 Cshader_t Cshader_wall_lightmap = {{NULL, RSurfShader_Wall_Lightmap}, NULL};
1750 Cshader_t Cshader_wall_fullbright = {{NULL, RSurfShader_Wall_Fullbright}, NULL};
1751 Cshader_t Cshader_water = {{NULL, RSurfShader_Water}, NULL};
1752 Cshader_t Cshader_sky = {{RSurfShader_Sky, NULL}, NULL};
1753
1754 int Cshader_count = 5;
1755 Cshader_t *Cshaders[5] =
1756 {
1757         &Cshader_wall_vertex,
1758         &Cshader_wall_lightmap,
1759         &Cshader_wall_fullbright,
1760         &Cshader_water,
1761         &Cshader_sky
1762 };
1763
1764 void R_PrepareSurfaces(entity_render_t *ent)
1765 {
1766         int i, alttextures, texframe, framecount;
1767         texture_t *t;
1768         model_t *model;
1769         msurface_t *surf;
1770
1771         for (i = 0;i < Cshader_count;i++)
1772                 Cshaders[i]->chain = NULL;
1773
1774         model = ent->model;
1775         alttextures = ent->frame != 0;
1776         texframe = (int)(cl.time * 5.0f);
1777
1778         for (i = 0;i < model->nummodelsurfaces;i++)
1779         {
1780                 surf = model->modelsortedsurfaces[i];
1781                 if (surf->visframe == r_framecount)
1782                 {
1783                         if (surf->insertframe != r_framecount)
1784                         {
1785                                 surf->insertframe = r_framecount;
1786                                 c_faces++;
1787                                 t = surf->texinfo->texture;
1788                                 if (t->animated)
1789                                 {
1790                                         framecount = t->anim_total[alttextures];
1791                                         if (framecount >= 2)
1792                                                 surf->currenttexture = t->anim_frames[alttextures][texframe % framecount];
1793                                         else
1794                                                 surf->currenttexture = t->anim_frames[alttextures][0];
1795                                 }
1796                                 else
1797                                         surf->currenttexture = t;
1798                         }
1799
1800                         surf->chain = surf->shader->chain;
1801                         surf->shader->chain = surf;
1802                 }
1803         }
1804 }
1805
1806 void R_DrawSurfaces (entity_render_t *ent, int type)
1807 {
1808         int                     i;
1809         Cshader_t       *shader;
1810
1811         for (i = 0;i < Cshader_count;i++)
1812         {
1813                 shader = Cshaders[i];
1814                 if (shader->chain && shader->shaderfunc[type])
1815                         shader->shaderfunc[type](ent, shader->chain);
1816         }
1817 }
1818
1819 static void R_DrawPortal_Callback(const void *calldata1, int calldata2)
1820 {
1821         int i;
1822         float *v;
1823         rmeshbufferinfo_t m;
1824         const entity_render_t *ent = calldata1;
1825         const mportal_t *portal = ent->model->portals + calldata2;
1826         memset(&m, 0, sizeof(m));
1827         m.blendfunc1 = GL_SRC_ALPHA;
1828         m.blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
1829         m.numverts = portal->numpoints;
1830         m.numtriangles = portal->numpoints - 2;
1831         m.matrix = ent->matrix;
1832         if (R_Mesh_Draw_GetBuffer(&m, false))
1833         {
1834                 for (i = 0;i < m.numtriangles;i++)
1835                 {
1836                         m.index[i * 3 + 0] = 0;
1837                         m.index[i * 3 + 1] = i + 1;
1838                         m.index[i * 3 + 2] = i + 2;
1839                 }
1840                 i = portal - ent->model->portals;
1841                 R_FillColors(m.color, m.numverts,
1842                         ((i & 0x0007) >> 0) * (1.0f / 7.0f) * m.colorscale,
1843                         ((i & 0x0038) >> 3) * (1.0f / 7.0f) * m.colorscale,
1844                         ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * m.colorscale,
1845                         0.125f);
1846                 if (PlaneDiff(r_origin, (&portal->plane)) > 0)
1847                 {
1848                         for (i = portal->numpoints - 1, v = m.vertex;i >= 0;i--, v += 4)
1849                                 VectorCopy(portal->points[i].position, v);
1850                 }
1851                 else
1852                         for (i = 0, v = m.vertex;i < portal->numpoints;i++, v += 4)
1853                                 VectorCopy(portal->points[i].position, v);
1854                 R_Mesh_Render();
1855         }
1856 }
1857
1858 void R_DrawPortals(entity_render_t *ent)
1859 {
1860         int i;
1861         mportal_t *portal, *endportal;
1862         float temp[3], center[3], f;
1863
1864         if (r_drawportals.integer < 1)
1865                 return;
1866
1867         for (portal = ent->model->portals, endportal = portal + ent->model->numportals;portal < endportal;portal++)
1868         {
1869                 if (portal->here->visframe == r_framecount || portal->past->visframe == r_framecount)
1870                 {
1871                         VectorClear(temp);
1872                         for (i = 0;i < portal->numpoints;i++)
1873                                 VectorAdd(temp, portal->points[i].position, temp);
1874                         f = ixtable[portal->numpoints];
1875                         VectorScale(temp, f, temp);
1876                         Matrix4x4_Transform(&ent->matrix, temp, center);
1877                         R_MeshQueue_AddTransparent(center, R_DrawPortal_Callback, ent, portal - ent->model->portals);
1878                 }
1879         }
1880 }
1881
1882 void R_SetupForBModelRendering(entity_render_t *ent)
1883 {
1884         int                     i;
1885         msurface_t      *surf;
1886         model_t         *model;
1887         vec3_t          modelorg;
1888
1889         // because bmodels can be reused, we have to decide which things to render
1890         // from scratch every time
1891
1892         model = ent->model;
1893
1894         Matrix4x4_Transform(&ent->inversematrix, r_origin, modelorg);
1895         for (i = 0;i < model->nummodelsurfaces;i++)
1896         {
1897                 surf = model->modelsortedsurfaces[i];
1898                 if (((surf->flags & SURF_PLANEBACK) == 0) == (PlaneDiff(modelorg, surf->plane) >= 0))
1899                         surf->visframe = r_framecount;
1900                 else
1901                         surf->visframe = -1;
1902                 surf->worldnodeframe = -1;
1903                 surf->lightframe = -1;
1904                 surf->dlightframe = -1;
1905                 surf->insertframe = -1;
1906         }
1907 }
1908
1909 void R_SetupForWorldRendering(entity_render_t *ent)
1910 {
1911         // there is only one instance of the world, but it can be rendered in
1912         // multiple stages
1913 }
1914
1915 static void R_SurfMarkLights (entity_render_t *ent)
1916 {
1917         int                     i;
1918         msurface_t      *surf;
1919
1920         if (r_dynamic.integer)
1921                 R_MarkLights(ent);
1922
1923         if (!r_vertexsurfaces.integer)
1924         {
1925                 for (i = 0;i < ent->model->nummodelsurfaces;i++)
1926                 {
1927                         surf = ent->model->modelsortedsurfaces[i];
1928                         if (surf->visframe == r_framecount && surf->lightmaptexture != NULL)
1929                         {
1930                                 if (surf->cached_dlight
1931                                  || surf->cached_ambient != r_ambient.value
1932                                  || surf->cached_lightscalebit != lightscalebit)
1933                                         R_BuildLightMap(ent, surf, false); // base lighting changed
1934                                 else if (r_dynamic.integer)
1935                                 {
1936                                         if  (surf->styles[0] != 255 && (d_lightstylevalue[surf->styles[0]] != surf->cached_light[0]
1937                                          || (surf->styles[1] != 255 && (d_lightstylevalue[surf->styles[1]] != surf->cached_light[1]
1938                                          || (surf->styles[2] != 255 && (d_lightstylevalue[surf->styles[2]] != surf->cached_light[2]
1939                                          || (surf->styles[3] != 255 && (d_lightstylevalue[surf->styles[3]] != surf->cached_light[3]))))))))
1940                                                 R_BuildLightMap(ent, surf, false); // base lighting changed
1941                                         else if (surf->dlightframe == r_framecount && r_dlightmap.integer)
1942                                                 R_BuildLightMap(ent, surf, true); // only dlights
1943                                 }
1944                         }
1945                 }
1946         }
1947 }
1948
1949 void R_MarkWorldLights(entity_render_t *ent)
1950 {
1951         R_SetupForWorldRendering(ent);
1952         R_SurfMarkLights(ent);
1953 }
1954
1955 /*
1956 =============
1957 R_DrawWorld
1958 =============
1959 */
1960 void R_DrawWorld (entity_render_t *ent)
1961 {
1962         R_SetupForWorldRendering(ent);
1963
1964         if (r_viewleaf->contents == CONTENTS_SOLID || r_novis.integer || r_viewleaf->compressed_vis == NULL)
1965                 R_SolidWorldNode (ent);
1966         else
1967                 R_PVSWorldNode (ent);
1968 }
1969
1970 /*
1971 =================
1972 R_DrawBrushModel
1973 =================
1974 */
1975 void R_DrawBrushModelSky (entity_render_t *ent)
1976 {
1977         R_SetupForBModelRendering(ent);
1978
1979         R_PrepareSurfaces(ent);
1980         R_DrawSurfaces(ent, SHADERSTAGE_SKY);
1981 }
1982
1983 void R_DrawBrushModelNormal (entity_render_t *ent)
1984 {
1985         c_bmodels++;
1986
1987         // have to flush queue because of possible lightmap reuse
1988         R_Mesh_Render();
1989
1990         R_SetupForBModelRendering(ent);
1991
1992         R_SurfMarkLights(ent);
1993
1994         R_PrepareSurfaces(ent);
1995
1996         if (!skyrendermasked)
1997                 R_DrawSurfaces(ent, SHADERSTAGE_SKY);
1998         R_DrawSurfaces(ent, SHADERSTAGE_NORMAL);
1999 }
2000
2001 static void gl_surf_start(void)
2002 {
2003 }
2004
2005 static void gl_surf_shutdown(void)
2006 {
2007 }
2008
2009 static void gl_surf_newmap(void)
2010 {
2011 }
2012
2013 void GL_Surf_Init(void)
2014 {
2015         int i;
2016         dlightdivtable[0] = 4194304;
2017         for (i = 1;i < 32768;i++)
2018                 dlightdivtable[i] = 4194304 / (i << 7);
2019
2020         Cvar_RegisterVariable(&r_ambient);
2021         Cvar_RegisterVariable(&r_vertexsurfaces);
2022         Cvar_RegisterVariable(&r_dlightmap);
2023         Cvar_RegisterVariable(&r_drawportals);
2024         Cvar_RegisterVariable(&r_testvis);
2025         Cvar_RegisterVariable(&r_floatbuildlightmap);
2026         Cvar_RegisterVariable(&r_detailtextures);
2027
2028         R_RegisterModule("GL_Surf", gl_surf_start, gl_surf_shutdown, gl_surf_newmap);
2029 }
2030