removed a lot of renderer cruft (such as 48% of gl_rsurf.c) as a result of the previo...
[xonotic/darkplaces.git] / gl_rsurf.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // r_surf.c: surface-related refresh code
21
22 #include "quakedef.h"
23 #include "r_shadow.h"
24
25 #define MAX_LIGHTMAP_SIZE 256
26
27 static unsigned int intblocklights[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*3]; // LordHavoc: *3 for colored lighting
28 static float floatblocklights[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*3]; // LordHavoc: *3 for colored lighting
29
30 static qbyte templight[MAX_LIGHTMAP_SIZE*MAX_LIGHTMAP_SIZE*4];
31
32 cvar_t r_ambient = {0, "r_ambient", "0"};
33 cvar_t r_drawportals = {0, "r_drawportals", "0"};
34 cvar_t r_testvis = {0, "r_testvis", "0"};
35 cvar_t r_floatbuildlightmap = {0, "r_floatbuildlightmap", "0"};
36 cvar_t r_detailtextures = {CVAR_SAVE, "r_detailtextures", "1"};
37 cvar_t r_surfaceworldnode = {0, "r_surfaceworldnode", "0"};
38 cvar_t r_drawcollisionbrushes_polygonfactor = {0, "r_drawcollisionbrushes_polygonfactor", "-1"};
39 cvar_t r_drawcollisionbrushes_polygonoffset = {0, "r_drawcollisionbrushes_polygonoffset", "0"};
40 cvar_t r_q3bsp_renderskydepth = {0, "r_q3bsp_renderskydepth", "0"};
41 cvar_t gl_lightmaps = {0, "gl_lightmaps", "0"};
42
43 // flag arrays used for visibility checking on world model
44 // (all other entities have no per-surface/per-leaf visibility checks)
45 // TODO: dynamic resize according to r_refdef.worldmodel->brush.num_clusters
46 qbyte r_pvsbits[(32768+7)>>3];
47 // TODO: dynamic resize according to r_refdef.worldmodel->brush.num_leafs
48 qbyte r_worldleafvisible[32768];
49 // TODO: dynamic resize according to r_refdef.worldmodel->brush.num_surfaces
50 qbyte r_worldsurfacevisible[262144];
51
52 /*
53 ===============
54 R_BuildLightMap
55
56 Combine and scale multiple lightmaps into the 8.8 format in blocklights
57 ===============
58 */
59 static void R_BuildLightMap (const entity_render_t *ent, msurface_t *surface)
60 {
61         if (!r_floatbuildlightmap.integer)
62         {
63                 int smax, tmax, i, j, size, size3, maps, stride, l;
64                 unsigned int *bl, scale;
65                 qbyte *lightmap, *out, *stain;
66
67                 // update cached lighting info
68                 surface->cached_dlight = 0;
69
70                 smax = (surface->extents[0]>>4)+1;
71                 tmax = (surface->extents[1]>>4)+1;
72                 size = smax*tmax;
73                 size3 = size*3;
74                 lightmap = surface->samples;
75
76         // set to full bright if no light data
77                 bl = intblocklights;
78                 if (!ent->model->brushq1.lightdata)
79                 {
80                         for (i = 0;i < size3;i++)
81                                 bl[i] = 255*256;
82                 }
83                 else
84                 {
85         // clear to no light
86                         memset(bl, 0, size*3*sizeof(unsigned int));
87
88         // add all the lightmaps
89                         if (lightmap)
90                         {
91                                 bl = intblocklights;
92                                 for (maps = 0;maps < MAXLIGHTMAPS && surface->styles[maps] != 255;maps++, lightmap += size3)
93                                         for (scale = d_lightstylevalue[surface->styles[maps]], i = 0;i < size3;i++)
94                                                 bl[i] += lightmap[i] * scale;
95                         }
96                 }
97
98                 stain = surface->stainsamples;
99                 bl = intblocklights;
100                 out = templight;
101                 // the >> 16 shift adjusts down 8 bits to account for the stainmap
102                 // scaling, and remaps the 0-65536 (2x overbright) to 0-256, it will
103                 // be doubled during rendering to achieve 2x overbright
104                 // (0 = 0.0, 128 = 1.0, 256 = 2.0)
105                 if (ent->model->brushq1.lightmaprgba)
106                 {
107                         stride = (surface->lightmaptexturestride - smax) * 4;
108                         for (i = 0;i < tmax;i++, out += stride)
109                         {
110                                 for (j = 0;j < smax;j++)
111                                 {
112                                         l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255);
113                                         l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255);
114                                         l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255);
115                                         *out++ = 255;
116                                 }
117                         }
118                 }
119                 else
120                 {
121                         stride = (surface->lightmaptexturestride - smax) * 3;
122                         for (i = 0;i < tmax;i++, out += stride)
123                         {
124                                 for (j = 0;j < smax;j++)
125                                 {
126                                         l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255);
127                                         l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255);
128                                         l = (*bl++ * *stain++) >> 16;*out++ = min(l, 255);
129                                 }
130                         }
131                 }
132
133                 R_UpdateTexture(surface->lightmaptexture, templight);
134         }
135         else
136         {
137                 int smax, tmax, i, j, size, size3, maps, stride, l;
138                 float *bl, scale;
139                 qbyte *lightmap, *out, *stain;
140
141                 // update cached lighting info
142                 surface->cached_dlight = 0;
143
144                 smax = (surface->extents[0]>>4)+1;
145                 tmax = (surface->extents[1]>>4)+1;
146                 size = smax*tmax;
147                 size3 = size*3;
148                 lightmap = surface->samples;
149
150         // set to full bright if no light data
151                 bl = floatblocklights;
152                 if (!ent->model->brushq1.lightdata)
153                 {
154                         for (i = 0;i < size3;i++)
155                                 bl[i] = 255*256;
156                 }
157                 else
158                 {
159                         memset(bl, 0, size*3*sizeof(float));
160
161                         // add all the lightmaps
162                         if (lightmap)
163                         {
164                                 bl = floatblocklights;
165                                 for (maps = 0;maps < MAXLIGHTMAPS && surface->styles[maps] != 255;maps++, lightmap += size3)
166                                         for (scale = d_lightstylevalue[surface->styles[maps]], i = 0;i < size3;i++)
167                                                 bl[i] += lightmap[i] * scale;
168                         }
169                 }
170
171                 stain = surface->stainsamples;
172                 bl = floatblocklights;
173                 out = templight;
174                 // this scaling adjusts down 8 bits to account for the stainmap
175                 // scaling, and remaps the 0.0-2.0 (2x overbright) to 0-256, it will
176                 // be doubled during rendering to achieve 2x overbright
177                 // (0 = 0.0, 128 = 1.0, 256 = 2.0)
178                 scale = 1.0f / (1 << 16);
179                 if (ent->model->brushq1.lightmaprgba)
180                 {
181                         stride = (surface->lightmaptexturestride - smax) * 4;
182                         for (i = 0;i < tmax;i++, out += stride)
183                         {
184                                 for (j = 0;j < smax;j++)
185                                 {
186                                         l = *bl++ * *stain++ * scale;*out++ = min(l, 255);
187                                         l = *bl++ * *stain++ * scale;*out++ = min(l, 255);
188                                         l = *bl++ * *stain++ * scale;*out++ = min(l, 255);
189                                         *out++ = 255;
190                                 }
191                         }
192                 }
193                 else
194                 {
195                         stride = (surface->lightmaptexturestride - smax) * 3;
196                         for (i = 0;i < tmax;i++, out += stride)
197                         {
198                                 for (j = 0;j < smax;j++)
199                                 {
200                                         l = *bl++ * *stain++ * scale;*out++ = min(l, 255);
201                                         l = *bl++ * *stain++ * scale;*out++ = min(l, 255);
202                                         l = *bl++ * *stain++ * scale;*out++ = min(l, 255);
203                                 }
204                         }
205                 }
206
207                 R_UpdateTexture(surface->lightmaptexture, templight);
208         }
209 }
210
211 void R_StainNode (mnode_t *node, model_t *model, const vec3_t origin, float radius, const float fcolor[8])
212 {
213         float ndist, a, ratio, maxdist, maxdist2, maxdist3, invradius, sdtable[256], td, dist2;
214         msurface_t *surface, *endsurface;
215         int i, s, t, smax, tmax, smax3, impacts, impactt, stained;
216         qbyte *bl;
217         vec3_t impact;
218
219         maxdist = radius * radius;
220         invradius = 1.0f / radius;
221
222 loc0:
223         if (!node->plane)
224                 return;
225         ndist = PlaneDiff(origin, node->plane);
226         if (ndist > radius)
227         {
228                 node = node->children[0];
229                 goto loc0;
230         }
231         if (ndist < -radius)
232         {
233                 node = node->children[1];
234                 goto loc0;
235         }
236
237         dist2 = ndist * ndist;
238         maxdist3 = maxdist - dist2;
239
240         if (node->plane->type < 3)
241         {
242                 VectorCopy(origin, impact);
243                 impact[node->plane->type] -= ndist;
244         }
245         else
246         {
247                 impact[0] = origin[0] - node->plane->normal[0] * ndist;
248                 impact[1] = origin[1] - node->plane->normal[1] * ndist;
249                 impact[2] = origin[2] - node->plane->normal[2] * ndist;
250         }
251
252         for (surface = model->brush.data_surfaces + node->firstsurface, endsurface = surface + node->numsurfaces;surface < endsurface;surface++)
253         {
254                 if (surface->stainsamples)
255                 {
256                         smax = (surface->extents[0] >> 4) + 1;
257                         tmax = (surface->extents[1] >> 4) + 1;
258
259                         impacts = DotProduct (impact, surface->texinfo->vecs[0]) + surface->texinfo->vecs[0][3] - surface->texturemins[0];
260                         impactt = DotProduct (impact, surface->texinfo->vecs[1]) + surface->texinfo->vecs[1][3] - surface->texturemins[1];
261
262                         s = bound(0, impacts, smax * 16) - impacts;
263                         t = bound(0, impactt, tmax * 16) - impactt;
264                         i = s * s + t * t + dist2;
265                         if (i > maxdist)
266                                 continue;
267
268                         // reduce calculations
269                         for (s = 0, i = impacts; s < smax; s++, i -= 16)
270                                 sdtable[s] = i * i + dist2;
271
272                         bl = surface->stainsamples;
273                         smax3 = smax * 3;
274                         stained = false;
275
276                         i = impactt;
277                         for (t = 0;t < tmax;t++, i -= 16)
278                         {
279                                 td = i * i;
280                                 // make sure some part of it is visible on this line
281                                 if (td < maxdist3)
282                                 {
283                                         maxdist2 = maxdist - td;
284                                         for (s = 0;s < smax;s++)
285                                         {
286                                                 if (sdtable[s] < maxdist2)
287                                                 {
288                                                         ratio = lhrandom(0.0f, 1.0f);
289                                                         a = (fcolor[3] + ratio * fcolor[7]) * (1.0f - sqrt(sdtable[s] + td) * invradius);
290                                                         if (a >= (1.0f / 64.0f))
291                                                         {
292                                                                 if (a > 1)
293                                                                         a = 1;
294                                                                 bl[0] = (qbyte) ((float) bl[0] + a * ((fcolor[0] + ratio * fcolor[4]) - (float) bl[0]));
295                                                                 bl[1] = (qbyte) ((float) bl[1] + a * ((fcolor[1] + ratio * fcolor[5]) - (float) bl[1]));
296                                                                 bl[2] = (qbyte) ((float) bl[2] + a * ((fcolor[2] + ratio * fcolor[6]) - (float) bl[2]));
297                                                                 stained = true;
298                                                         }
299                                                 }
300                                                 bl += 3;
301                                         }
302                                 }
303                                 else // skip line
304                                         bl += smax3;
305                         }
306                         // force lightmap upload
307                         if (stained)
308                                 surface->cached_dlight = true;
309                 }
310         }
311
312         if (node->children[0]->plane)
313         {
314                 if (node->children[1]->plane)
315                 {
316                         R_StainNode(node->children[0], model, origin, radius, fcolor);
317                         node = node->children[1];
318                         goto loc0;
319                 }
320                 else
321                 {
322                         node = node->children[0];
323                         goto loc0;
324                 }
325         }
326         else if (node->children[1]->plane)
327         {
328                 node = node->children[1];
329                 goto loc0;
330         }
331 }
332
333 void R_Stain (const vec3_t origin, float radius, int cr1, int cg1, int cb1, int ca1, int cr2, int cg2, int cb2, int ca2)
334 {
335         int n;
336         float fcolor[8];
337         entity_render_t *ent;
338         model_t *model;
339         vec3_t org;
340         if (r_refdef.worldmodel == NULL || !r_refdef.worldmodel->brush.data_nodes)
341                 return;
342         fcolor[0] = cr1;
343         fcolor[1] = cg1;
344         fcolor[2] = cb1;
345         fcolor[3] = ca1 * (1.0f / 64.0f);
346         fcolor[4] = cr2 - cr1;
347         fcolor[5] = cg2 - cg1;
348         fcolor[6] = cb2 - cb1;
349         fcolor[7] = (ca2 - ca1) * (1.0f / 64.0f);
350
351         R_StainNode(r_refdef.worldmodel->brush.data_nodes + r_refdef.worldmodel->brushq1.hulls[0].firstclipnode, r_refdef.worldmodel, origin, radius, fcolor);
352
353         // look for embedded bmodels
354         for (n = 0;n < cl_num_brushmodel_entities;n++)
355         {
356                 ent = cl_brushmodel_entities[n];
357                 model = ent->model;
358                 if (model && model->name[0] == '*')
359                 {
360                         Mod_CheckLoaded(model);
361                         if (model->brush.data_nodes)
362                         {
363                                 Matrix4x4_Transform(&ent->inversematrix, origin, org);
364                                 R_StainNode(model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode, model, org, radius, fcolor);
365                         }
366                 }
367         }
368 }
369
370
371 /*
372 =============================================================
373
374         BRUSH MODELS
375
376 =============================================================
377 */
378
379 static float *RSurf_GetVertexPointer(const entity_render_t *ent, const msurface_t *surface)
380 {
381         if (surface->texture->textureflags & (Q3TEXTUREFLAG_AUTOSPRITE | Q3TEXTUREFLAG_AUTOSPRITE2))
382         {
383                 texture_t *texture = surface->texture;
384                 int i, j;
385                 float center[3], center2[3], forward[3], right[3], up[3], v[4][3];
386                 matrix4x4_t matrix1, imatrix1;
387                 R_Mesh_Matrix(&r_identitymatrix);
388                 // a single autosprite surface can contain multiple sprites...
389                 for (j = 0;j < surface->mesh.num_vertices - 3;j += 4)
390                 {
391                         VectorClear(center);
392                         for (i = 0;i < 4;i++)
393                                 VectorAdd(center, surface->mesh.data_vertex3f + (j+i) * 3, center);
394                         VectorScale(center, 0.25f, center);
395                         Matrix4x4_Transform(&ent->matrix, center, center2);
396                         // FIXME: calculate vectors from triangle edges instead of using texture vectors as an easy way out?
397                         Matrix4x4_FromVectors(&matrix1, surface->mesh.data_normal3f + j*3, surface->mesh.data_svector3f + j*3, surface->mesh.data_tvector3f + j*3, center);
398                         Matrix4x4_Invert_Simple(&imatrix1, &matrix1);
399                         for (i = 0;i < 4;i++)
400                                 Matrix4x4_Transform(&imatrix1, surface->mesh.data_vertex3f + (j+i)*3, v[i]);
401                         if (texture->textureflags & Q3TEXTUREFLAG_AUTOSPRITE2)
402                         {
403                                 forward[0] = r_vieworigin[0] - center2[0];
404                                 forward[1] = r_vieworigin[1] - center2[1];
405                                 forward[2] = 0;
406                                 VectorNormalize(forward);
407                                 right[0] = forward[1];
408                                 right[1] = -forward[0];
409                                 right[2] = 0;
410                                 up[0] = 0;
411                                 up[1] = 0;
412                                 up[2] = 1;
413                         }
414                         else
415                         {
416                                 VectorCopy(r_viewforward, forward);
417                                 VectorCopy(r_viewright, right);
418                                 VectorCopy(r_viewup, up);
419                         }
420                         for (i = 0;i < 4;i++)
421                                 VectorMAMAMAM(1, center2, v[i][0], forward, v[i][1], right, v[i][2], up, varray_vertex3f + (i+j) * 3);
422                 }
423                 return varray_vertex3f;
424         }
425         else
426                 return surface->mesh.data_vertex3f;
427 }
428
429 void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t)
430 {
431         // we don't need to set currentframe if t->animated is false because
432         // it was already set up by the texture loader for non-animating
433         if (t->animated)
434         {
435                 t->currentframe = t->anim_frames[ent->frame != 0][(t->anim_total[ent->frame != 0] >= 2) ? ((int)(r_refdef.time * 5.0f) % t->anim_total[ent->frame != 0]) : 0];
436                 t = t->currentframe;
437         }
438         t->currentmaterialflags = t->basematerialflags;
439         t->currentalpha = ent->alpha;
440         if (t->basematerialflags & MATERIALFLAG_WATERALPHA)
441                 t->currentalpha *= r_wateralpha.value;
442         if (!(ent->flags & RENDER_LIGHT))
443                 t->currentmaterialflags |= MATERIALFLAG_FULLBRIGHT;
444         if (ent->effects & EF_ADDITIVE)
445                 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_TRANSPARENT;
446         else if (t->currentalpha < 1)
447                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_TRANSPARENT;
448 }
449
450 matrix4x4_t r_surf_waterscrollmatrix;
451
452 void R_UpdateAllTextureInfo(entity_render_t *ent)
453 {
454         int i;
455         Matrix4x4_CreateTranslate(&r_surf_waterscrollmatrix, sin(r_refdef.time) * 0.025 * r_waterscroll.value, sin(r_refdef.time * 0.8f) * 0.025 * r_waterscroll.value, 0);
456         if (ent->model)
457                 for (i = 0;i < ent->model->brush.num_textures;i++)
458                         R_UpdateTextureInfo(ent, ent->model->brush.data_textures + i);
459 }
460
461 static void R_DrawSurfaceList(const entity_render_t *ent, texture_t *texture, int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t modelorg)
462 {
463         int i;
464         int texturesurfaceindex;
465         const float *v;
466         float *c;
467         float diff[3];
468         float f, r, g, b, a, base, colorscale;
469         const msurface_t *surface;
470         qboolean dolightmap;
471         qboolean dobase;
472         qboolean doambient;
473         qboolean dodetail;
474         qboolean doglow;
475         qboolean dofogpass;
476         qboolean fogallpasses;
477         qboolean waterscrolling;
478         rmeshstate_t m;
479         texture = texture->currentframe;
480         if (texture->currentmaterialflags & MATERIALFLAG_NODRAW)
481                 return;
482         c_faces += texturenumsurfaces;
483         // gl_lightmaps debugging mode skips normal texturing
484         if (gl_lightmaps.integer)
485         {
486                 GL_BlendFunc(GL_ONE, GL_ZERO);
487                 GL_DepthMask(true);
488                 GL_DepthTest(true);
489                 qglDisable(GL_CULL_FACE);
490                 GL_Color(1, 1, 1, 1);
491                 memset(&m, 0, sizeof(m));
492                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
493                 {
494                         surface = texturesurfacelist[texturesurfaceindex];
495                         m.tex[0] = R_GetTexture(surface->lightmaptexture);
496                         m.pointer_texcoord[0] = surface->mesh.data_texcoordlightmap2f;
497                         if (surface->lightmaptexture)
498                         {
499                                 GL_Color(1, 1, 1, 1);
500                                 m.pointer_color = NULL;
501                         }
502                         else
503                                 m.pointer_color = surface->mesh.data_lightmapcolor4f;
504                         m.pointer_vertex = surface->mesh.data_vertex3f;
505                         R_Mesh_State(&m);
506                         GL_LockArrays(0, surface->mesh.num_vertices);
507                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
508                         GL_LockArrays(0, 0);
509                 }
510                 qglEnable(GL_CULL_FACE);
511                 return;
512         }
513         GL_DepthTest(!(texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
514         GL_DepthMask(!(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT));
515         if (texture->currentmaterialflags & MATERIALFLAG_ADD)
516                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
517         else if (texture->currentmaterialflags & MATERIALFLAG_ALPHA)
518                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
519         else
520                 GL_BlendFunc(GL_ONE, GL_ZERO);
521         // water waterscrolling in texture matrix
522         waterscrolling = (texture->currentmaterialflags & MATERIALFLAG_WATER) && r_waterscroll.value != 0;
523         if (texture->textureflags & Q3TEXTUREFLAG_TWOSIDED)
524                 qglDisable(GL_CULL_FACE);
525         if (texture->currentmaterialflags & MATERIALFLAG_SKY)
526         {
527                 if (skyrendernow)
528                 {
529                         skyrendernow = false;
530                         if (skyrendermasked)
531                                 R_Sky();
532                 }
533                 // LordHavoc: HalfLife maps have freaky skypolys...
534                 if (!ent->model->brush.ishlbsp)
535                 {
536                         R_Mesh_Matrix(&ent->matrix);
537                         GL_Color(fogcolor[0], fogcolor[1], fogcolor[2], 1);
538                         if (skyrendermasked)
539                         {
540                                 // depth-only (masking)
541                                 GL_ColorMask(0,0,0,0);
542                                 // just to make sure that braindead drivers don't draw anything
543                                 // despite that colormask...
544                                 GL_BlendFunc(GL_ZERO, GL_ONE);
545                         }
546                         else
547                         {
548                                 // fog sky
549                                 GL_BlendFunc(GL_ONE, GL_ZERO);
550                         }
551                         GL_DepthMask(true);
552                         GL_DepthTest(true);
553                         memset(&m, 0, sizeof(m));
554                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
555                         {
556                                 surface = texturesurfacelist[texturesurfaceindex];
557                                 m.pointer_vertex = surface->mesh.data_vertex3f;
558                                 R_Mesh_State(&m);
559                                 GL_LockArrays(0, surface->mesh.num_vertices);
560                                 R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
561                                 GL_LockArrays(0, 0);
562                         }
563                         GL_ColorMask(r_refdef.colormask[0], r_refdef.colormask[1], r_refdef.colormask[2], 1);
564                 }
565         }
566         else if ((texture->currentmaterialflags & MATERIALFLAG_WATER) && r_watershader.value && gl_textureshader && !texture->skin.glow && !fogenabled && ent->colormod[0] == 1 && ent->colormod[1] == 1 && ent->colormod[2] == 1)
567         {
568                 // NVIDIA Geforce3 distortion texture shader on water
569                 float args[4] = {0.05f,0,0,0.04f};
570                 memset(&m, 0, sizeof(m));
571                 m.tex[0] = R_GetTexture(mod_shared_distorttexture[(int)(r_refdef.time * 16)&63]);
572                 m.tex[1] = R_GetTexture(texture->skin.base);
573                 m.texcombinergb[0] = GL_REPLACE;
574                 m.texcombinergb[1] = GL_REPLACE;
575                 Matrix4x4_CreateFromQuakeEntity(&m.texmatrix[0], 0, 0, 0, 0, 0, 0, r_watershader.value);
576                 m.texmatrix[1] = r_surf_waterscrollmatrix;
577
578                 GL_ActiveTexture(0);
579                 qglTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_2D);
580                 GL_ActiveTexture(1);
581                 qglTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_OFFSET_TEXTURE_2D_NV);
582                 qglTexEnvi(GL_TEXTURE_SHADER_NV, GL_PREVIOUS_TEXTURE_INPUT_NV, GL_TEXTURE0_ARB);
583                 qglTexEnvfv(GL_TEXTURE_SHADER_NV, GL_OFFSET_TEXTURE_MATRIX_NV, &args[0]);
584                 qglEnable(GL_TEXTURE_SHADER_NV);
585
586                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
587                 {
588                         surface = texturesurfacelist[texturesurfaceindex];
589                         m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
590                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
591                         m.pointer_texcoord[1] = surface->mesh.data_texcoordtexture2f;
592                         R_Mesh_State(&m);
593                         GL_LockArrays(0, surface->mesh.num_vertices);
594                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
595                         GL_LockArrays(0, 0);
596                 }
597
598                 qglDisable(GL_TEXTURE_SHADER_NV);
599                 qglTexEnvi(GL_TEXTURE_SHADER_NV, GL_SHADER_OPERATION_NV, GL_TEXTURE_2D);
600                 GL_ActiveTexture(0);
601         }
602         else if (texture->currentmaterialflags & (MATERIALFLAG_WATER | MATERIALFLAG_WALL))
603         {
604                 // normal surface (wall or water)
605                 dobase = true;
606                 dolightmap = !(texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT);
607                 doambient = r_ambient.value >= (1/64.0f);
608                 dodetail = texture->skin.detail != NULL && !(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT);
609                 doglow = texture->skin.glow != NULL;
610                 dofogpass = fogenabled && !(texture->currentmaterialflags & MATERIALFLAG_ADD);
611                 fogallpasses = fogenabled && !(texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT);
612                 if (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT)
613                 {
614                         if (dobase && dolightmap && gl_combine.integer)
615                         {
616                                 dobase = false;
617                                 memset(&m, 0, sizeof(m));
618                                 m.tex[1] = R_GetTexture(texture->skin.base);
619                                 if (waterscrolling)
620                                         m.texmatrix[1] = r_surf_waterscrollmatrix;
621                                 m.texrgbscale[1] = 2;
622                                 m.pointer_color = varray_color4f;
623                                 colorscale = 1;
624                                 r = ent->colormod[0] * colorscale;
625                                 g = ent->colormod[1] * colorscale;
626                                 b = ent->colormod[2] * colorscale;
627                                 a = texture->currentalpha;
628                                 base = r_ambient.value * (1.0f / 64.0f);
629                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
630                                 {
631                                         surface = texturesurfacelist[texturesurfaceindex];
632                                         m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
633                                         m.pointer_texcoord[0] = surface->mesh.data_texcoordlightmap2f;
634                                         m.pointer_texcoord[1] = surface->mesh.data_texcoordtexture2f;
635                                         if (surface->lightmaptexture)
636                                         {
637                                                 m.tex[0] = R_GetTexture(surface->lightmaptexture);
638                                                 if (fogallpasses)
639                                                 {
640                                                         m.pointer_color = varray_color4f;
641                                                         for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
642                                                         {
643                                                                 VectorSubtract(v, modelorg, diff);
644                                                                 f = 1 - exp(fogdensity/DotProduct(diff, diff));
645                                                                 c[0] = f * r;
646                                                                 c[1] = f * g;
647                                                                 c[2] = f * b;
648                                                                 c[3] = a;
649                                                         }
650                                                 }
651                                                 else
652                                                 {
653                                                         m.pointer_color = NULL;
654                                                         GL_Color(r, g, b, a);
655                                                 }
656                                         }
657                                         else
658                                         {
659                                                 m.tex[0] = R_GetTexture(r_texture_white);
660                                                 m.pointer_color = varray_color4f;
661                                                 if (surface->styles[0] != 255)
662                                                 {
663                                                         for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
664                                                         {
665                                                                 c[0] = 0;
666                                                                 c[1] = 0;
667                                                                 c[2] = 0;
668                                                                 if (surface->styles[0] != 255)
669                                                                 {
670                                                                         if (surface->mesh.data_lightmapcolor4f)
671                                                                         {
672                                                                                 float scale = d_lightstylevalue[surface->styles[0]] * (1.0f / 128.0f);
673                                                                                 VectorMA(c, scale, surface->mesh.data_lightmapcolor4f + i*4, c);
674                                                                         }
675                                                                         else if (surface->mesh.data_lightmapoffsets)
676                                                                         {
677                                                                                 const qbyte *lm = surface->samples + surface->mesh.data_lightmapoffsets[i];
678                                                                                 float scale = d_lightstylevalue[surface->styles[0]] * (1.0f / 32768.0f);
679                                                                                 VectorMA(c, scale, lm, c);
680                                                                                 if (surface->styles[1] != 255)
681                                                                                 {
682                                                                                         int size3 = ((surface->extents[0]>>4)+1)*((surface->extents[1]>>4)+1)*3;
683                                                                                         lm += size3;
684                                                                                         scale = d_lightstylevalue[surface->styles[1]] * (1.0f / 32768.0f);
685                                                                                         VectorMA(c, scale, lm, c);
686                                                                                         if (surface->styles[2] != 255)
687                                                                                         {
688                                                                                                 lm += size3;
689                                                                                                 scale = d_lightstylevalue[surface->styles[2]] * (1.0f / 32768.0f);
690                                                                                                 VectorMA(c, scale, lm, c);
691                                                                                                 if (surface->styles[3] != 255)
692                                                                                                 {
693                                                                                                         lm += size3;
694                                                                                                         scale = d_lightstylevalue[surface->styles[3]] * (1.0f / 32768.0f);
695                                                                                                         VectorMA(c, scale, lm, c);
696                                                                                                 }
697                                                                                         }
698                                                                                 }
699                                                                         }
700                                                                 }
701                                                                 c[0] *= r;
702                                                                 c[1] *= g;
703                                                                 c[2] *= b;
704                                                                 if (fogallpasses)
705                                                                 {
706                                                                         VectorSubtract(v, modelorg, diff);
707                                                                         f = 1 - exp(fogdensity/DotProduct(diff, diff));
708                                                                         VectorScale(c, f, c);
709                                                                 }
710                                                                 if (surface->mesh.data_lightmapcolor4f && (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
711                                                                         c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a;
712                                                                 else
713                                                                         c[3] = a;
714                                                         }
715                                                 }
716                                                 else
717                                                 {
718                                                         if (surface->mesh.data_lightmapcolor4f && (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
719                                                         {
720                                                                 for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
721                                                                 {
722                                                                         c[0] = 0;
723                                                                         c[1] = 0;
724                                                                         c[2] = 0;
725                                                                         c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a;
726                                                                 }
727                                                         }
728                                                         else
729                                                         {
730                                                                 m.pointer_color = NULL;
731                                                                 GL_Color(0, 0, 0, a);
732                                                         }
733                                                 }
734                                         }
735                                         R_Mesh_State(&m);
736                                         GL_LockArrays(0, surface->mesh.num_vertices);
737                                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
738                                         GL_LockArrays(0, 0);
739                                 }
740                         }
741                         if (dobase)
742                         {
743                                 dobase = false;
744                                 memset(&m, 0, sizeof(m));
745                                 m.tex[0] = R_GetTexture(texture->skin.base);
746                                 if (waterscrolling)
747                                         m.texmatrix[0] = r_surf_waterscrollmatrix;
748                                 m.texmatrix[0] = r_surf_waterscrollmatrix;
749                                 m.pointer_color = varray_color4f;
750                                 colorscale = 1;
751                                 if (gl_combine.integer)
752                                 {
753                                         m.texrgbscale[0] = 4;
754                                         colorscale *= 0.25f;
755                                 }
756                                 r = ent->colormod[0] * colorscale;
757                                 g = ent->colormod[1] * colorscale;
758                                 b = ent->colormod[2] * colorscale;
759                                 a = texture->currentalpha;
760                                 if (dolightmap)
761                                 {
762                                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
763                                         {
764                                                 surface = texturesurfacelist[texturesurfaceindex];
765                                                 m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
766                                                 m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
767                                                 for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
768                                                 {
769                                                         c[0] = 0;
770                                                         c[1] = 0;
771                                                         c[2] = 0;
772                                                         if (surface->styles[0] != 255)
773                                                         {
774                                                                 if (surface->mesh.data_lightmapcolor4f)
775                                                                 {
776                                                                         float scale = d_lightstylevalue[surface->styles[0]] * (1.0f / 128.0f);
777                                                                         VectorMA(c, scale, surface->mesh.data_lightmapcolor4f + i*4, c);
778                                                                 }
779                                                                 else if (surface->mesh.data_lightmapoffsets)
780                                                                 {
781                                                                         const qbyte *lm = surface->samples + surface->mesh.data_lightmapoffsets[i];
782                                                                         float scale = d_lightstylevalue[surface->styles[0]] * (1.0f / 32768.0f);
783                                                                         VectorMA(c, scale, lm, c);
784                                                                         if (surface->styles[1] != 255)
785                                                                         {
786                                                                                 int size3 = ((surface->extents[0]>>4)+1)*((surface->extents[1]>>4)+1)*3;
787                                                                                 lm += size3;
788                                                                                 scale = d_lightstylevalue[surface->styles[1]] * (1.0f / 32768.0f);
789                                                                                 VectorMA(c, scale, lm, c);
790                                                                                 if (surface->styles[2] != 255)
791                                                                                 {
792                                                                                         lm += size3;
793                                                                                         scale = d_lightstylevalue[surface->styles[2]] * (1.0f / 32768.0f);
794                                                                                         VectorMA(c, scale, lm, c);
795                                                                                         if (surface->styles[3] != 255)
796                                                                                         {
797                                                                                                 lm += size3;
798                                                                                                 scale = d_lightstylevalue[surface->styles[3]] * (1.0f / 32768.0f);
799                                                                                                 VectorMA(c, scale, lm, c);
800                                                                                         }
801                                                                                 }
802                                                                         }
803                                                                 }
804                                                         }
805                                                         c[0] *= r;
806                                                         c[1] *= g;
807                                                         c[2] *= b;
808                                                         if (fogallpasses)
809                                                         {
810                                                                 VectorSubtract(v, modelorg, diff);
811                                                                 f = 1 - exp(fogdensity/DotProduct(diff, diff));
812                                                                 VectorScale(c, f, c);
813                                                         }
814                                                         if (surface->mesh.data_lightmapcolor4f && (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
815                                                                 c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a;
816                                                         else
817                                                                 c[3] = a;
818                                                 }
819                                                 R_Mesh_State(&m);
820                                                 GL_LockArrays(0, surface->mesh.num_vertices);
821                                                 R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
822                                                 GL_LockArrays(0, 0);
823                                         }
824                                 }
825                                 else
826                                 {
827                                         if (fogallpasses)
828                                         {
829                                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
830                                                 {
831                                                         surface = texturesurfacelist[texturesurfaceindex];
832                                                         m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
833                                                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
834                                                         if (m.tex[1])
835                                                                 m.pointer_texcoord[1] = surface->mesh.data_texcoordtexture2f;
836                                                         if (surface->mesh.data_lightmapcolor4f && (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
837                                                         {
838                                                                 m.pointer_color = varray_color4f;
839                                                                 for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
840                                                                 {
841                                                                         VectorSubtract(v, modelorg, diff);
842                                                                         f = 1 - exp(fogdensity/DotProduct(diff, diff));
843                                                                         c[0] = r * f;
844                                                                         c[1] = g * f;
845                                                                         c[2] = b * f;
846                                                                         c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a;
847                                                                 }
848                                                         }
849                                                         else
850                                                         {
851                                                                 m.pointer_color = varray_color4f;
852                                                                 for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
853                                                                 {
854                                                                         VectorSubtract(v, modelorg, diff);
855                                                                         f = 1 - exp(fogdensity/DotProduct(diff, diff));
856                                                                         c[0] = r * f;
857                                                                         c[1] = g * f;
858                                                                         c[2] = b * f;
859                                                                         c[3] = a;
860                                                                 }
861                                                         }
862                                                         R_Mesh_State(&m);
863                                                         GL_LockArrays(0, surface->mesh.num_vertices);
864                                                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
865                                                         GL_LockArrays(0, 0);
866                                                 }
867                                         }
868                                         else
869                                         {
870                                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
871                                                 {
872                                                         surface = texturesurfacelist[texturesurfaceindex];
873                                                         m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
874                                                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
875                                                         if (m.tex[1])
876                                                                 m.pointer_texcoord[1] = surface->mesh.data_texcoordtexture2f;
877                                                         if (surface->mesh.data_lightmapcolor4f && (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
878                                                         {
879                                                                 m.pointer_color = varray_color4f;
880                                                                 for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
881                                                                 {
882                                                                         c[0] = r;
883                                                                         c[1] = g;
884                                                                         c[2] = b;
885                                                                         c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a;
886                                                                 }
887                                                         }
888                                                         else
889                                                         {
890                                                                 m.pointer_color = NULL;
891                                                                 GL_Color(r, g, b, a);
892                                                         }
893                                                         R_Mesh_State(&m);
894                                                         GL_LockArrays(0, surface->mesh.num_vertices);
895                                                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
896                                                         GL_LockArrays(0, 0);
897                                                 }
898                                         }
899                                 }
900                         }
901                 }
902                 else
903                 {
904                         if (!dolightmap && dobase)
905                         {
906                                 dolightmap = false;
907                                 dobase = false;
908                                 GL_Color(ent->colormod[0], ent->colormod[1], ent->colormod[2], 1);
909                                 memset(&m, 0, sizeof(m));
910                                 m.tex[0] = R_GetTexture(texture->skin.base);
911                                 if (waterscrolling)
912                                         m.texmatrix[0] = r_surf_waterscrollmatrix;
913                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
914                                 {
915                                         surface = texturesurfacelist[texturesurfaceindex];
916                                         m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
917                                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
918                                         R_Mesh_State(&m);
919                                         GL_LockArrays(0, surface->mesh.num_vertices);
920                                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
921                                         GL_LockArrays(0, 0);
922                                 }
923                         }
924                         if (r_lightmapintensity <= 0 && dolightmap && dobase)
925                         {
926                                 dolightmap = false;
927                                 dobase = false;
928                                 GL_Color(0, 0, 0, 1);
929                                 memset(&m, 0, sizeof(m));
930                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
931                                 {
932                                         surface = texturesurfacelist[texturesurfaceindex];
933                                         m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
934                                         R_Mesh_State(&m);
935                                         GL_LockArrays(0, surface->mesh.num_vertices);
936                                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
937                                         GL_LockArrays(0, 0);
938                                 }
939                         }
940                         if (r_textureunits.integer >= 2 && gl_combine.integer && dolightmap && dobase)
941                         {
942                                 // dualtexture combine
943                                 GL_BlendFunc(GL_ONE, GL_ZERO);
944                                 GL_DepthMask(true);
945                                 dolightmap = false;
946                                 dobase = false;
947                                 memset(&m, 0, sizeof(m));
948                                 m.tex[1] = R_GetTexture(texture->skin.base);
949                                 if (waterscrolling)
950                                         m.texmatrix[1] = r_surf_waterscrollmatrix;
951                                 m.texrgbscale[1] = 2;
952                                 r = ent->colormod[0] * r_lightmapintensity;
953                                 g = ent->colormod[1] * r_lightmapintensity;
954                                 b = ent->colormod[2] * r_lightmapintensity;
955                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
956                                 {
957                                         surface = texturesurfacelist[texturesurfaceindex];
958                                         memset(&m, 0, sizeof(m));
959                                         m.tex[1] = R_GetTexture(texture->skin.base);
960                                         if (waterscrolling)
961                                                 m.texmatrix[1] = r_surf_waterscrollmatrix;
962                                         m.texrgbscale[1] = 2;
963                                         m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
964                                         m.pointer_texcoord[0] = surface->mesh.data_texcoordlightmap2f;
965                                         m.pointer_texcoord[1] = surface->mesh.data_texcoordtexture2f;
966                                         if (surface->lightmaptexture)
967                                         {
968                                                 m.tex[0] = R_GetTexture(surface->lightmaptexture);
969                                                 m.pointer_color = NULL;
970                                                 GL_Color(r, g, b, 1);
971                                         }
972                                         else if (r == 1 && g == 1 && b == 1)
973                                         {
974                                                 m.tex[0] = R_GetTexture(r_texture_white);
975                                                 m.pointer_color = surface->mesh.data_lightmapcolor4f;
976                                         }
977                                         else
978                                         {
979                                                 m.tex[0] = R_GetTexture(r_texture_white);
980                                                 m.pointer_color = varray_color4f;
981                                                 for (i = 0;i < surface->mesh.num_vertices;i++)
982                                                 {
983                                                         varray_color4f[i*4+0] = surface->mesh.data_lightmapcolor4f[i*4+0] * r;
984                                                         varray_color4f[i*4+1] = surface->mesh.data_lightmapcolor4f[i*4+1] * g;
985                                                         varray_color4f[i*4+2] = surface->mesh.data_lightmapcolor4f[i*4+2] * b;
986                                                         varray_color4f[i*4+3] = surface->mesh.data_lightmapcolor4f[i*4+3];
987                                                 }
988                                         }
989                                         R_Mesh_State(&m);
990                                         GL_LockArrays(0, surface->mesh.num_vertices);
991                                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
992                                         GL_LockArrays(0, 0);
993                                 }
994                         }
995                         // single texture
996                         if (dolightmap)
997                         {
998                                 GL_BlendFunc(GL_ONE, GL_ZERO);
999                                 GL_DepthMask(true);
1000                                 GL_Color(1, 1, 1, 1);
1001                                 memset(&m, 0, sizeof(m));
1002                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1003                                 {
1004                                         surface = texturesurfacelist[texturesurfaceindex];
1005                                         m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
1006                                         m.tex[0] = R_GetTexture(surface->lightmaptexture);
1007                                         m.pointer_texcoord[0] = surface->mesh.data_texcoordlightmap2f;
1008                                         if (surface->lightmaptexture)
1009                                                 m.pointer_color = NULL;
1010                                         else
1011                                                 m.pointer_color = surface->mesh.data_lightmapcolor4f;
1012                                         R_Mesh_State(&m);
1013                                         GL_LockArrays(0, surface->mesh.num_vertices);
1014                                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1015                                         GL_LockArrays(0, 0);
1016                                 }
1017                         }
1018                         if (dobase)
1019                         {
1020                                 GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
1021                                 GL_DepthMask(false);
1022                                 GL_Color(r_lightmapintensity * ent->colormod[0], r_lightmapintensity * ent->colormod[1], r_lightmapintensity * ent->colormod[2], 1);
1023                                 memset(&m, 0, sizeof(m));
1024                                 m.tex[0] = R_GetTexture(texture->skin.base);
1025                                 if (waterscrolling)
1026                                         m.texmatrix[0] = r_surf_waterscrollmatrix;
1027                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1028                                 {
1029                                         surface = texturesurfacelist[texturesurfaceindex];
1030                                         m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
1031                                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
1032                                         R_Mesh_State(&m);
1033                                         GL_LockArrays(0, surface->mesh.num_vertices);
1034                                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1035                                         GL_LockArrays(0, 0);
1036                                 }
1037                         }
1038                 }
1039                 if (doambient)
1040                 {
1041                         doambient = false;
1042                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1043                         GL_DepthMask(false);
1044                         memset(&m, 0, sizeof(m));
1045                         m.tex[0] = R_GetTexture(texture->skin.base);
1046                         if (waterscrolling)
1047                                 m.texmatrix[0] = r_surf_waterscrollmatrix;
1048                         m.pointer_color = varray_color4f;
1049                         colorscale = 1;
1050                         if (gl_combine.integer)
1051                         {
1052                                 m.texrgbscale[0] = 4;
1053                                 colorscale *= 0.25f;
1054                         }
1055                         base = r_ambient.value * (1.0f / 64.0f);
1056                         r = ent->colormod[0] * colorscale * base;
1057                         g = ent->colormod[1] * colorscale * base;
1058                         b = ent->colormod[2] * colorscale * base;
1059                         a = texture->currentalpha;
1060                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1061                         {
1062                                 surface = texturesurfacelist[texturesurfaceindex];
1063                                 m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
1064                                 m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
1065                                 for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
1066                                 {
1067                                         c[0] = r;
1068                                         c[1] = g;
1069                                         c[2] = b;
1070                                         if (fogallpasses)
1071                                         {
1072                                                 VectorSubtract(v, modelorg, diff);
1073                                                 f = 1 - exp(fogdensity/DotProduct(diff, diff));
1074                                                 VectorScale(c, f, c);
1075                                         }
1076                                         if (surface->mesh.data_lightmapcolor4f && (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
1077                                                 c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a;
1078                                         else
1079                                                 c[3] = a;
1080                                 }
1081                                 R_Mesh_State(&m);
1082                                 GL_LockArrays(0, surface->mesh.num_vertices);
1083                                 R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1084                                 GL_LockArrays(0, 0);
1085                         }
1086                 }
1087                 if (dodetail)
1088                 {
1089                         GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
1090                         GL_DepthMask(false);
1091                         GL_Color(1, 1, 1, 1);
1092                         memset(&m, 0, sizeof(m));
1093                         m.tex[0] = R_GetTexture(texture->skin.detail);
1094                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1095                         {
1096                                 surface = texturesurfacelist[texturesurfaceindex];
1097                                 m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
1098                                 m.pointer_texcoord[0] = surface->mesh.data_texcoorddetail2f;
1099                                 R_Mesh_State(&m);
1100                                 GL_LockArrays(0, surface->mesh.num_vertices);
1101                                 R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1102                                 GL_LockArrays(0, 0);
1103                         }
1104                 }
1105                 if (doglow)
1106                 {
1107                         // if glow was not already done using multitexture, do it now.
1108                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1109                         GL_DepthMask(false);
1110                         memset(&m, 0, sizeof(m));
1111                         m.tex[0] = R_GetTexture(texture->skin.glow);
1112                         if (waterscrolling)
1113                                 m.texmatrix[0] = r_surf_waterscrollmatrix;
1114                         m.pointer_color = varray_color4f;
1115                         colorscale = 1;
1116                         r = ent->colormod[0] * colorscale;
1117                         g = ent->colormod[1] * colorscale;
1118                         b = ent->colormod[2] * colorscale;
1119                         a = texture->currentalpha;
1120                         if (fogallpasses)
1121                         {
1122                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1123                                 {
1124                                         surface = texturesurfacelist[texturesurfaceindex];
1125                                         m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
1126                                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
1127                                         if (surface->mesh.data_lightmapcolor4f && (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
1128                                         {
1129                                                 m.pointer_color = varray_color4f;
1130                                                 for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
1131                                                 {
1132                                                         VectorSubtract(v, modelorg, diff);
1133                                                         f = 1 - exp(fogdensity/DotProduct(diff, diff));
1134                                                         c[0] = f * r;
1135                                                         c[1] = f * g;
1136                                                         c[2] = f * b;
1137                                                         c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a;
1138                                                 }
1139                                         }
1140                                         else
1141                                         {
1142                                                 m.pointer_color = varray_color4f;
1143                                                 for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
1144                                                 {
1145                                                         VectorSubtract(v, modelorg, diff);
1146                                                         f = 1 - exp(fogdensity/DotProduct(diff, diff));
1147                                                         c[0] = f * r;
1148                                                         c[1] = f * g;
1149                                                         c[2] = f * b;
1150                                                         c[3] = a;
1151                                                 }
1152                                         }
1153                                         R_Mesh_State(&m);
1154                                         GL_LockArrays(0, surface->mesh.num_vertices);
1155                                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1156                                         GL_LockArrays(0, 0);
1157                                 }
1158                         }
1159                         else
1160                         {
1161                                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1162                                 {
1163                                         surface = texturesurfacelist[texturesurfaceindex];
1164                                         m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
1165                                         m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
1166                                         if (surface->mesh.data_lightmapcolor4f && (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
1167                                         {
1168                                                 m.pointer_color = varray_color4f;
1169                                                 for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
1170                                                 {
1171                                                         c[0] = r;
1172                                                         c[1] = g;
1173                                                         c[2] = b;
1174                                                         c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * a;
1175                                                 }
1176                                         }
1177                                         else
1178                                         {
1179                                                 m.pointer_color = NULL;
1180                                                 GL_Color(r, g, b, a);
1181                                         }
1182                                         R_Mesh_State(&m);
1183                                         GL_LockArrays(0, surface->mesh.num_vertices);
1184                                         R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1185                                         GL_LockArrays(0, 0);
1186                                 }
1187                         }
1188                 }
1189                 if (dofogpass)
1190                 {
1191                         // if this is opaque use alpha blend which will darken the earlier
1192                         // passes cheaply.
1193                         //
1194                         // if this is an alpha blended material, all the earlier passes
1195                         // were darkened by fog already, so we only need to add the fog
1196                         // color ontop through the fog mask texture
1197                         //
1198                         // if this is an additive blended material, all the earlier passes
1199                         // were darkened by fog already, and we should not add fog color
1200                         // (because the background was not darkened, there is no fog color
1201                         // that was lost behind it).
1202                         if (!fogallpasses)
1203                                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1204                         else
1205                                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1206                         GL_DepthMask(false);
1207                         memset(&m, 0, sizeof(m));
1208                         m.tex[0] = R_GetTexture(texture->skin.fog);
1209                         if (waterscrolling)
1210                                 m.texmatrix[0] = r_surf_waterscrollmatrix;
1211                         r = fogcolor[0];
1212                         g = fogcolor[1];
1213                         b = fogcolor[2];
1214                         a = texture->currentalpha;
1215                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1216                         {
1217                                 surface = texturesurfacelist[texturesurfaceindex];
1218                                 m.pointer_vertex = RSurf_GetVertexPointer(ent, surface);
1219                                 m.pointer_texcoord[0] = surface->mesh.data_texcoordtexture2f;
1220                                 m.pointer_color = varray_color4f;
1221                                 //RSurf_FogPassColors_Vertex3f_Color4f(surface->mesh.data_vertex3f, varray_color4f, fogcolor[0], fogcolor[1], fogcolor[2], texture->currentalpha, 1, surface->mesh.num_vertices, modelorg);
1222                                 if (surface->mesh.data_lightmapcolor4f && (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
1223                                 {
1224                                         m.pointer_color = varray_color4f;
1225                                         for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
1226                                         {
1227                                                 VectorSubtract(v, modelorg, diff);
1228                                                 f = exp(fogdensity/DotProduct(diff, diff));
1229                                                 c[0] = r;
1230                                                 c[1] = g;
1231                                                 c[2] = b;
1232                                                 c[3] = surface->mesh.data_lightmapcolor4f[i*4+3] * f * a;
1233                                         }
1234                                 }
1235                                 else
1236                                 {
1237                                         m.pointer_color = varray_color4f;
1238                                         for (i = 0, v = m.pointer_vertex, c = varray_color4f;i < surface->mesh.num_vertices;i++, v += 3, c += 4)
1239                                         {
1240                                                 VectorSubtract(v, modelorg, diff);
1241                                                 f = exp(fogdensity/DotProduct(diff, diff));
1242                                                 c[0] = r;
1243                                                 c[1] = g;
1244                                                 c[2] = b;
1245                                                 c[3] = f * a;
1246                                         }
1247                                 }
1248                                 R_Mesh_State(&m);
1249                                 GL_LockArrays(0, surface->mesh.num_vertices);
1250                                 R_Mesh_Draw(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i);
1251                                 GL_LockArrays(0, 0);
1252                         }
1253                 }
1254         }
1255         if (texture->textureflags & Q3TEXTUREFLAG_TWOSIDED)
1256                 qglEnable(GL_CULL_FACE);
1257 }
1258
1259 static void RSurfShader_Transparent_Callback(const void *calldata1, int calldata2)
1260 {
1261         const entity_render_t *ent = calldata1;
1262         const msurface_t *surface = ent->model->brush.data_surfaces + calldata2;
1263         vec3_t modelorg;
1264         texture_t *texture;
1265
1266         texture = surface->texture;
1267         if (texture->basematerialflags & MATERIALFLAG_SKY)
1268                 return; // transparent sky is too difficult
1269         R_UpdateTextureInfo(ent, texture);
1270
1271         R_Mesh_Matrix(&ent->matrix);
1272         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg);
1273         R_DrawSurfaceList(ent, texture, 1, &surface, modelorg);
1274 }
1275
1276 void R_QueueSurfaceList(entity_render_t *ent, texture_t *texture, int texturenumsurfaces, const msurface_t **texturesurfacelist, const vec3_t modelorg)
1277 {
1278         int texturesurfaceindex;
1279         const msurface_t *surface;
1280         vec3_t tempcenter, center;
1281         if (texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT)
1282         {
1283                 // drawing sky transparently would be too difficult
1284                 if (!(texture->currentmaterialflags & MATERIALFLAG_SKY))
1285                 {
1286                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
1287                         {
1288                                 surface = texturesurfacelist[texturesurfaceindex];
1289                                 tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
1290                                 tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
1291                                 tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
1292                                 Matrix4x4_Transform(&ent->matrix, tempcenter, center);
1293                                 R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_vieworigin : center, RSurfShader_Transparent_Callback, ent, surface - ent->model->brush.data_surfaces);
1294                         }
1295                 }
1296         }
1297         else
1298                 R_DrawSurfaceList(ent, texture, texturenumsurfaces, texturesurfacelist, modelorg);
1299 }
1300
1301 void R_DrawSurfaces(entity_render_t *ent, qboolean skysurfaces)
1302 {
1303         int i, j, f, flagsmask;
1304         msurface_t *surface, **surfacechain;
1305         texture_t *t, *texture;
1306         model_t *model = ent->model;
1307         vec3_t modelorg;
1308         const int maxsurfacelist = 1024;
1309         int numsurfacelist = 0;
1310         const msurface_t *surfacelist[1024];
1311         if (model == NULL)
1312                 return;
1313         R_Mesh_Matrix(&ent->matrix);
1314         Matrix4x4_Transform(&ent->inversematrix, r_vieworigin, modelorg);
1315
1316         // update light styles
1317         if (!skysurfaces)
1318         {
1319                 for (i = 0;i < model->brushq1.light_styles;i++)
1320                 {
1321                         if (model->brushq1.light_stylevalue[i] != d_lightstylevalue[model->brushq1.light_style[i]])
1322                         {
1323                                 model->brushq1.light_stylevalue[i] = d_lightstylevalue[model->brushq1.light_style[i]];
1324                                 if ((surfacechain = model->brushq1.light_styleupdatechains[i]))
1325                                         for (;(surface = *surfacechain);surfacechain++)
1326                                                 surface->cached_dlight = true;
1327                         }
1328                 }
1329         }
1330
1331         R_UpdateAllTextureInfo(ent);
1332         flagsmask = skysurfaces ? MATERIALFLAG_SKY : (MATERIALFLAG_WATER | MATERIALFLAG_WALL);
1333         f = 0;
1334         t = NULL;
1335         texture = NULL;
1336         numsurfacelist = 0;
1337         for (i = 0, j = model->firstmodelsurface;i < model->nummodelsurfaces;i++, j++)
1338         {
1339                 if (ent != r_refdef.worldentity || r_worldsurfacevisible[j])
1340                 {
1341                         surface = model->brush.data_surfaces + j;
1342                         if (t != surface->texture)
1343                         {
1344                                 if (numsurfacelist)
1345                                 {
1346                                         R_QueueSurfaceList(ent, texture, numsurfacelist, surfacelist, modelorg);
1347                                         numsurfacelist = 0;
1348                                 }
1349                                 t = surface->texture;
1350                                 f = t->currentmaterialflags & flagsmask;
1351                                 texture = t->currentframe;
1352                         }
1353                         if (f)
1354                         {
1355                                 // if lightmap parameters changed, rebuild lightmap texture
1356                                 if (surface->cached_dlight && surface->samples)
1357                                         R_BuildLightMap(ent, surface);
1358                                 // add face to draw list
1359                                 surfacelist[numsurfacelist++] = surface;
1360                                 if (numsurfacelist >= maxsurfacelist)
1361                                 {
1362                                         R_QueueSurfaceList(ent, texture, numsurfacelist, surfacelist, modelorg);
1363                                         numsurfacelist = 0;
1364                                 }
1365                         }
1366                 }
1367         }
1368         if (numsurfacelist)
1369                 R_QueueSurfaceList(ent, texture, numsurfacelist, surfacelist, modelorg);
1370 }
1371
1372 static void R_DrawPortal_Callback(const void *calldata1, int calldata2)
1373 {
1374         int i;
1375         float *v;
1376         rmeshstate_t m;
1377         const mportal_t *portal = calldata1;
1378         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1379         GL_DepthMask(false);
1380         GL_DepthTest(true);
1381         R_Mesh_Matrix(&r_identitymatrix);
1382
1383         memset(&m, 0, sizeof(m));
1384         m.pointer_vertex = varray_vertex3f;
1385         R_Mesh_State(&m);
1386
1387         i = calldata2;
1388         GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f),
1389                          ((i & 0x0038) >> 3) * (1.0f / 7.0f),
1390                          ((i & 0x01C0) >> 6) * (1.0f / 7.0f),
1391                          0.125f);
1392         if (PlaneDiff(r_vieworigin, (&portal->plane)) < 0)
1393         {
1394                 for (i = portal->numpoints - 1, v = varray_vertex3f;i >= 0;i--, v += 3)
1395                         VectorCopy(portal->points[i].position, v);
1396         }
1397         else
1398                 for (i = 0, v = varray_vertex3f;i < portal->numpoints;i++, v += 3)
1399                         VectorCopy(portal->points[i].position, v);
1400         GL_LockArrays(0, portal->numpoints);
1401         R_Mesh_Draw(portal->numpoints, portal->numpoints - 2, polygonelements);
1402         GL_LockArrays(0, 0);
1403 }
1404
1405 // LordHavoc: this is just a nice debugging tool, very slow
1406 static void R_DrawPortals(void)
1407 {
1408         int i, portalnum;
1409         mportal_t *portal;
1410         float center[3], f;
1411         model_t *model = r_refdef.worldmodel;
1412         if (model == NULL)
1413                 return;
1414         for (portalnum = 0, portal = model->brush.data_portals;portalnum < model->brush.num_portals;portalnum++, portal++)
1415         {
1416                 if (portal->numpoints <= POLYGONELEMENTS_MAXPOINTS)
1417                 if (!R_CullBox(portal->mins, portal->maxs))
1418                 {
1419                         VectorClear(center);
1420                         for (i = 0;i < portal->numpoints;i++)
1421                                 VectorAdd(center, portal->points[i].position, center);
1422                         f = ixtable[portal->numpoints];
1423                         VectorScale(center, f, center);
1424                         R_MeshQueue_AddTransparent(center, R_DrawPortal_Callback, portal, portalnum);
1425                 }
1426         }
1427 }
1428
1429 static void R_DrawCollisionBrush(colbrushf_t *brush)
1430 {
1431         int i;
1432         rmeshstate_t m;
1433         memset(&m, 0, sizeof(m));
1434         m.pointer_vertex = brush->points->v;
1435         R_Mesh_State(&m);
1436         i = (int)(((size_t)brush) / sizeof(colbrushf_t));
1437         GL_Color((i & 31) * (1.0f / 32.0f), ((i >> 5) & 31) * (1.0f / 32.0f), ((i >> 10) & 31) * (1.0f / 32.0f), 0.2f);
1438         GL_LockArrays(0, brush->numpoints);
1439         R_Mesh_Draw(brush->numpoints, brush->numtriangles, brush->elements);
1440         GL_LockArrays(0, 0);
1441 }
1442
1443 static void R_DrawCollisionSurface(entity_render_t *ent, msurface_t *surface)
1444 {
1445         int i;
1446         rmeshstate_t m;
1447         if (!surface->mesh.num_collisiontriangles)
1448                 return;
1449         memset(&m, 0, sizeof(m));
1450         m.pointer_vertex = surface->mesh.data_collisionvertex3f;
1451         R_Mesh_State(&m);
1452         i = (int)(((size_t)surface) / sizeof(msurface_t));
1453         GL_Color((i & 31) * (1.0f / 32.0f), ((i >> 5) & 31) * (1.0f / 32.0f), ((i >> 10) & 31) * (1.0f / 32.0f), 0.2f);
1454         GL_LockArrays(0, surface->mesh.num_collisionvertices);
1455         R_Mesh_Draw(surface->mesh.num_collisionvertices, surface->mesh.num_collisiontriangles, surface->mesh.data_collisionelement3i);
1456         GL_LockArrays(0, 0);
1457 }
1458
1459 void R_WorldVisibility(void)
1460 {
1461         int i, j, *mark;
1462         mleaf_t *leaf;
1463         mleaf_t *viewleaf;
1464         model_t *model = r_refdef.worldmodel;
1465
1466         if (!model)
1467                 return;
1468
1469         // if possible find the leaf the view origin is in
1470         viewleaf = model->brushq1.PointInLeaf ? model->brushq1.PointInLeaf(model, r_vieworigin) : NULL;
1471         // if possible fetch the visible cluster bits
1472         if (model->brush.FatPVS)
1473                 model->brush.FatPVS(model, r_vieworigin, 2, r_pvsbits, sizeof(r_pvsbits));
1474
1475         // clear the visible surface and leaf flags arrays
1476         memset(r_worldsurfacevisible, 0, model->brush.num_surfaces);
1477         memset(r_worldleafvisible, 0, model->brush.num_leafs);
1478
1479         // if the user prefers surfaceworldnode (testing?) or the viewleaf could
1480         // not be found, or the viewleaf is not part of the visible world
1481         // (floating around in the void), use the pvs method
1482         if (r_surfaceworldnode.integer || !viewleaf || viewleaf->clusterindex < 0)
1483         {
1484                 // pvs method:
1485                 // similar to quake's RecursiveWorldNode but without cache misses
1486                 for (j = 0, leaf = model->brush.data_leafs;j < model->brush.num_leafs;j++, leaf++)
1487                 {
1488                         // if leaf is in current pvs and on the screen, mark its surfaces
1489                         if (CHECKPVSBIT(r_pvsbits, leaf->clusterindex) && !R_CullBox(leaf->mins, leaf->maxs))
1490                         {
1491                                 c_leafs++;
1492                                 r_worldleafvisible[j] = true;
1493                                 if (leaf->numleafsurfaces)
1494                                         for (i = 0, mark = leaf->firstleafsurface;i < leaf->numleafsurfaces;i++, mark++)
1495                                                 r_worldsurfacevisible[*mark] = true;
1496                         }
1497                 }
1498         }
1499         else
1500         {
1501                 int leafstackpos;
1502                 mportal_t *p;
1503                 mleaf_t *leafstack[8192];
1504                 // portal method:
1505                 // follows portals leading outward from viewleaf, does not venture
1506                 // offscreen or into leafs that are not visible, faster than Quake's
1507                 // RecursiveWorldNode and vastly better in unvised maps, often culls a
1508                 // lot of surface that pvs alone would miss
1509                 leafstack[0] = viewleaf;
1510                 leafstackpos = 1;
1511                 while (leafstackpos)
1512                 {
1513                         c_leafs++;
1514                         leaf = leafstack[--leafstackpos];
1515                         r_worldleafvisible[leaf - model->brush.data_leafs] = true;
1516                         // mark any surfaces bounding this leaf
1517                         if (leaf->numleafsurfaces)
1518                                 for (i = 0, mark = leaf->firstleafsurface;i < leaf->numleafsurfaces;i++, mark++)
1519                                         r_worldsurfacevisible[*mark] = true;
1520                         // follow portals into other leafs
1521                         // the checks are:
1522                         // if viewer is behind portal (portal faces outward into the scene)
1523                         // and the portal polygon's bounding box is on the screen
1524                         // and the leaf has not been visited yet
1525                         // and the leaf is visible in the pvs
1526                         // (the first two checks won't cause as many cache misses as the leaf checks)
1527                         for (p = leaf->portals;p;p = p->next)
1528                                 if (DotProduct(r_vieworigin, p->plane.normal) < (p->plane.dist + 1) && !R_CullBox(p->mins, p->maxs) && !r_worldleafvisible[p->past - model->brush.data_leafs] && CHECKPVSBIT(r_pvsbits, p->past->clusterindex))
1529                                         leafstack[leafstackpos++] = p->past;
1530                 }
1531         }
1532
1533         if (r_drawportals.integer)
1534                 R_DrawPortals();
1535 }
1536
1537 void R_Q1BSP_DrawSky(entity_render_t *ent)
1538 {
1539         if (ent->model == NULL)
1540                 return;
1541         if (r_drawcollisionbrushes.integer < 2)
1542                 R_DrawSurfaces(ent, true);
1543 }
1544
1545 void R_Q1BSP_Draw(entity_render_t *ent)
1546 {
1547         if (ent->model == NULL)
1548                 return;
1549         c_bmodels++;
1550         if (r_drawcollisionbrushes.integer < 2)
1551                 R_DrawSurfaces(ent, false);
1552         if (r_drawcollisionbrushes.integer >= 1 && ent->model->brush.num_brushes)
1553         {
1554                 int i;
1555                 model_t *model = ent->model;
1556                 msurface_t *surface;
1557                 q3mbrush_t *brush;
1558                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1559                 GL_DepthMask(false);
1560                 GL_DepthTest(true);
1561                 qglPolygonOffset(r_drawcollisionbrushes_polygonfactor.value, r_drawcollisionbrushes_polygonoffset.value);
1562                 for (i = 0, brush = model->brush.data_brushes + model->firstmodelbrush;i < model->nummodelbrushes;i++, brush++)
1563                         if (brush->colbrushf && brush->colbrushf->numtriangles)
1564                                 R_DrawCollisionBrush(brush->colbrushf);
1565                 for (i = 0, surface = model->brush.data_surfaces + model->firstmodelsurface;i < model->nummodelsurfaces;i++, surface++)
1566                         if (surface->mesh.num_collisiontriangles)
1567                                 R_DrawCollisionSurface(ent, surface);
1568                 qglPolygonOffset(0, 0);
1569         }
1570 }
1571
1572 void R_Q1BSP_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outclusterlist, qbyte *outclusterpvs, int *outnumclusterspointer, int *outsurfacelist, qbyte *outsurfacepvs, int *outnumsurfacespointer)
1573 {
1574         model_t *model = ent->model;
1575         vec3_t lightmins, lightmaxs;
1576         int t, leafindex, leafsurfaceindex, surfaceindex, triangleindex, outnumclusters = 0, outnumsurfaces = 0;
1577         const int *e;
1578         const float *v[3];
1579         msurface_t *surface;
1580         mleaf_t *leaf;
1581         const qbyte *pvs;
1582         lightmins[0] = relativelightorigin[0] - lightradius;
1583         lightmins[1] = relativelightorigin[1] - lightradius;
1584         lightmins[2] = relativelightorigin[2] - lightradius;
1585         lightmaxs[0] = relativelightorigin[0] + lightradius;
1586         lightmaxs[1] = relativelightorigin[1] + lightradius;
1587         lightmaxs[2] = relativelightorigin[2] + lightradius;
1588         *outnumclusterspointer = 0;
1589         *outnumsurfacespointer = 0;
1590         memset(outclusterpvs, 0, model->brush.num_pvsclusterbytes);
1591         memset(outsurfacepvs, 0, (model->nummodelsurfaces + 7) >> 3);
1592         if (model == NULL)
1593         {
1594                 VectorCopy(lightmins, outmins);
1595                 VectorCopy(lightmaxs, outmaxs);
1596                 return;
1597         }
1598         VectorCopy(relativelightorigin, outmins);
1599         VectorCopy(relativelightorigin, outmaxs);
1600         if (model->brush.GetPVS)
1601                 pvs = model->brush.GetPVS(model, relativelightorigin);
1602         else
1603                 pvs = NULL;
1604         R_UpdateAllTextureInfo(ent);
1605         // FIXME: use BSP recursion as lights are often small
1606         for (leafindex = 0, leaf = model->brush.data_leafs;leafindex < model->brush.num_leafs;leafindex++, leaf++)
1607         {
1608                 if (BoxesOverlap(lightmins, lightmaxs, leaf->mins, leaf->maxs) && (pvs == NULL || CHECKPVSBIT(pvs, leaf->clusterindex)))
1609                 {
1610                         outmins[0] = min(outmins[0], leaf->mins[0]);
1611                         outmins[1] = min(outmins[1], leaf->mins[1]);
1612                         outmins[2] = min(outmins[2], leaf->mins[2]);
1613                         outmaxs[0] = max(outmaxs[0], leaf->maxs[0]);
1614                         outmaxs[1] = max(outmaxs[1], leaf->maxs[1]);
1615                         outmaxs[2] = max(outmaxs[2], leaf->maxs[2]);
1616                         if (outclusterpvs)
1617                         {
1618                                 if (!CHECKPVSBIT(outclusterpvs, leaf->clusterindex))
1619                                 {
1620                                         SETPVSBIT(outclusterpvs, leaf->clusterindex);
1621                                         outclusterlist[outnumclusters++] = leaf->clusterindex;
1622                                 }
1623                         }
1624                         if (outsurfacepvs)
1625                         {
1626                                 for (leafsurfaceindex = 0;leafsurfaceindex < leaf->numleafsurfaces;leafsurfaceindex++)
1627                                 {
1628                                         surfaceindex = leaf->firstleafsurface[leafsurfaceindex];
1629                                         if (!CHECKPVSBIT(outsurfacepvs, surfaceindex))
1630                                         {
1631                                                 surface = model->brush.data_surfaces + surfaceindex;
1632                                                 if (BoxesOverlap(lightmins, lightmaxs, surface->mins, surface->maxs))
1633                                                 if ((surface->texture->currentmaterialflags & (MATERIALFLAG_WALL | MATERIALFLAG_NODRAW | MATERIALFLAG_TRANSPARENT)) == MATERIALFLAG_WALL)
1634                                                 {
1635                                                         for (triangleindex = 0, t = surface->num_firstshadowmeshtriangle, e = model->brush.shadowmesh->element3i + t * 3;triangleindex < surface->mesh.num_triangles;triangleindex++, t++, e += 3)
1636                                                         {
1637                                                                 v[0] = model->brush.shadowmesh->vertex3f + e[0] * 3;
1638                                                                 v[1] = model->brush.shadowmesh->vertex3f + e[1] * 3;
1639                                                                 v[2] = model->brush.shadowmesh->vertex3f + e[2] * 3;
1640                                                                 if (lightmaxs[0] > min(v[0][0], min(v[1][0], v[2][0])) && lightmins[0] < max(v[0][0], max(v[1][0], v[2][0])) && lightmaxs[1] > min(v[0][1], min(v[1][1], v[2][1])) && lightmins[1] < max(v[0][1], max(v[1][1], v[2][1])) && lightmaxs[2] > min(v[0][2], min(v[1][2], v[2][2])) && lightmins[2] < max(v[0][2], max(v[1][2], v[2][2])))
1641                                                                 {
1642                                                                         SETPVSBIT(outsurfacepvs, surfaceindex);
1643                                                                         outsurfacelist[outnumsurfaces++] = surfaceindex;
1644                                                                         break;
1645                                                                 }
1646                                                         }
1647                                                 }
1648                                         }
1649                                 }
1650                         }
1651                 }
1652         }
1653
1654         // limit combined leaf box to light boundaries
1655         outmins[0] = max(outmins[0], lightmins[0]);
1656         outmins[1] = max(outmins[1], lightmins[1]);
1657         outmins[2] = max(outmins[2], lightmins[2]);
1658         outmaxs[0] = min(outmaxs[0], lightmaxs[0]);
1659         outmaxs[1] = min(outmaxs[1], lightmaxs[1]);
1660         outmaxs[2] = min(outmaxs[2], lightmaxs[2]);
1661
1662         *outnumclusterspointer = outnumclusters;
1663         *outnumsurfacespointer = outnumsurfaces;
1664 }
1665
1666 void R_Q1BSP_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int numsurfaces, const int *surfacelist, const vec3_t lightmins, const vec3_t lightmaxs)
1667 {
1668         model_t *model = ent->model;
1669         msurface_t *surface;
1670         int surfacelistindex;
1671         if (r_drawcollisionbrushes.integer < 2)
1672         {
1673                 R_Mesh_Matrix(&ent->matrix);
1674                 R_Shadow_PrepareShadowMark(model->brush.shadowmesh->numtriangles);
1675                 if (!r_shadow_compilingrtlight)
1676                         R_UpdateAllTextureInfo(ent);
1677                 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1678                 {
1679                         surface = model->brush.data_surfaces + surfacelist[surfacelistindex];
1680                         if ((surface->texture->currentmaterialflags & (MATERIALFLAG_NODRAW | MATERIALFLAG_TRANSPARENT | MATERIALFLAG_WALL)) != MATERIALFLAG_WALL)
1681                                 continue;
1682                         if (surface->texture->textureflags & Q3TEXTUREFLAG_TWOSIDED)
1683                                 continue;
1684                         R_Shadow_MarkVolumeFromBox(surface->num_firstshadowmeshtriangle, surface->mesh.num_triangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, relativelightorigin, lightmins, lightmaxs, surface->mins, surface->maxs);
1685                 }
1686                 R_Shadow_VolumeFromList(model->brush.shadowmesh->numverts, model->brush.shadowmesh->numtriangles, model->brush.shadowmesh->vertex3f, model->brush.shadowmesh->element3i, model->brush.shadowmesh->neighbor3i, relativelightorigin, lightradius + model->radius + r_shadow_projectdistance.value, numshadowmark, shadowmarklist);
1687         }
1688 }
1689
1690 void R_Q1BSP_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltolight, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz, rtexture_t *lightcubemap, vec_t ambientscale, vec_t diffusescale, vec_t specularscale, int numsurfaces, const int *surfacelist)
1691 {
1692         model_t *model = ent->model;
1693         msurface_t *surface;
1694         texture_t *t;
1695         int surfacelistindex;
1696         if (r_drawcollisionbrushes.integer < 2)
1697         {
1698                 R_Mesh_Matrix(&ent->matrix);
1699                 if (!r_shadow_compilingrtlight)
1700                         R_UpdateAllTextureInfo(ent);
1701                 for (surfacelistindex = 0;surfacelistindex < numsurfaces;surfacelistindex++)
1702                 {
1703                         surface = model->brush.data_surfaces + surfacelist[surfacelistindex];
1704                         if (surface->texture->basematerialflags & MATERIALFLAG_NODRAW || !surface->mesh.num_triangles)
1705                                 continue;
1706                         if (r_shadow_compilingrtlight)
1707                         {
1708                                 // if compiling an rtlight, capture the mesh
1709                                 t = surface->texture;
1710                                 if ((t->basematerialflags & (MATERIALFLAG_WALL | MATERIALFLAG_TRANSPARENT)) == MATERIALFLAG_WALL)
1711                                         Mod_ShadowMesh_AddMesh(r_shadow_mempool, r_shadow_compilingrtlight->static_meshchain_light, surface->texture->skin.base, surface->texture->skin.gloss, surface->texture->skin.nmap, surface->mesh.data_vertex3f, surface->mesh.data_svector3f, surface->mesh.data_tvector3f, surface->mesh.data_normal3f, surface->mesh.data_texcoordtexture2f, surface->mesh.num_triangles, surface->mesh.data_element3i);
1712                         }
1713                         else if (ent != r_refdef.worldentity || r_worldsurfacevisible[surfacelist[surfacelistindex]])
1714                         {
1715                                 t = surface->texture->currentframe;
1716                                 // FIXME: transparent surfaces need to be lit later
1717                                 if ((t->currentmaterialflags & (MATERIALFLAG_WALL | MATERIALFLAG_TRANSPARENT)) == MATERIALFLAG_WALL)
1718                                 {
1719                                         if (surface->texture->textureflags & Q3TEXTUREFLAG_TWOSIDED)
1720                                                 qglDisable(GL_CULL_FACE);
1721                                         R_Shadow_RenderLighting(surface->mesh.num_vertices, surface->mesh.num_triangles, surface->mesh.data_element3i, surface->mesh.data_vertex3f, surface->mesh.data_svector3f, surface->mesh.data_tvector3f, surface->mesh.data_normal3f, surface->mesh.data_texcoordtexture2f, relativelightorigin, relativeeyeorigin, lightcolor, matrix_modeltolight, matrix_modeltoattenuationxyz, matrix_modeltoattenuationz, t->skin.base, t->skin.nmap, t->skin.gloss, lightcubemap, ambientscale, diffusescale, specularscale);
1722                                         if (surface->texture->textureflags & Q3TEXTUREFLAG_TWOSIDED)
1723                                                 qglEnable(GL_CULL_FACE);
1724                                 }
1725                         }
1726                 }
1727         }
1728 }
1729
1730 #if 0
1731 static void gl_surf_start(void)
1732 {
1733 }
1734
1735 static void gl_surf_shutdown(void)
1736 {
1737 }
1738
1739 static void gl_surf_newmap(void)
1740 {
1741 }
1742 #endif
1743
1744 void GL_Surf_Init(void)
1745 {
1746
1747         Cvar_RegisterVariable(&r_ambient);
1748         Cvar_RegisterVariable(&r_drawportals);
1749         Cvar_RegisterVariable(&r_testvis);
1750         Cvar_RegisterVariable(&r_floatbuildlightmap);
1751         Cvar_RegisterVariable(&r_detailtextures);
1752         Cvar_RegisterVariable(&r_surfaceworldnode);
1753         Cvar_RegisterVariable(&r_drawcollisionbrushes_polygonfactor);
1754         Cvar_RegisterVariable(&r_drawcollisionbrushes_polygonoffset);
1755         Cvar_RegisterVariable(&r_q3bsp_renderskydepth);
1756         Cvar_RegisterVariable(&gl_lightmaps);
1757
1758         //R_RegisterModule("GL_Surf", gl_surf_start, gl_surf_shutdown, gl_surf_newmap);
1759 }
1760