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