]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_rmain.c
implemented .loc file support, including some editing (add command, and removenearest...
[divverent/darkplaces.git] / gl_rmain.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_main.c
21
22 #include "quakedef.h"
23 #include "r_shadow.h"
24 #include "polygon.h"
25
26 mempool_t *r_main_mempool;
27 rtexturepool_t *r_main_texturepool;
28
29 //
30 // screen size info
31 //
32 r_refdef_t r_refdef;
33 r_view_t r_view;
34 r_viewcache_t r_viewcache;
35
36 cvar_t r_nearclip = {0, "r_nearclip", "1", "distance from camera of nearclip plane" };
37 cvar_t r_showsurfaces = {0, "r_showsurfaces", "0", "1 shows surfaces as different colors, or a value of 2 shows triangle draw order (for analyzing whether meshes are optimized for vertex cache)"};
38 cvar_t r_showtris = {0, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"};
39 cvar_t r_shownormals = {0, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"};
40 cvar_t r_showlighting = {0, "r_showlighting", "0", "shows areas lit by lights, useful for finding out why some areas of a map render slowly (bright orange = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"};
41 cvar_t r_showshadowvolumes = {0, "r_showshadowvolumes", "0", "shows areas shadowed by lights, useful for finding out why some areas of a map render slowly (bright blue = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"};
42 cvar_t r_showcollisionbrushes = {0, "r_showcollisionbrushes", "0", "draws collision brushes in quake3 maps (mode 1), mode 2 disables rendering of world (trippy!)"};
43 cvar_t r_showcollisionbrushes_polygonfactor = {0, "r_showcollisionbrushes_polygonfactor", "-1", "expands outward the brush polygons a little bit, used to make collision brushes appear infront of walls"};
44 cvar_t r_showcollisionbrushes_polygonoffset = {0, "r_showcollisionbrushes_polygonoffset", "0", "nudges brush polygon depth in hardware depth units, used to make collision brushes appear infront of walls"};
45 cvar_t r_showdisabledepthtest = {0, "r_showdisabledepthtest", "0", "disables depth testing on r_show* cvars, allowing you to see what hidden geometry the graphics card is processing"};
46 cvar_t r_drawportals = {0, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"};
47 cvar_t r_drawentities = {0, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"};
48 cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1", "draw your weapon model"};
49 cvar_t r_cullentities_trace = {0, "r_cullentities_trace", "1", "probabistically cull invisible entities"};
50 cvar_t r_cullentities_trace_samples = {0, "r_cullentities_trace_samples", "2", "number of samples to test for entity culling"};
51 cvar_t r_cullentities_trace_enlarge = {0, "r_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
52 cvar_t r_cullentities_trace_delay = {0, "r_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
53 cvar_t r_speeds = {0, "r_speeds","0", "displays rendering statistics and per-subsystem timings"};
54 cvar_t r_fullbright = {0, "r_fullbright","0", "make everything bright cheat (not allowed in multiplayer)"};
55 cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1", "opacity of water polygons"};
56 cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1", "enables dynamic lights (rocket glow and such)"};
57 cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1", "enables glowing pixels in quake textures (changes need r_restart to take effect)"};
58 cvar_t r_shadows = {CVAR_SAVE, "r_shadows", "0", "casts fake stencil shadows from models onto the world (rtlights are unaffected by this)"};
59 cvar_t r_shadows_throwdistance = {CVAR_SAVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"};
60 cvar_t r_q1bsp_skymasking = {0, "r_qb1sp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
61
62 cvar_t gl_fogenable = {0, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"};
63 cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"};
64 cvar_t gl_fogred = {0, "gl_fogred","0.3", "nehahra fog color red value (for Nehahra compatibility only)"};
65 cvar_t gl_foggreen = {0, "gl_foggreen","0.3", "nehahra fog color green value (for Nehahra compatibility only)"};
66 cvar_t gl_fogblue = {0, "gl_fogblue","0.3", "nehahra fog color blue value (for Nehahra compatibility only)"};
67 cvar_t gl_fogstart = {0, "gl_fogstart", "0", "nehahra fog start distance (for Nehahra compatibility only)"};
68 cvar_t gl_fogend = {0, "gl_fogend","0", "nehahra fog end distance (for Nehahra compatibility only)"};
69
70 cvar_t r_textureunits = {0, "r_textureunits", "32", "number of hardware texture units reported by driver (note: setting this to 1 turns off gl_combine)"};
71
72 cvar_t r_glsl = {0, "r_glsl", "1", "enables use of OpenGL 2.0 pixel shaders for lighting"};
73 cvar_t r_glsl_offsetmapping = {0, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
74 cvar_t r_glsl_offsetmapping_reliefmapping = {0, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
75 cvar_t r_glsl_offsetmapping_scale = {0, "r_glsl_offsetmapping_scale", "0.04", "how deep the offset mapping effect is"};
76 cvar_t r_glsl_deluxemapping = {0, "r_glsl_deluxemapping", "1", "use per pixel lighting on deluxemap-compiled q3bsp maps (or a value of 2 forces deluxemap shading even without deluxemaps)"};
77
78 cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "1", "enables animation smoothing on sprites (requires r_lerpmodels 1)"};
79 cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
80 cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
81
82 cvar_t r_bloom = {CVAR_SAVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"};
83 cvar_t r_bloom_colorscale = {CVAR_SAVE, "r_bloom_colorscale", "1", "how bright the glow is"};
84 cvar_t r_bloom_brighten = {CVAR_SAVE, "r_bloom_brighten", "2", "how bright the glow is, after subtract/power"};
85 cvar_t r_bloom_blur = {CVAR_SAVE, "r_bloom_blur", "4", "how large the glow is"};
86 cvar_t r_bloom_resolution = {CVAR_SAVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"};
87 cvar_t r_bloom_colorexponent = {CVAR_SAVE, "r_bloom_colorexponent", "1", "how exagerated the glow is"};
88 cvar_t r_bloom_colorsubtract = {CVAR_SAVE, "r_bloom_colorsubtract", "0.125", "reduces bloom colors by a certain amount"};
89
90 cvar_t r_hdr = {CVAR_SAVE, "r_hdr", "0", "enables High Dynamic Range bloom effect (higher quality version of r_bloom)"};
91 cvar_t r_hdr_scenebrightness = {CVAR_SAVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
92 cvar_t r_hdr_glowintensity = {CVAR_SAVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
93 cvar_t r_hdr_range = {CVAR_SAVE, "r_hdr_range", "4", "how much dynamic range to render bloom with (equivilant to multiplying r_bloom_brighten by this value and dividing r_bloom_colorscale by this value)"};
94
95 cvar_t r_smoothnormals_areaweighting = {0, "r_smoothnormals_areaweighting", "1", "uses significantly faster (and supposedly higher quality) area-weighted vertex normals and tangent vectors rather than summing normalized triangle normals and tangents"};
96
97 cvar_t developer_texturelogging = {0, "developer_texturelogging", "0", "produces a textures.log file containing names of skins and map textures the engine tried to load"};
98
99 cvar_t gl_lightmaps = {0, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers)"};
100
101 cvar_t r_test = {0, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"}; // used for testing renderer code changes, otherwise does nothing
102 cvar_t r_batchmode = {0, "r_batchmode", "1", "selects method of rendering multiple surfaces with one driver call (values are 0, 1, 2, etc...)"};
103
104 typedef struct r_glsl_bloomshader_s
105 {
106         int program;
107         int loc_Texture_Bloom;
108 }
109 r_glsl_bloomshader_t;
110
111 static struct r_bloomstate_s
112 {
113         qboolean enabled;
114         qboolean hdr;
115
116         int bloomwidth, bloomheight;
117
118         int screentexturewidth, screentextureheight;
119         rtexture_t *texture_screen;
120
121         int bloomtexturewidth, bloomtextureheight;
122         rtexture_t *texture_bloom;
123
124         r_glsl_bloomshader_t *shader;
125
126         // arrays for rendering the screen passes
127         float screentexcoord2f[8];
128         float bloomtexcoord2f[8];
129         float offsettexcoord2f[8];
130 }
131 r_bloomstate;
132
133 // shadow volume bsp struct with automatically growing nodes buffer
134 svbsp_t r_svbsp;
135
136 rtexture_t *r_texture_blanknormalmap;
137 rtexture_t *r_texture_white;
138 rtexture_t *r_texture_black;
139 rtexture_t *r_texture_notexture;
140 rtexture_t *r_texture_whitecube;
141 rtexture_t *r_texture_normalizationcube;
142 rtexture_t *r_texture_fogattenuation;
143 //rtexture_t *r_texture_fogintensity;
144
145 // information about each possible shader permutation
146 r_glsl_permutation_t r_glsl_permutations[SHADERPERMUTATION_COUNT];
147 // currently selected permutation
148 r_glsl_permutation_t *r_glsl_permutation;
149
150 // temporary variable used by a macro
151 int fogtableindex;
152
153 // vertex coordinates for a quad that covers the screen exactly
154 const static float r_screenvertex3f[12] =
155 {
156         0, 0, 0,
157         1, 0, 0,
158         1, 1, 0,
159         0, 1, 0
160 };
161
162 extern void R_DrawModelShadows(void);
163
164 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
165 {
166         int i;
167         for (i = 0;i < verts;i++)
168         {
169                 out[0] = in[0] * r;
170                 out[1] = in[1] * g;
171                 out[2] = in[2] * b;
172                 out[3] = in[3];
173                 in += 4;
174                 out += 4;
175         }
176 }
177
178 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
179 {
180         int i;
181         for (i = 0;i < verts;i++)
182         {
183                 out[0] = r;
184                 out[1] = g;
185                 out[2] = b;
186                 out[3] = a;
187                 out += 4;
188         }
189 }
190
191 // FIXME: move this to client?
192 void FOG_clear(void)
193 {
194         if (gamemode == GAME_NEHAHRA)
195         {
196                 Cvar_Set("gl_fogenable", "0");
197                 Cvar_Set("gl_fogdensity", "0.2");
198                 Cvar_Set("gl_fogred", "0.3");
199                 Cvar_Set("gl_foggreen", "0.3");
200                 Cvar_Set("gl_fogblue", "0.3");
201         }
202         r_refdef.fog_density = r_refdef.fog_red = r_refdef.fog_green = r_refdef.fog_blue = 0.0f;
203 }
204
205 // FIXME: move this to client?
206 void FOG_registercvars(void)
207 {
208         int x;
209         double r, alpha;
210
211         if (gamemode == GAME_NEHAHRA)
212         {
213                 Cvar_RegisterVariable (&gl_fogenable);
214                 Cvar_RegisterVariable (&gl_fogdensity);
215                 Cvar_RegisterVariable (&gl_fogred);
216                 Cvar_RegisterVariable (&gl_foggreen);
217                 Cvar_RegisterVariable (&gl_fogblue);
218                 Cvar_RegisterVariable (&gl_fogstart);
219                 Cvar_RegisterVariable (&gl_fogend);
220         }
221
222         r = (-1.0/256.0) * (FOGTABLEWIDTH * FOGTABLEWIDTH);
223         for (x = 0;x < FOGTABLEWIDTH;x++)
224         {
225                 alpha = exp(r / ((double)x*(double)x));
226                 if (x == FOGTABLEWIDTH - 1)
227                         alpha = 1;
228                 r_refdef.fogtable[x] = bound(0, alpha, 1);
229         }
230 }
231
232 static void R_BuildBlankTextures(void)
233 {
234         unsigned char data[4];
235         data[0] = 128; // normal X
236         data[1] = 128; // normal Y
237         data[2] = 255; // normal Z
238         data[3] = 128; // height
239         r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
240         data[0] = 255;
241         data[1] = 255;
242         data[2] = 255;
243         data[3] = 255;
244         r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
245         data[0] = 0;
246         data[1] = 0;
247         data[2] = 0;
248         data[3] = 255;
249         r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
250 }
251
252 static void R_BuildNoTexture(void)
253 {
254         int x, y;
255         unsigned char pix[16][16][4];
256         // this makes a light grey/dark grey checkerboard texture
257         for (y = 0;y < 16;y++)
258         {
259                 for (x = 0;x < 16;x++)
260                 {
261                         if ((y < 8) ^ (x < 8))
262                         {
263                                 pix[y][x][0] = 128;
264                                 pix[y][x][1] = 128;
265                                 pix[y][x][2] = 128;
266                                 pix[y][x][3] = 255;
267                         }
268                         else
269                         {
270                                 pix[y][x][0] = 64;
271                                 pix[y][x][1] = 64;
272                                 pix[y][x][2] = 64;
273                                 pix[y][x][3] = 255;
274                         }
275                 }
276         }
277         r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP, NULL);
278 }
279
280 static void R_BuildWhiteCube(void)
281 {
282         unsigned char data[6*1*1*4];
283         data[ 0] = 255;data[ 1] = 255;data[ 2] = 255;data[ 3] = 255;
284         data[ 4] = 255;data[ 5] = 255;data[ 6] = 255;data[ 7] = 255;
285         data[ 8] = 255;data[ 9] = 255;data[10] = 255;data[11] = 255;
286         data[12] = 255;data[13] = 255;data[14] = 255;data[15] = 255;
287         data[16] = 255;data[17] = 255;data[18] = 255;data[19] = 255;
288         data[20] = 255;data[21] = 255;data[22] = 255;data[23] = 255;
289         r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
290 }
291
292 static void R_BuildNormalizationCube(void)
293 {
294         int x, y, side;
295         vec3_t v;
296         vec_t s, t, intensity;
297 #define NORMSIZE 64
298         unsigned char data[6][NORMSIZE][NORMSIZE][4];
299         for (side = 0;side < 6;side++)
300         {
301                 for (y = 0;y < NORMSIZE;y++)
302                 {
303                         for (x = 0;x < NORMSIZE;x++)
304                         {
305                                 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
306                                 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
307                                 switch(side)
308                                 {
309                                 default:
310                                 case 0:
311                                         v[0] = 1;
312                                         v[1] = -t;
313                                         v[2] = -s;
314                                         break;
315                                 case 1:
316                                         v[0] = -1;
317                                         v[1] = -t;
318                                         v[2] = s;
319                                         break;
320                                 case 2:
321                                         v[0] = s;
322                                         v[1] = 1;
323                                         v[2] = t;
324                                         break;
325                                 case 3:
326                                         v[0] = s;
327                                         v[1] = -1;
328                                         v[2] = -t;
329                                         break;
330                                 case 4:
331                                         v[0] = s;
332                                         v[1] = -t;
333                                         v[2] = 1;
334                                         break;
335                                 case 5:
336                                         v[0] = -s;
337                                         v[1] = -t;
338                                         v[2] = -1;
339                                         break;
340                                 }
341                                 intensity = 127.0f / sqrt(DotProduct(v, v));
342                                 data[side][y][x][0] = (unsigned char)(128.0f + intensity * v[0]);
343                                 data[side][y][x][1] = (unsigned char)(128.0f + intensity * v[1]);
344                                 data[side][y][x][2] = (unsigned char)(128.0f + intensity * v[2]);
345                                 data[side][y][x][3] = 255;
346                         }
347                 }
348         }
349         r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, &data[0][0][0][0], TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
350 }
351
352 static void R_BuildFogTexture(void)
353 {
354         int x, b;
355         double r, alpha;
356 #define FOGWIDTH 64
357         unsigned char data1[FOGWIDTH][4];
358         //unsigned char data2[FOGWIDTH][4];
359         r = (-1.0/256.0) * (FOGWIDTH * FOGWIDTH);
360         for (x = 0;x < FOGWIDTH;x++)
361         {
362                 alpha = exp(r / ((double)x*(double)x));
363                 if (x == FOGWIDTH - 1)
364                         alpha = 1;
365                 b = (int)(256.0 * alpha);
366                 b = bound(0, b, 255);
367                 data1[x][0] = 255 - b;
368                 data1[x][1] = 255 - b;
369                 data1[x][2] = 255 - b;
370                 data1[x][3] = 255;
371                 //data2[x][0] = b;
372                 //data2[x][1] = b;
373                 //data2[x][2] = b;
374                 //data2[x][3] = 255;
375         }
376         r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
377         //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
378 }
379
380 static const char *builtinshaderstring =
381 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
382 "// written by Forest 'LordHavoc' Hale\n"
383 "\n"
384 "// common definitions between vertex shader and fragment shader:\n"
385 "\n"
386 "#ifdef __GLSL_CG_DATA_TYPES\n"
387 "#define myhalf half\n"
388 "#define myhvec2 hvec2\n"
389 "#define myhvec3 hvec3\n"
390 "#define myhvec4 hvec4\n"
391 "#else\n"
392 "#define myhalf float\n"
393 "#define myhvec2 vec2\n"
394 "#define myhvec3 vec3\n"
395 "#define myhvec4 vec4\n"
396 "#endif\n"
397 "\n"
398 "varying vec2 TexCoord;\n"
399 "varying vec2 TexCoordLightmap;\n"
400 "\n"
401 "varying vec3 CubeVector;\n"
402 "varying vec3 LightVector;\n"
403 "varying vec3 EyeVector;\n"
404 "#ifdef USEFOG\n"
405 "varying vec3 EyeVectorModelSpace;\n"
406 "#endif\n"
407 "\n"
408 "varying vec3 VectorS; // direction of S texcoord (sometimes crudely called tangent)\n"
409 "varying vec3 VectorT; // direction of T texcoord (sometimes crudely called binormal)\n"
410 "varying vec3 VectorR; // direction of R texcoord (surface normal)\n"
411 "\n"
412 "\n"
413 "\n"
414 "\n"
415 "// vertex shader specific:\n"
416 "#ifdef VERTEX_SHADER\n"
417 "\n"
418 "uniform vec3 LightPosition;\n"
419 "uniform vec3 EyePosition;\n"
420 "uniform vec3 LightDir;\n"
421 "\n"
422 "// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3)\n"
423 "\n"
424 "void main(void)\n"
425 "{\n"
426 "       gl_FrontColor = gl_Color;\n"
427 "       // copy the surface texcoord\n"
428 "       TexCoord = vec2(gl_TextureMatrix[0] * gl_MultiTexCoord0);\n"
429 "#if !defined(MODE_LIGHTSOURCE) && !defined(MODE_LIGHTDIRECTION)\n"
430 "       TexCoordLightmap = vec2(gl_MultiTexCoord4);\n"
431 "#endif\n"
432 "\n"
433 "#ifdef MODE_LIGHTSOURCE\n"
434 "       // transform vertex position into light attenuation/cubemap space\n"
435 "       // (-1 to +1 across the light box)\n"
436 "       CubeVector = vec3(gl_TextureMatrix[3] * gl_Vertex);\n"
437 "\n"
438 "       // transform unnormalized light direction into tangent space\n"
439 "       // (we use unnormalized to ensure that it interpolates correctly and then\n"
440 "       //  normalize it per pixel)\n"
441 "       vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n"
442 "       LightVector.x = dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
443 "       LightVector.y = dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
444 "       LightVector.z = dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n"
445 "#endif\n"
446 "\n"
447 "#ifdef MODE_LIGHTDIRECTION\n"
448 "       LightVector.x = dot(LightDir, gl_MultiTexCoord1.xyz);\n"
449 "       LightVector.y = dot(LightDir, gl_MultiTexCoord2.xyz);\n"
450 "       LightVector.z = dot(LightDir, gl_MultiTexCoord3.xyz);\n"
451 "#endif\n"
452 "\n"
453 "       // transform unnormalized eye direction into tangent space\n"
454 "#ifndef USEFOG\n"
455 "       vec3 EyeVectorModelSpace;\n"
456 "#endif\n"
457 "       EyeVectorModelSpace = EyePosition - gl_Vertex.xyz;\n"
458 "       EyeVector.x = dot(EyeVectorModelSpace, gl_MultiTexCoord1.xyz);\n"
459 "       EyeVector.y = dot(EyeVectorModelSpace, gl_MultiTexCoord2.xyz);\n"
460 "       EyeVector.z = dot(EyeVectorModelSpace, gl_MultiTexCoord3.xyz);\n"
461 "\n"
462 "#ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
463 "       VectorS = gl_MultiTexCoord1.xyz;\n"
464 "       VectorT = gl_MultiTexCoord2.xyz;\n"
465 "       VectorR = gl_MultiTexCoord3.xyz;\n"
466 "#endif\n"
467 "\n"
468 "       // transform vertex to camera space, using ftransform to match non-VS\n"
469 "       // rendering\n"
470 "       gl_Position = ftransform();\n"
471 "}\n"
472 "\n"
473 "#endif // VERTEX_SHADER\n"
474 "\n"
475 "\n"
476 "\n"
477 "\n"
478 "// fragment shader specific:\n"
479 "#ifdef FRAGMENT_SHADER\n"
480 "\n"
481 "uniform sampler2D Texture_Normal;\n"
482 "uniform sampler2D Texture_Color;\n"
483 "uniform sampler2D Texture_Gloss;\n"
484 "uniform samplerCube Texture_Cube;\n"
485 "uniform sampler2D Texture_FogMask;\n"
486 "uniform sampler2D Texture_Pants;\n"
487 "uniform sampler2D Texture_Shirt;\n"
488 "uniform sampler2D Texture_Lightmap;\n"
489 "uniform sampler2D Texture_Deluxemap;\n"
490 "uniform sampler2D Texture_Glow;\n"
491 "\n"
492 "uniform myhvec3 LightColor;\n"
493 "uniform myhvec3 AmbientColor;\n"
494 "uniform myhvec3 DiffuseColor;\n"
495 "uniform myhvec3 SpecularColor;\n"
496 "uniform myhvec3 Color_Pants;\n"
497 "uniform myhvec3 Color_Shirt;\n"
498 "uniform myhvec3 FogColor;\n"
499 "\n"
500 "uniform myhalf GlowScale;\n"
501 "uniform myhalf SceneBrightness;\n"
502 "\n"
503 "uniform float OffsetMapping_Scale;\n"
504 "uniform float OffsetMapping_Bias;\n"
505 "uniform float FogRangeRecip;\n"
506 "\n"
507 "uniform myhalf AmbientScale;\n"
508 "uniform myhalf DiffuseScale;\n"
509 "uniform myhalf SpecularScale;\n"
510 "uniform myhalf SpecularPower;\n"
511 "\n"
512 "void main(void)\n"
513 "{\n"
514 "       // apply offsetmapping\n"
515 "#ifdef USEOFFSETMAPPING\n"
516 "       vec2 TexCoordOffset = TexCoord;\n"
517 "#define TexCoord TexCoordOffset\n"
518 "\n"
519 "       vec3 eyedir = vec3(normalize(EyeVector));\n"
520 "       float depthbias = 1.0 - eyedir.z; // should this be a -?\n"
521 "       depthbias = 1.0 - depthbias * depthbias;\n"
522 "\n"
523 "#ifdef USEOFFSETMAPPING_RELIEFMAPPING\n"
524 "       // 14 sample relief mapping: linear search and then binary search\n"
525 "       //vec3 OffsetVector = vec3(EyeVector.xy * (1.0 / EyeVector.z) * depthbias * OffsetMapping_Scale * vec2(-0.1, 0.1), -0.1);\n"
526 "       //vec3 OffsetVector = vec3(normalize(EyeVector.xy) * OffsetMapping_Scale * vec2(-0.1, 0.1), -0.1);\n"
527 "       vec3 OffsetVector = vec3(eyedir.xy * OffsetMapping_Scale * vec2(-0.1, 0.1), -0.1);\n"
528 "       vec3 RT = vec3(TexCoord - OffsetVector.xy * 10.0, 1.0) + OffsetVector;\n"
529 "       if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;\n"
530 "       if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;\n"
531 "       if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;\n"
532 "       if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;\n"
533 "       if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;\n"
534 "       if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;\n"
535 "       if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;\n"
536 "       if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;\n"
537 "       if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;OffsetVector *= 0.5;RT -= OffsetVector;\n"
538 "       if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;OffsetVector *= 0.5;RT -= OffsetVector;\n"
539 "       if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;OffsetVector *= 0.5;RT -= OffsetVector;\n"
540 "       if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;OffsetVector *= 0.5;RT -= OffsetVector;\n"
541 "       if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;OffsetVector *= 0.5;RT -= OffsetVector;\n"
542 "       if (RT.z > texture2D(Texture_Normal, RT.xy).a) RT += OffsetVector;OffsetVector *= 0.5;RT -= OffsetVector;\n"
543 "       TexCoord = RT.xy;\n"
544 "#elif 1\n"
545 "       // 3 sample offset mapping (only 3 samples because of ATI Radeon 9500-9800/X300 limits)\n"
546 "       //vec2 OffsetVector = vec2(EyeVector.xy * (1.0 / EyeVector.z) * depthbias) * OffsetMapping_Scale * vec2(-0.333, 0.333);\n"
547 "       //vec2 OffsetVector = vec2(normalize(EyeVector.xy)) * OffsetMapping_Scale * vec2(-0.333, 0.333);\n"
548 "       vec2 OffsetVector = vec2(eyedir.xy) * OffsetMapping_Scale * vec2(-0.333, 0.333);\n"
549 "       //TexCoord += OffsetVector * 3.0;\n"
550 "       TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
551 "       TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
552 "       TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
553 "#elif 0\n"
554 "       // 10 sample offset mapping\n"
555 "       //vec2 OffsetVector = vec2(EyeVector.xy * (1.0 / EyeVector.z) * depthbias) * OffsetMapping_Scale * vec2(-0.333, 0.333);\n"
556 "       //vec2 OffsetVector = vec2(normalize(EyeVector.xy)) * OffsetMapping_Scale * vec2(-0.333, 0.333);\n"
557 "       vec2 OffsetVector = vec2(eyedir.xy) * OffsetMapping_Scale * vec2(-0.1, 0.1);\n"
558 "       //TexCoord += OffsetVector * 3.0;\n"
559 "       TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
560 "       TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
561 "       TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
562 "       TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
563 "       TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
564 "       TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
565 "       TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
566 "       TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
567 "       TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
568 "       TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
569 "#elif 1\n"
570 "       // parallax mapping as described in the paper\n"
571 "       // 'Parallax Mapping with Offset Limiting: A Per-Pixel Approximation of Uneven Surfaces' by Terry Welsh\n"
572 "       // The paper provides code in the ARB fragment program assembly language\n"
573 "       // I translated it to GLSL but may have done something wrong - SavageX\n"
574 "       // LordHavoc: removed bias and simplified to one line\n"
575 "       // LordHavoc: this is just a single sample offsetmapping...\n"
576 "       TexCoordOffset += vec2(eyedir.x, -1.0 * eyedir.y) * OffsetMapping_Scale * texture2D(Texture_Normal, TexCoord).a;\n"
577 "#else\n"
578 "       // parallax mapping as described in the paper\n"
579 "       // 'Parallax Mapping with Offset Limiting: A Per-Pixel Approximation of Uneven Surfaces' by Terry Welsh\n"
580 "       // The paper provides code in the ARB fragment program assembly language\n"
581 "       // I translated it to GLSL but may have done something wrong - SavageX\n"
582 "       float height = texture2D(Texture_Normal, TexCoord).a;\n"
583 "       height = (height - 0.5) * OffsetMapping_Scale; // bias and scale\n"
584 "       TexCoordOffset += height * vec2(eyedir.x, -1.0 * eyedir.y);\n"
585 "#endif\n"
586 "#endif\n"
587 "\n"
588 "       // combine the diffuse textures (base, pants, shirt)\n"
589 "       myhvec4 color = myhvec4(texture2D(Texture_Color, TexCoord));\n"
590 "#ifdef USECOLORMAPPING\n"
591 "       color.rgb += myhvec3(texture2D(Texture_Pants, TexCoord)) * Color_Pants + myhvec3(texture2D(Texture_Shirt, TexCoord)) * Color_Shirt;\n"
592 "#endif\n"
593 "\n"
594 "\n"
595 "\n"
596 "\n"
597 "#ifdef MODE_LIGHTSOURCE\n"
598 "       // light source\n"
599 "\n"
600 "       // get the surface normal and light normal\n"
601 "       myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5));\n"
602 "       myhvec3 diffusenormal = myhvec3(normalize(LightVector));\n"
603 "\n"
604 "       // calculate directional shading\n"
605 "       color.rgb *= AmbientScale + DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0));\n"
606 "#ifdef USESPECULAR\n"
607 "       myhvec3 specularnormal = normalize(diffusenormal + myhvec3(normalize(EyeVector)));\n"
608 "       color.rgb += myhvec3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
609 "#endif\n"
610 "\n"
611 "#ifdef USECUBEFILTER\n"
612 "       // apply light cubemap filter\n"
613 "       //color.rgb *= normalize(CubeVector) * 0.5 + 0.5;//vec3(textureCube(Texture_Cube, CubeVector));\n"
614 "       color.rgb *= myhvec3(textureCube(Texture_Cube, CubeVector));\n"
615 "#endif\n"
616 "\n"
617 "       // apply light color\n"
618 "       color.rgb *= LightColor;\n"
619 "\n"
620 "       // apply attenuation\n"
621 "       //\n"
622 "       // the attenuation is (1-(x*x+y*y+z*z)) which gives a large bright\n"
623 "       // center and sharp falloff at the edge, this is about the most efficient\n"
624 "       // we can get away with as far as providing illumination.\n"
625 "       //\n"
626 "       // pow(1-(x*x+y*y+z*z), 4) is far more realistic but needs large lights to\n"
627 "       // provide significant illumination, large = slow = pain.\n"
628 "//     color.rgb *= myhalf(max(1.0 - dot(CubeVector, CubeVector), 0.0));\n"
629 "       color.rgb *= myhalf(max(2.0 - 2.0 * length(CubeVector), 0.0) / (1 + dot(CubeVector, CubeVector)));\n"
630 "\n"
631 "\n"
632 "\n"
633 "\n"
634 "#elif defined(MODE_LIGHTDIRECTION)\n"
635 "       // directional model lighting\n"
636 "\n"
637 "       // get the surface normal and light normal\n"
638 "       myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5));\n"
639 "       myhvec3 diffusenormal = myhvec3(normalize(LightVector));\n"
640 "\n"
641 "       // calculate directional shading\n"
642 "       color.rgb *= AmbientColor + DiffuseColor * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0));\n"
643 "#ifdef USESPECULAR\n"
644 "       myhvec3 specularnormal = normalize(diffusenormal + myhvec3(normalize(EyeVector)));\n"
645 "       color.rgb += myhvec3(texture2D(Texture_Gloss, TexCoord)) * SpecularColor * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
646 "#endif\n"
647 "\n"
648 "\n"
649 "\n"
650 "\n"
651 "#elif defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_LIGHTDIRECTIONMAP_TANGENTSPACE)\n"
652 "       // deluxemap lightmapping using light vectors in modelspace (evil q3map2)\n"
653 "\n"
654 "       // get the surface normal and light normal\n"
655 "       myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5));\n"
656 "\n"
657 "#ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
658 "       myhvec3 diffusenormal_modelspace = myhvec3(texture2D(Texture_Deluxemap, TexCoordLightmap)) - myhvec3(0.5);\n"
659 "       myhvec3 diffusenormal = normalize(myhvec3(dot(diffusenormal_modelspace, myhvec3(VectorS)), dot(diffusenormal_modelspace, myhvec3(VectorT)), dot(diffusenormal_modelspace, myhvec3(VectorR))));\n"
660 "#else\n"
661 "       myhvec3 diffusenormal = normalize(myhvec3(texture2D(Texture_Deluxemap, TexCoordLightmap)) - myhvec3(0.5));\n"
662 "#endif\n"
663 "       // calculate directional shading\n"
664 "       myhvec3 tempcolor = color.rgb * (DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0)));\n"
665 "#ifdef USESPECULAR\n"
666 "       myhvec3 specularnormal = myhvec3(normalize(diffusenormal + myhvec3(normalize(EyeVector))));\n"
667 "       tempcolor += myhvec3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
668 "#endif\n"
669 "\n"
670 "       // apply lightmap color\n"
671 "       color.rgb = tempcolor * myhvec3(texture2D(Texture_Lightmap, TexCoordLightmap)) + color.rgb * AmbientScale;\n"
672 "\n"
673 "\n"
674 "#else // MODE none (lightmap)\n"
675 "       // apply lightmap color\n"
676 "       color.rgb *= myhvec3(texture2D(Texture_Lightmap, TexCoordLightmap)) * DiffuseScale + myhvec3(AmbientScale);\n"
677 "#endif // MODE\n"
678 "\n"
679 "       color *= myhvec4(gl_Color);\n"
680 "\n"
681 "#ifdef USEGLOW\n"
682 "       color.rgb += myhvec3(texture2D(Texture_Glow, TexCoord)) * GlowScale;\n"
683 "#endif\n"
684 "\n"
685 "#ifdef USEFOG\n"
686 "       // apply fog\n"
687 "       myhalf fog = myhalf(texture2D(Texture_FogMask, myhvec2(length(EyeVectorModelSpace)*FogRangeRecip, 0.0)).x);\n"
688 "       color.rgb = color.rgb * fog + FogColor * (1.0 - fog);\n"
689 "#endif\n"
690 "\n"
691 "       color.rgb *= SceneBrightness;\n"
692 "\n"
693 "       gl_FragColor = vec4(color);\n"
694 "}\n"
695 "\n"
696 "#endif // FRAGMENT_SHADER\n"
697 ;
698
699 // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
700 const char *permutationinfo[][2] =
701 {
702         {"#define MODE_LIGHTSOURCE\n", " lightsource"},
703         {"#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
704         {"#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
705         {"#define MODE_LIGHTDIRECTION\n", " lightdirection"},
706         {"#define USEGLOW\n", " glow"},
707         {"#define USEFOG\n", " fog"},
708         {"#define USECOLORMAPPING\n", " colormapping"},
709         {"#define USESPECULAR\n", " specular"},
710         {"#define USECUBEFILTER\n", " cubefilter"},
711         {"#define USEOFFSETMAPPING\n", " offsetmapping"},
712         {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
713         {NULL, NULL}
714 };
715
716 void R_GLSL_CompilePermutation(const char *filename, int permutation)
717 {
718         int i;
719         qboolean shaderfound;
720         r_glsl_permutation_t *p = r_glsl_permutations + (permutation & SHADERPERMUTATION_COUNTMASK);
721         int vertstrings_count;
722         int geomstrings_count;
723         int fragstrings_count;
724         char *shaderstring;
725         const char *vertstrings_list[SHADERPERMUTATION_COUNT+1];
726         const char *geomstrings_list[SHADERPERMUTATION_COUNT+1];
727         const char *fragstrings_list[SHADERPERMUTATION_COUNT+1];
728         char permutationname[256];
729         if (p->compiled)
730                 return;
731         p->compiled = true;
732         p->program = 0;
733         vertstrings_list[0] = "#define VERTEX_SHADER\n";
734         geomstrings_list[0] = "#define GEOMETRY_SHADER\n";
735         fragstrings_list[0] = "#define FRAGMENT_SHADER\n";
736         vertstrings_count = 1;
737         geomstrings_count = 1;
738         fragstrings_count = 1;
739         permutationname[0] = 0;
740         for (i = 0;permutationinfo[i][0];i++)
741         {
742                 if (permutation & (1<<i))
743                 {
744                         vertstrings_list[vertstrings_count++] = permutationinfo[i][0];
745                         geomstrings_list[geomstrings_count++] = permutationinfo[i][0];
746                         fragstrings_list[fragstrings_count++] = permutationinfo[i][0];
747                         strlcat(permutationname, permutationinfo[i][1], sizeof(permutationname));
748                 }
749                 else
750                 {
751                         // keep line numbers correct
752                         vertstrings_list[vertstrings_count++] = "\n";
753                         geomstrings_list[geomstrings_count++] = "\n";
754                         fragstrings_list[fragstrings_count++] = "\n";
755                 }
756         }
757         shaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL);
758         shaderfound = false;
759         if (shaderstring)
760         {
761                 Con_DPrintf("GLSL shader text for \"%s\" loaded from disk\n", filename);
762                 vertstrings_list[vertstrings_count++] = shaderstring;
763                 geomstrings_list[geomstrings_count++] = shaderstring;
764                 fragstrings_list[fragstrings_count++] = shaderstring;
765                 shaderfound = true;
766         }
767         else if (!strcmp(filename, "glsl/default.glsl"))
768         {
769                 Con_DPrintf("GLSL shader text for \"%s\" loaded from engine\n", filename);
770                 vertstrings_list[vertstrings_count++] = builtinshaderstring;
771                 geomstrings_list[geomstrings_count++] = builtinshaderstring;
772                 fragstrings_list[fragstrings_count++] = builtinshaderstring;
773                 shaderfound = true;
774         }
775         // clear any lists that are not needed by this shader
776         if (!(permutation & SHADERPERMUTATION_USES_VERTEXSHADER))
777                 vertstrings_count = 0;
778         if (!(permutation & SHADERPERMUTATION_USES_GEOMETRYSHADER))
779                 geomstrings_count = 0;
780         if (!(permutation & SHADERPERMUTATION_USES_FRAGMENTSHADER))
781                 fragstrings_count = 0;
782         // compile the shader program
783         if (shaderfound && vertstrings_count + geomstrings_count + fragstrings_count)
784                 p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
785         if (p->program)
786         {
787                 CHECKGLERROR
788                 qglUseProgramObjectARB(p->program);CHECKGLERROR
789                 // look up all the uniform variable names we care about, so we don't
790                 // have to look them up every time we set them
791                 p->loc_Texture_Normal      = qglGetUniformLocationARB(p->program, "Texture_Normal");
792                 p->loc_Texture_Color       = qglGetUniformLocationARB(p->program, "Texture_Color");
793                 p->loc_Texture_Gloss       = qglGetUniformLocationARB(p->program, "Texture_Gloss");
794                 p->loc_Texture_Cube        = qglGetUniformLocationARB(p->program, "Texture_Cube");
795                 p->loc_Texture_FogMask     = qglGetUniformLocationARB(p->program, "Texture_FogMask");
796                 p->loc_Texture_Pants       = qglGetUniformLocationARB(p->program, "Texture_Pants");
797                 p->loc_Texture_Shirt       = qglGetUniformLocationARB(p->program, "Texture_Shirt");
798                 p->loc_Texture_Lightmap    = qglGetUniformLocationARB(p->program, "Texture_Lightmap");
799                 p->loc_Texture_Deluxemap   = qglGetUniformLocationARB(p->program, "Texture_Deluxemap");
800                 p->loc_Texture_Glow        = qglGetUniformLocationARB(p->program, "Texture_Glow");
801                 p->loc_FogColor            = qglGetUniformLocationARB(p->program, "FogColor");
802                 p->loc_LightPosition       = qglGetUniformLocationARB(p->program, "LightPosition");
803                 p->loc_EyePosition         = qglGetUniformLocationARB(p->program, "EyePosition");
804                 p->loc_LightColor          = qglGetUniformLocationARB(p->program, "LightColor");
805                 p->loc_Color_Pants         = qglGetUniformLocationARB(p->program, "Color_Pants");
806                 p->loc_Color_Shirt         = qglGetUniformLocationARB(p->program, "Color_Shirt");
807                 p->loc_FogRangeRecip       = qglGetUniformLocationARB(p->program, "FogRangeRecip");
808                 p->loc_AmbientScale        = qglGetUniformLocationARB(p->program, "AmbientScale");
809                 p->loc_DiffuseScale        = qglGetUniformLocationARB(p->program, "DiffuseScale");
810                 p->loc_SpecularPower       = qglGetUniformLocationARB(p->program, "SpecularPower");
811                 p->loc_SpecularScale       = qglGetUniformLocationARB(p->program, "SpecularScale");
812                 p->loc_GlowScale           = qglGetUniformLocationARB(p->program, "GlowScale");
813                 p->loc_SceneBrightness     = qglGetUniformLocationARB(p->program, "SceneBrightness");
814                 p->loc_OffsetMapping_Scale = qglGetUniformLocationARB(p->program, "OffsetMapping_Scale");
815                 p->loc_AmbientColor        = qglGetUniformLocationARB(p->program, "AmbientColor");
816                 p->loc_DiffuseColor        = qglGetUniformLocationARB(p->program, "DiffuseColor");
817                 p->loc_SpecularColor       = qglGetUniformLocationARB(p->program, "SpecularColor");
818                 p->loc_LightDir            = qglGetUniformLocationARB(p->program, "LightDir");
819                 // initialize the samplers to refer to the texture units we use
820                 if (p->loc_Texture_Normal >= 0)    qglUniform1iARB(p->loc_Texture_Normal, 0);
821                 if (p->loc_Texture_Color >= 0)     qglUniform1iARB(p->loc_Texture_Color, 1);
822                 if (p->loc_Texture_Gloss >= 0)     qglUniform1iARB(p->loc_Texture_Gloss, 2);
823                 if (p->loc_Texture_Cube >= 0)      qglUniform1iARB(p->loc_Texture_Cube, 3);
824                 if (p->loc_Texture_FogMask >= 0)   qglUniform1iARB(p->loc_Texture_FogMask, 4);
825                 if (p->loc_Texture_Pants >= 0)     qglUniform1iARB(p->loc_Texture_Pants, 5);
826                 if (p->loc_Texture_Shirt >= 0)     qglUniform1iARB(p->loc_Texture_Shirt, 6);
827                 if (p->loc_Texture_Lightmap >= 0)  qglUniform1iARB(p->loc_Texture_Lightmap, 7);
828                 if (p->loc_Texture_Deluxemap >= 0) qglUniform1iARB(p->loc_Texture_Deluxemap, 8);
829                 if (p->loc_Texture_Glow >= 0)      qglUniform1iARB(p->loc_Texture_Glow, 9);
830                 CHECKGLERROR
831                 qglUseProgramObjectARB(0);CHECKGLERROR
832         }
833         else
834                 Con_Printf("permutation%s failed for shader %s, some features may not work properly!\n", permutationname, "glsl/default.glsl");
835         if (shaderstring)
836                 Mem_Free(shaderstring);
837 }
838
839 void R_GLSL_Restart_f(void)
840 {
841         int i;
842         for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
843                 if (r_glsl_permutations[i].program)
844                         GL_Backend_FreeProgram(r_glsl_permutations[i].program);
845         memset(r_glsl_permutations, 0, sizeof(r_glsl_permutations));
846 }
847
848 int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting)
849 {
850         // select a permutation of the lighting shader appropriate to this
851         // combination of texture, entity, light source, and fogging, only use the
852         // minimum features necessary to avoid wasting rendering time in the
853         // fragment shader on features that are not being used
854         const char *shaderfilename = NULL;
855         int permutation = 0;
856         float specularscale = rsurface_texture->specularscale;
857         r_glsl_permutation = NULL;
858         // TODO: implement geometry-shader based shadow volumes someday
859         if (r_shadow_rtlight)
860         {
861                 // light source
862                 shaderfilename = "glsl/default.glsl";
863                 permutation = SHADERPERMUTATION_MODE_LIGHTSOURCE | SHADERPERMUTATION_USES_VERTEXSHADER | SHADERPERMUTATION_USES_FRAGMENTSHADER;
864                 specularscale *= r_shadow_rtlight->specularscale;
865                 if (r_shadow_rtlight->currentcubemap != r_texture_whitecube)
866                         permutation |= SHADERPERMUTATION_CUBEFILTER;
867                 if (specularscale > 0)
868                         permutation |= SHADERPERMUTATION_SPECULAR;
869                 if (r_refdef.fogenabled)
870                         permutation |= SHADERPERMUTATION_FOG;
871                 if (rsurface_texture->colormapping)
872                         permutation |= SHADERPERMUTATION_COLORMAPPING;
873                 if (r_glsl_offsetmapping.integer)
874                 {
875                         permutation |= SHADERPERMUTATION_OFFSETMAPPING;
876                         if (r_glsl_offsetmapping_reliefmapping.integer)
877                                 permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
878                 }
879         }
880         else if (rsurface_texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
881         {
882                 // bright unshaded geometry
883                 shaderfilename = "glsl/default.glsl";
884                 permutation = SHADERPERMUTATION_USES_VERTEXSHADER | SHADERPERMUTATION_USES_FRAGMENTSHADER;
885                 if (rsurface_texture->currentskinframe->glow)
886                         permutation |= SHADERPERMUTATION_GLOW;
887                 if (r_refdef.fogenabled)
888                         permutation |= SHADERPERMUTATION_FOG;
889                 if (rsurface_texture->colormapping)
890                         permutation |= SHADERPERMUTATION_COLORMAPPING;
891                 if (r_glsl_offsetmapping.integer)
892                 {
893                         permutation |= SHADERPERMUTATION_OFFSETMAPPING;
894                         if (r_glsl_offsetmapping_reliefmapping.integer)
895                                 permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
896                 }
897         }
898         else if (modellighting)
899         {
900                 // directional model lighting
901                 shaderfilename = "glsl/default.glsl";
902                 permutation = SHADERPERMUTATION_USES_VERTEXSHADER | SHADERPERMUTATION_USES_FRAGMENTSHADER;
903                 permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTION;
904                 if (rsurface_texture->currentskinframe->glow)
905                         permutation |= SHADERPERMUTATION_GLOW;
906                 if (specularscale > 0)
907                         permutation |= SHADERPERMUTATION_SPECULAR;
908                 if (r_refdef.fogenabled)
909                         permutation |= SHADERPERMUTATION_FOG;
910                 if (rsurface_texture->colormapping)
911                         permutation |= SHADERPERMUTATION_COLORMAPPING;
912                 if (r_glsl_offsetmapping.integer)
913                 {
914                         permutation |= SHADERPERMUTATION_OFFSETMAPPING;
915                         if (r_glsl_offsetmapping_reliefmapping.integer)
916                                 permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
917                 }
918         }
919         else
920         {
921                 // lightmapped wall
922                 shaderfilename = "glsl/default.glsl";
923                 permutation = SHADERPERMUTATION_USES_VERTEXSHADER | SHADERPERMUTATION_USES_FRAGMENTSHADER;
924                 if (r_glsl_deluxemapping.integer >= 1 && rsurface_uselightmaptexture && r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping)
925                 {
926                         // deluxemapping (light direction texture)
927                         if (rsurface_uselightmaptexture && r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping && r_refdef.worldmodel->brushq3.deluxemapping_modelspace)
928                                 permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_MODELSPACE;
929                         else
930                                 permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
931                         if (specularscale > 0)
932                                 permutation |= SHADERPERMUTATION_SPECULAR;
933                 }
934                 else if (r_glsl_deluxemapping.integer >= 2)
935                 {
936                         // fake deluxemapping (uniform light direction in tangentspace)
937                         permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
938                         if (specularscale > 0)
939                                 permutation |= SHADERPERMUTATION_SPECULAR;
940                 }
941                 else
942                 {
943                         // ordinary lightmapping
944                         permutation |= 0;
945                 }
946                 if (rsurface_texture->currentskinframe->glow)
947                         permutation |= SHADERPERMUTATION_GLOW;
948                 if (r_refdef.fogenabled)
949                         permutation |= SHADERPERMUTATION_FOG;
950                 if (rsurface_texture->colormapping)
951                         permutation |= SHADERPERMUTATION_COLORMAPPING;
952                 if (r_glsl_offsetmapping.integer)
953                 {
954                         permutation |= SHADERPERMUTATION_OFFSETMAPPING;
955                         if (r_glsl_offsetmapping_reliefmapping.integer)
956                                 permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
957                 }
958         }
959         if (!r_glsl_permutations[permutation & SHADERPERMUTATION_COUNTMASK].program)
960         {
961                 if (!r_glsl_permutations[permutation & SHADERPERMUTATION_COUNTMASK].compiled)
962                         R_GLSL_CompilePermutation(shaderfilename, permutation);
963                 if (!r_glsl_permutations[permutation & SHADERPERMUTATION_COUNTMASK].program)
964                 {
965                         // remove features until we find a valid permutation
966                         int i;
967                         for (i = SHADERPERMUTATION_COUNT-1;;i>>=1)
968                         {
969                                 // reduce i more quickly whenever it would not remove any bits
970                                 if (permutation < i)
971                                         continue;
972                                 permutation &= i;
973                                 if (!r_glsl_permutations[permutation & SHADERPERMUTATION_COUNTMASK].compiled)
974                                         R_GLSL_CompilePermutation(shaderfilename, permutation);
975                                 if (r_glsl_permutations[permutation & SHADERPERMUTATION_COUNTMASK].program)
976                                         break;
977                                 if (!i)
978                                         return 0; // utterly failed
979                         }
980                 }
981         }
982         r_glsl_permutation = r_glsl_permutations + (permutation & SHADERPERMUTATION_COUNTMASK);
983         CHECKGLERROR
984         qglUseProgramObjectARB(r_glsl_permutation->program);CHECKGLERROR
985         R_Mesh_TexMatrix(0, &rsurface_texture->currenttexmatrix);
986         if (permutation & SHADERPERMUTATION_MODE_LIGHTSOURCE)
987         {
988                 if (r_glsl_permutation->loc_Texture_Cube >= 0 && r_shadow_rtlight) R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_rtlight->currentcubemap));
989                 if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightPosition, r_shadow_entitylightorigin[0], r_shadow_entitylightorigin[1], r_shadow_entitylightorigin[2]);
990                 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightColor, lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);
991                 if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, r_shadow_rtlight->ambientscale);
992                 if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, r_shadow_rtlight->diffusescale);
993                 if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, specularscale);
994         }
995         else if (permutation & SHADERPERMUTATION_MODE_LIGHTDIRECTION)
996         {
997                 if (r_glsl_permutation->loc_AmbientColor >= 0)
998                         qglUniform3fARB(r_glsl_permutation->loc_AmbientColor, rsurface_entity->modellight_ambient[0], rsurface_entity->modellight_ambient[1], rsurface_entity->modellight_ambient[2]);
999                 if (r_glsl_permutation->loc_DiffuseColor >= 0)
1000                         qglUniform3fARB(r_glsl_permutation->loc_DiffuseColor, rsurface_entity->modellight_diffuse[0], rsurface_entity->modellight_diffuse[1], rsurface_entity->modellight_diffuse[2]);
1001                 if (r_glsl_permutation->loc_SpecularColor >= 0)
1002                         qglUniform3fARB(r_glsl_permutation->loc_SpecularColor, rsurface_entity->modellight_diffuse[0] * rsurface_texture->specularscale, rsurface_entity->modellight_diffuse[1] * rsurface_texture->specularscale, rsurface_entity->modellight_diffuse[2] * rsurface_texture->specularscale);
1003                 if (r_glsl_permutation->loc_LightDir >= 0)
1004                         qglUniform3fARB(r_glsl_permutation->loc_LightDir, rsurface_entity->modellight_lightdir[0], rsurface_entity->modellight_lightdir[1], rsurface_entity->modellight_lightdir[2]);
1005         }
1006         else
1007         {
1008                 if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, r_ambient.value * 2.0f / 128.0f);
1009                 if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, r_refdef.lightmapintensity * 2.0f);
1010                 if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, r_refdef.lightmapintensity * specularscale * 2.0f);
1011         }
1012         if (r_glsl_permutation->loc_Texture_Normal >= 0) R_Mesh_TexBind(0, R_GetTexture(rsurface_texture->currentskinframe->nmap));
1013         if (r_glsl_permutation->loc_Texture_Color >= 0) R_Mesh_TexBind(1, R_GetTexture(rsurface_texture->basetexture));
1014         if (r_glsl_permutation->loc_Texture_Gloss >= 0) R_Mesh_TexBind(2, R_GetTexture(rsurface_texture->glosstexture));
1015         //if (r_glsl_permutation->loc_Texture_Cube >= 0 && permutation & SHADERPERMUTATION_MODE_LIGHTSOURCE) R_Mesh_TexBindCubeMap(3, R_GetTexture(r_shadow_rtlight->currentcubemap));
1016         if (r_glsl_permutation->loc_Texture_FogMask >= 0) R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation));
1017         if (r_glsl_permutation->loc_Texture_Pants >= 0) R_Mesh_TexBind(5, R_GetTexture(rsurface_texture->currentskinframe->pants));
1018         if (r_glsl_permutation->loc_Texture_Shirt >= 0) R_Mesh_TexBind(6, R_GetTexture(rsurface_texture->currentskinframe->shirt));
1019         //if (r_glsl_permutation->loc_Texture_Lightmap >= 0) R_Mesh_TexBind(7, R_GetTexture(r_texture_white));
1020         //if (r_glsl_permutation->loc_Texture_Deluxemap >= 0) R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
1021         if (r_glsl_permutation->loc_Texture_Glow >= 0) R_Mesh_TexBind(9, R_GetTexture(rsurface_texture->currentskinframe->glow));
1022         if (r_glsl_permutation->loc_GlowScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_GlowScale, r_hdr_glowintensity.value);
1023         if (r_glsl_permutation->loc_SceneBrightness >= 0) qglUniform1fARB(r_glsl_permutation->loc_SceneBrightness, r_view.colorscale);
1024         if (r_glsl_permutation->loc_FogColor >= 0)
1025         {
1026                 // additive passes are only darkened by fog, not tinted
1027                 if (r_shadow_rtlight || (rsurface_texture->currentmaterialflags & MATERIALFLAG_ADD))
1028                         qglUniform3fARB(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1029                 else
1030                         qglUniform3fARB(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1031         }
1032         if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_EyePosition, rsurface_modelorg[0], rsurface_modelorg[1], rsurface_modelorg[2]);
1033         if (r_glsl_permutation->loc_Color_Pants >= 0)
1034         {
1035                 if (rsurface_texture->currentskinframe->pants)
1036                         qglUniform3fARB(r_glsl_permutation->loc_Color_Pants, rsurface_entity->colormap_pantscolor[0], rsurface_entity->colormap_pantscolor[1], rsurface_entity->colormap_pantscolor[2]);
1037                 else
1038                         qglUniform3fARB(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
1039         }
1040         if (r_glsl_permutation->loc_Color_Shirt >= 0)
1041         {
1042                 if (rsurface_texture->currentskinframe->shirt)
1043                         qglUniform3fARB(r_glsl_permutation->loc_Color_Shirt, rsurface_entity->colormap_shirtcolor[0], rsurface_entity->colormap_shirtcolor[1], rsurface_entity->colormap_shirtcolor[2]);
1044                 else
1045                         qglUniform3fARB(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
1046         }
1047         if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1fARB(r_glsl_permutation->loc_FogRangeRecip, r_refdef.fograngerecip);
1048         if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularPower, rsurface_texture->specularpower);
1049         if (r_glsl_permutation->loc_OffsetMapping_Scale >= 0) qglUniform1fARB(r_glsl_permutation->loc_OffsetMapping_Scale, r_glsl_offsetmapping_scale.value);
1050         CHECKGLERROR
1051         return permutation;
1052 }
1053
1054 void R_SwitchSurfaceShader(int permutation)
1055 {
1056         if (r_glsl_permutation != r_glsl_permutations + (permutation & SHADERPERMUTATION_COUNTMASK))
1057         {
1058                 r_glsl_permutation = r_glsl_permutations + (permutation & SHADERPERMUTATION_COUNTMASK);
1059                 CHECKGLERROR
1060                 qglUseProgramObjectARB(r_glsl_permutation->program);
1061                 CHECKGLERROR
1062         }
1063 }
1064
1065 void gl_main_start(void)
1066 {
1067         r_main_texturepool = R_AllocTexturePool();
1068         R_BuildBlankTextures();
1069         R_BuildNoTexture();
1070         if (gl_texturecubemap)
1071         {
1072                 R_BuildWhiteCube();
1073                 R_BuildNormalizationCube();
1074         }
1075         R_BuildFogTexture();
1076         memset(&r_bloomstate, 0, sizeof(r_bloomstate));
1077         memset(r_glsl_permutations, 0, sizeof(r_glsl_permutations));
1078         memset(&r_svbsp, 0, sizeof (r_svbsp));
1079 }
1080
1081 void gl_main_shutdown(void)
1082 {
1083         if (r_svbsp.nodes)
1084                 Mem_Free(r_svbsp.nodes);
1085         memset(&r_svbsp, 0, sizeof (r_svbsp));
1086         R_FreeTexturePool(&r_main_texturepool);
1087         r_texture_blanknormalmap = NULL;
1088         r_texture_white = NULL;
1089         r_texture_black = NULL;
1090         r_texture_whitecube = NULL;
1091         r_texture_normalizationcube = NULL;
1092         memset(&r_bloomstate, 0, sizeof(r_bloomstate));
1093         R_GLSL_Restart_f();
1094 }
1095
1096 extern void CL_ParseEntityLump(char *entitystring);
1097 void gl_main_newmap(void)
1098 {
1099         // FIXME: move this code to client
1100         int l;
1101         char *entities, entname[MAX_QPATH];
1102         if (cl.worldmodel)
1103         {
1104                 strlcpy(entname, cl.worldmodel->name, sizeof(entname));
1105                 l = (int)strlen(entname) - 4;
1106                 if (l >= 0 && !strcmp(entname + l, ".bsp"))
1107                 {
1108                         memcpy(entname + l, ".ent", 5);
1109                         if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
1110                         {
1111                                 CL_ParseEntityLump(entities);
1112                                 Mem_Free(entities);
1113                                 return;
1114                         }
1115                 }
1116                 if (cl.worldmodel->brush.entities)
1117                         CL_ParseEntityLump(cl.worldmodel->brush.entities);
1118         }
1119 }
1120
1121 void GL_Main_Init(void)
1122 {
1123         r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
1124
1125         Cmd_AddCommand("r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
1126         FOG_registercvars(); // FIXME: move this fog stuff to client?
1127         Cvar_RegisterVariable(&r_nearclip);
1128         Cvar_RegisterVariable(&r_showsurfaces);
1129         Cvar_RegisterVariable(&r_showtris);
1130         Cvar_RegisterVariable(&r_shownormals);
1131         Cvar_RegisterVariable(&r_showlighting);
1132         Cvar_RegisterVariable(&r_showshadowvolumes);
1133         Cvar_RegisterVariable(&r_showcollisionbrushes);
1134         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
1135         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
1136         Cvar_RegisterVariable(&r_showdisabledepthtest);
1137         Cvar_RegisterVariable(&r_drawportals);
1138         Cvar_RegisterVariable(&r_drawentities);
1139         Cvar_RegisterVariable(&r_cullentities_trace);
1140         Cvar_RegisterVariable(&r_cullentities_trace_samples);
1141         Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
1142         Cvar_RegisterVariable(&r_cullentities_trace_delay);
1143         Cvar_RegisterVariable(&r_drawviewmodel);
1144         Cvar_RegisterVariable(&r_speeds);
1145         Cvar_RegisterVariable(&r_fullbrights);
1146         Cvar_RegisterVariable(&r_wateralpha);
1147         Cvar_RegisterVariable(&r_dynamic);
1148         Cvar_RegisterVariable(&r_fullbright);
1149         Cvar_RegisterVariable(&r_shadows);
1150         Cvar_RegisterVariable(&r_shadows_throwdistance);
1151         Cvar_RegisterVariable(&r_q1bsp_skymasking);
1152         Cvar_RegisterVariable(&r_textureunits);
1153         Cvar_RegisterVariable(&r_glsl);
1154         Cvar_RegisterVariable(&r_glsl_offsetmapping);
1155         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
1156         Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
1157         Cvar_RegisterVariable(&r_glsl_deluxemapping);
1158         Cvar_RegisterVariable(&r_lerpsprites);
1159         Cvar_RegisterVariable(&r_lerpmodels);
1160         Cvar_RegisterVariable(&r_waterscroll);
1161         Cvar_RegisterVariable(&r_bloom);
1162         Cvar_RegisterVariable(&r_bloom_colorscale);
1163         Cvar_RegisterVariable(&r_bloom_brighten);
1164         Cvar_RegisterVariable(&r_bloom_blur);
1165         Cvar_RegisterVariable(&r_bloom_resolution);
1166         Cvar_RegisterVariable(&r_bloom_colorexponent);
1167         Cvar_RegisterVariable(&r_bloom_colorsubtract);
1168         Cvar_RegisterVariable(&r_hdr);
1169         Cvar_RegisterVariable(&r_hdr_scenebrightness);
1170         Cvar_RegisterVariable(&r_hdr_glowintensity);
1171         Cvar_RegisterVariable(&r_hdr_range);
1172         Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
1173         Cvar_RegisterVariable(&developer_texturelogging);
1174         Cvar_RegisterVariable(&gl_lightmaps);
1175         Cvar_RegisterVariable(&r_test);
1176         Cvar_RegisterVariable(&r_batchmode);
1177         if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
1178                 Cvar_SetValue("r_fullbrights", 0);
1179         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
1180 }
1181
1182 extern void R_Textures_Init(void);
1183 extern void GL_Draw_Init(void);
1184 extern void GL_Main_Init(void);
1185 extern void R_Shadow_Init(void);
1186 extern void R_Sky_Init(void);
1187 extern void GL_Surf_Init(void);
1188 extern void R_Light_Init(void);
1189 extern void R_Particles_Init(void);
1190 extern void R_Explosion_Init(void);
1191 extern void gl_backend_init(void);
1192 extern void Sbar_Init(void);
1193 extern void R_LightningBeams_Init(void);
1194 extern void Mod_RenderInit(void);
1195
1196 void Render_Init(void)
1197 {
1198         gl_backend_init();
1199         R_Textures_Init();
1200         GL_Main_Init();
1201         GL_Draw_Init();
1202         R_Shadow_Init();
1203         R_Sky_Init();
1204         GL_Surf_Init();
1205         Sbar_Init();
1206         R_Light_Init();
1207         R_Particles_Init();
1208         R_Explosion_Init();
1209         R_LightningBeams_Init();
1210         Mod_RenderInit();
1211 }
1212
1213 /*
1214 ===============
1215 GL_Init
1216 ===============
1217 */
1218 extern char *ENGINE_EXTENSIONS;
1219 void GL_Init (void)
1220 {
1221         VID_CheckExtensions();
1222
1223         // LordHavoc: report supported extensions
1224         Con_DPrintf("\nQuakeC extensions for server and client: %s\nQuakeC extensions for menu: %s\n", vm_sv_extensions, vm_m_extensions );
1225
1226         // clear to black (loading plaque will be seen over this)
1227         CHECKGLERROR
1228         qglClearColor(0,0,0,1);CHECKGLERROR
1229         qglClear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
1230 }
1231
1232 int R_CullBox(const vec3_t mins, const vec3_t maxs)
1233 {
1234         int i;
1235         mplane_t *p;
1236         for (i = 0;i < 4;i++)
1237         {
1238                 p = r_view.frustum + i;
1239                 switch(p->signbits)
1240                 {
1241                 default:
1242                 case 0:
1243                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
1244                                 return true;
1245                         break;
1246                 case 1:
1247                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
1248                                 return true;
1249                         break;
1250                 case 2:
1251                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
1252                                 return true;
1253                         break;
1254                 case 3:
1255                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
1256                                 return true;
1257                         break;
1258                 case 4:
1259                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
1260                                 return true;
1261                         break;
1262                 case 5:
1263                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
1264                                 return true;
1265                         break;
1266                 case 6:
1267                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
1268                                 return true;
1269                         break;
1270                 case 7:
1271                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
1272                                 return true;
1273                         break;
1274                 }
1275         }
1276         return false;
1277 }
1278
1279 int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
1280 {
1281         int i;
1282         const mplane_t *p;
1283         for (i = 0;i < numplanes;i++)
1284         {
1285                 p = planes + i;
1286                 switch(p->signbits)
1287                 {
1288                 default:
1289                 case 0:
1290                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
1291                                 return true;
1292                         break;
1293                 case 1:
1294                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
1295                                 return true;
1296                         break;
1297                 case 2:
1298                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
1299                                 return true;
1300                         break;
1301                 case 3:
1302                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
1303                                 return true;
1304                         break;
1305                 case 4:
1306                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
1307                                 return true;
1308                         break;
1309                 case 5:
1310                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
1311                                 return true;
1312                         break;
1313                 case 6:
1314                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
1315                                 return true;
1316                         break;
1317                 case 7:
1318                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
1319                                 return true;
1320                         break;
1321                 }
1322         }
1323         return false;
1324 }
1325
1326 //==================================================================================
1327
1328 static void R_UpdateEntityLighting(entity_render_t *ent)
1329 {
1330         vec3_t tempdiffusenormal;
1331
1332         // fetch the lighting from the worldmodel data
1333         VectorSet(ent->modellight_ambient, r_ambient.value * (2.0f / 128.0f), r_ambient.value * (2.0f / 128.0f), r_ambient.value * (2.0f / 128.0f));
1334         VectorClear(ent->modellight_diffuse);
1335         VectorClear(tempdiffusenormal);
1336         if ((ent->flags & RENDER_LIGHT) && r_refdef.worldmodel && r_refdef.worldmodel->brush.LightPoint)
1337         {
1338                 vec3_t org;
1339                 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
1340                 r_refdef.worldmodel->brush.LightPoint(r_refdef.worldmodel, org, ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal);
1341         }
1342         else // highly rare
1343                 VectorSet(ent->modellight_ambient, 1, 1, 1);
1344
1345         // move the light direction into modelspace coordinates for lighting code
1346         Matrix4x4_Transform3x3(&ent->inversematrix, tempdiffusenormal, ent->modellight_lightdir);
1347         VectorNormalize(ent->modellight_lightdir);
1348
1349         // scale ambient and directional light contributions according to rendering variables
1350         ent->modellight_ambient[0] *= ent->colormod[0] * r_refdef.lightmapintensity;
1351         ent->modellight_ambient[1] *= ent->colormod[1] * r_refdef.lightmapintensity;
1352         ent->modellight_ambient[2] *= ent->colormod[2] * r_refdef.lightmapintensity;
1353         ent->modellight_diffuse[0] *= ent->colormod[0] * r_refdef.lightmapintensity;
1354         ent->modellight_diffuse[1] *= ent->colormod[1] * r_refdef.lightmapintensity;
1355         ent->modellight_diffuse[2] *= ent->colormod[2] * r_refdef.lightmapintensity;
1356 }
1357
1358 static void R_View_UpdateEntityVisible (void)
1359 {
1360         int i, renderimask;
1361         entity_render_t *ent;
1362
1363         if (!r_drawentities.integer)
1364                 return;
1365
1366         renderimask = r_refdef.envmap ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL) : (chase_active.integer ? 0 : RENDER_EXTERIORMODEL);
1367         if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingVisibleLeafs)
1368         {
1369                 // worldmodel can check visibility
1370                 for (i = 0;i < r_refdef.numentities;i++)
1371                 {
1372                         ent = r_refdef.entities[i];
1373                         r_viewcache.entityvisible[i] = !(ent->flags & renderimask) && !R_CullBox(ent->mins, ent->maxs) && ((ent->effects & EF_NODEPTHTEST) || r_refdef.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.worldmodel, r_viewcache.world_leafvisible, ent->mins, ent->maxs));
1374                 }
1375                 if(r_cullentities_trace.integer)
1376                 {
1377                         for (i = 0;i < r_refdef.numentities;i++)
1378                         {
1379                                 ent = r_refdef.entities[i];
1380                                 if(r_viewcache.entityvisible[i] && !(ent->effects & EF_NODEPTHTEST) && !(ent->model && (ent->model->name[0] == '*')))
1381                                 {
1382                                         if(Mod_CanSeeBox_Trace(r_cullentities_trace_samples.integer, r_cullentities_trace_enlarge.value, r_refdef.worldmodel, r_view.origin, ent->mins, ent->maxs))
1383                                                 ent->last_trace_visibility = realtime;
1384                                         if(ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
1385                                                 r_viewcache.entityvisible[i] = 0;
1386                                 }
1387                         }
1388                 }
1389         }
1390         else
1391         {
1392                 // no worldmodel or it can't check visibility
1393                 for (i = 0;i < r_refdef.numentities;i++)
1394                 {
1395                         ent = r_refdef.entities[i];
1396                         r_viewcache.entityvisible[i] = !(ent->flags & renderimask) && !R_CullBox(ent->mins, ent->maxs);
1397                 }
1398         }
1399
1400         // update entity lighting (even on hidden entities for r_shadows)
1401         for (i = 0;i < r_refdef.numentities;i++)
1402                 R_UpdateEntityLighting(r_refdef.entities[i]);
1403 }
1404
1405 // only used if skyrendermasked, and normally returns false
1406 int R_DrawBrushModelsSky (void)
1407 {
1408         int i, sky;
1409         entity_render_t *ent;
1410
1411         if (!r_drawentities.integer)
1412                 return false;
1413
1414         sky = false;
1415         for (i = 0;i < r_refdef.numentities;i++)
1416         {
1417                 if (!r_viewcache.entityvisible[i])
1418                         continue;
1419                 ent = r_refdef.entities[i];
1420                 if (!ent->model || !ent->model->DrawSky)
1421                         continue;
1422                 ent->model->DrawSky(ent);
1423                 sky = true;
1424         }
1425         return sky;
1426 }
1427
1428 void R_DrawNoModel(entity_render_t *ent);
1429 void R_DrawModels(void)
1430 {
1431         int i;
1432         entity_render_t *ent;
1433
1434         if (!r_drawentities.integer)
1435                 return;
1436
1437         for (i = 0;i < r_refdef.numentities;i++)
1438         {
1439                 if (!r_viewcache.entityvisible[i])
1440                         continue;
1441                 ent = r_refdef.entities[i];
1442                 r_refdef.stats.entities++;
1443                 if (ent->model && ent->model->Draw != NULL)
1444                         ent->model->Draw(ent);
1445                 else
1446                         R_DrawNoModel(ent);
1447         }
1448 }
1449
1450 static void R_View_SetFrustum(void)
1451 {
1452         double slopex, slopey;
1453
1454         // break apart the view matrix into vectors for various purposes
1455         Matrix4x4_ToVectors(&r_view.matrix, r_view.forward, r_view.left, r_view.up, r_view.origin);
1456         VectorNegate(r_view.left, r_view.right);
1457
1458 #if 0
1459         r_view.frustum[0].normal[0] = 0 - 1.0 / r_view.frustum_x;
1460         r_view.frustum[0].normal[1] = 0 - 0;
1461         r_view.frustum[0].normal[2] = -1 - 0;
1462         r_view.frustum[1].normal[0] = 0 + 1.0 / r_view.frustum_x;
1463         r_view.frustum[1].normal[1] = 0 + 0;
1464         r_view.frustum[1].normal[2] = -1 + 0;
1465         r_view.frustum[2].normal[0] = 0 - 0;
1466         r_view.frustum[2].normal[1] = 0 - 1.0 / r_view.frustum_y;
1467         r_view.frustum[2].normal[2] = -1 - 0;
1468         r_view.frustum[3].normal[0] = 0 + 0;
1469         r_view.frustum[3].normal[1] = 0 + 1.0 / r_view.frustum_y;
1470         r_view.frustum[3].normal[2] = -1 + 0;
1471 #endif
1472
1473 #if 0
1474         zNear = r_refdef.nearclip;
1475         nudge = 1.0 - 1.0 / (1<<23);
1476         r_view.frustum[4].normal[0] = 0 - 0;
1477         r_view.frustum[4].normal[1] = 0 - 0;
1478         r_view.frustum[4].normal[2] = -1 - -nudge;
1479         r_view.frustum[4].dist = 0 - -2 * zNear * nudge;
1480         r_view.frustum[5].normal[0] = 0 + 0;
1481         r_view.frustum[5].normal[1] = 0 + 0;
1482         r_view.frustum[5].normal[2] = -1 + -nudge;
1483         r_view.frustum[5].dist = 0 + -2 * zNear * nudge;
1484 #endif
1485
1486
1487
1488 #if 0
1489         r_view.frustum[0].normal[0] = m[3] - m[0];
1490         r_view.frustum[0].normal[1] = m[7] - m[4];
1491         r_view.frustum[0].normal[2] = m[11] - m[8];
1492         r_view.frustum[0].dist = m[15] - m[12];
1493
1494         r_view.frustum[1].normal[0] = m[3] + m[0];
1495         r_view.frustum[1].normal[1] = m[7] + m[4];
1496         r_view.frustum[1].normal[2] = m[11] + m[8];
1497         r_view.frustum[1].dist = m[15] + m[12];
1498
1499         r_view.frustum[2].normal[0] = m[3] - m[1];
1500         r_view.frustum[2].normal[1] = m[7] - m[5];
1501         r_view.frustum[2].normal[2] = m[11] - m[9];
1502         r_view.frustum[2].dist = m[15] - m[13];
1503
1504         r_view.frustum[3].normal[0] = m[3] + m[1];
1505         r_view.frustum[3].normal[1] = m[7] + m[5];
1506         r_view.frustum[3].normal[2] = m[11] + m[9];
1507         r_view.frustum[3].dist = m[15] + m[13];
1508
1509         r_view.frustum[4].normal[0] = m[3] - m[2];
1510         r_view.frustum[4].normal[1] = m[7] - m[6];
1511         r_view.frustum[4].normal[2] = m[11] - m[10];
1512         r_view.frustum[4].dist = m[15] - m[14];
1513
1514         r_view.frustum[5].normal[0] = m[3] + m[2];
1515         r_view.frustum[5].normal[1] = m[7] + m[6];
1516         r_view.frustum[5].normal[2] = m[11] + m[10];
1517         r_view.frustum[5].dist = m[15] + m[14];
1518 #endif
1519
1520
1521
1522         slopex = 1.0 / r_view.frustum_x;
1523         slopey = 1.0 / r_view.frustum_y;
1524         VectorMA(r_view.forward, -slopex, r_view.left, r_view.frustum[0].normal);
1525         VectorMA(r_view.forward,  slopex, r_view.left, r_view.frustum[1].normal);
1526         VectorMA(r_view.forward, -slopey, r_view.up  , r_view.frustum[2].normal);
1527         VectorMA(r_view.forward,  slopey, r_view.up  , r_view.frustum[3].normal);
1528         VectorCopy(r_view.forward, r_view.frustum[4].normal);
1529         VectorNormalize(r_view.frustum[0].normal);
1530         VectorNormalize(r_view.frustum[1].normal);
1531         VectorNormalize(r_view.frustum[2].normal);
1532         VectorNormalize(r_view.frustum[3].normal);
1533         r_view.frustum[0].dist = DotProduct (r_view.origin, r_view.frustum[0].normal);
1534         r_view.frustum[1].dist = DotProduct (r_view.origin, r_view.frustum[1].normal);
1535         r_view.frustum[2].dist = DotProduct (r_view.origin, r_view.frustum[2].normal);
1536         r_view.frustum[3].dist = DotProduct (r_view.origin, r_view.frustum[3].normal);
1537         r_view.frustum[4].dist = DotProduct (r_view.origin, r_view.frustum[4].normal) + r_refdef.nearclip;
1538         PlaneClassify(&r_view.frustum[0]);
1539         PlaneClassify(&r_view.frustum[1]);
1540         PlaneClassify(&r_view.frustum[2]);
1541         PlaneClassify(&r_view.frustum[3]);
1542         PlaneClassify(&r_view.frustum[4]);
1543
1544         // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
1545         VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, -1024 * slopex, r_view.left, -1024 * slopey, r_view.up, r_view.frustumcorner[0]);
1546         VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward,  1024 * slopex, r_view.left, -1024 * slopey, r_view.up, r_view.frustumcorner[1]);
1547         VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, -1024 * slopex, r_view.left,  1024 * slopey, r_view.up, r_view.frustumcorner[2]);
1548         VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward,  1024 * slopex, r_view.left,  1024 * slopey, r_view.up, r_view.frustumcorner[3]);
1549
1550         // LordHavoc: note to all quake engine coders, Quake had a special case
1551         // for 90 degrees which assumed a square view (wrong), so I removed it,
1552         // Quake2 has it disabled as well.
1553
1554         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
1555         //RotatePointAroundVector( r_view.frustum[0].normal, r_view.up, r_view.forward, -(90 - r_refdef.fov_x / 2));
1556         //r_view.frustum[0].dist = DotProduct (r_view.origin, frustum[0].normal);
1557         //PlaneClassify(&frustum[0]);
1558
1559         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
1560         //RotatePointAroundVector( r_view.frustum[1].normal, r_view.up, r_view.forward, (90 - r_refdef.fov_x / 2));
1561         //r_view.frustum[1].dist = DotProduct (r_view.origin, frustum[1].normal);
1562         //PlaneClassify(&frustum[1]);
1563
1564         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
1565         //RotatePointAroundVector( r_view.frustum[2].normal, r_view.left, r_view.forward, -(90 - r_refdef.fov_y / 2));
1566         //r_view.frustum[2].dist = DotProduct (r_view.origin, frustum[2].normal);
1567         //PlaneClassify(&frustum[2]);
1568
1569         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
1570         //RotatePointAroundVector( r_view.frustum[3].normal, r_view.left, r_view.forward, (90 - r_refdef.fov_y / 2));
1571         //r_view.frustum[3].dist = DotProduct (r_view.origin, frustum[3].normal);
1572         //PlaneClassify(&frustum[3]);
1573
1574         // nearclip plane
1575         //VectorCopy(r_view.forward, r_view.frustum[4].normal);
1576         //r_view.frustum[4].dist = DotProduct (r_view.origin, frustum[4].normal) + r_nearclip.value;
1577         //PlaneClassify(&frustum[4]);
1578 }
1579
1580 void R_View_Update(void)
1581 {
1582         R_View_SetFrustum();
1583         R_View_WorldVisibility();
1584         R_View_UpdateEntityVisible();
1585 }
1586
1587 void R_SetupView(const matrix4x4_t *matrix)
1588 {
1589         if (r_refdef.rtworldshadows || r_refdef.rtdlightshadows)
1590                 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view.frustum_x, r_view.frustum_y, r_refdef.nearclip);
1591         else
1592                 GL_SetupView_Mode_Perspective(r_view.frustum_x, r_view.frustum_y, r_refdef.nearclip, r_refdef.farclip);
1593
1594         GL_SetupView_Orientation_FromEntity(matrix);
1595 }
1596
1597 void R_ResetViewRendering2D(void)
1598 {
1599         if (gl_support_fragment_shader)
1600         {
1601                 qglUseProgramObjectARB(0);CHECKGLERROR
1602         }
1603
1604         DrawQ_Finish();
1605
1606         // GL is weird because it's bottom to top, r_view.y is top to bottom
1607         qglViewport(r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
1608         GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
1609         GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1610         GL_Color(1, 1, 1, 1);
1611         GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
1612         GL_BlendFunc(GL_ONE, GL_ZERO);
1613         GL_AlphaTest(false);
1614         GL_ScissorTest(false);
1615         GL_DepthMask(false);
1616         GL_DepthTest(false);
1617         R_Mesh_Matrix(&identitymatrix);
1618         R_Mesh_ResetTextureState();
1619         qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1620         qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
1621         qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1622         qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1623         qglStencilMask(~0);CHECKGLERROR
1624         qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1625         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1626         GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
1627 }
1628
1629 void R_ResetViewRendering3D(void)
1630 {
1631         if (gl_support_fragment_shader)
1632         {
1633                 qglUseProgramObjectARB(0);CHECKGLERROR
1634         }
1635
1636         DrawQ_Finish();
1637
1638         // GL is weird because it's bottom to top, r_view.y is top to bottom
1639         qglViewport(r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
1640         R_SetupView(&r_view.matrix);
1641         GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
1642         GL_Color(1, 1, 1, 1);
1643         GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
1644         GL_BlendFunc(GL_ONE, GL_ZERO);
1645         GL_AlphaTest(false);
1646         GL_ScissorTest(true);
1647         GL_DepthMask(true);
1648         GL_DepthTest(true);
1649         R_Mesh_Matrix(&identitymatrix);
1650         R_Mesh_ResetTextureState();
1651         qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
1652         qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
1653         qglDepthFunc(GL_LEQUAL);CHECKGLERROR
1654         qglDisable(GL_STENCIL_TEST);CHECKGLERROR
1655         qglStencilMask(~0);CHECKGLERROR
1656         qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
1657         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
1658         GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
1659 }
1660
1661 /*
1662         R_Bloom_SetupShader(
1663 "// bloom shader\n"
1664 "// written by Forest 'LordHavoc' Hale\n"
1665 "\n"
1666 "// common definitions between vertex shader and fragment shader:\n"
1667 "\n"
1668 "#ifdef __GLSL_CG_DATA_TYPES\n"
1669 "#define myhalf half\n"
1670 "#define myhvec2 hvec2\n"
1671 "#define myhvec3 hvec3\n"
1672 "#define myhvec4 hvec4\n"
1673 "#else\n"
1674 "#define myhalf float\n"
1675 "#define myhvec2 vec2\n"
1676 "#define myhvec3 vec3\n"
1677 "#define myhvec4 vec4\n"
1678 "#endif\n"
1679 "\n"
1680 "varying vec2 ScreenTexCoord;\n"
1681 "varying vec2 BloomTexCoord;\n"
1682 "\n"
1683 "\n"
1684 "\n"
1685 "\n"
1686 "// vertex shader specific:\n"
1687 "#ifdef VERTEX_SHADER\n"
1688 "\n"
1689 "void main(void)\n"
1690 "{\n"
1691 "       ScreenTexCoord = vec2(gl_MultiTexCoord0);\n"
1692 "       BloomTexCoord = vec2(gl_MultiTexCoord1);\n"
1693 "       // transform vertex to camera space, using ftransform to match non-VS\n"
1694 "       // rendering\n"
1695 "       gl_Position = ftransform();\n"
1696 "}\n"
1697 "\n"
1698 "#endif // VERTEX_SHADER\n"
1699 "\n"
1700 "\n"
1701 "\n"
1702 "\n"
1703 "// fragment shader specific:\n"
1704 "#ifdef FRAGMENT_SHADER\n"
1705 "\n"
1706 "void main(void)\n"
1707 "{\n"
1708 "       int x, y;
1709 "       myhvec3 color = myhvec3(texture2D(Texture_Screen, ScreenTexCoord));\n"
1710 "       for (x = -BLUR_X;x <= BLUR_X;x++)
1711 "       color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
1712 "       color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
1713 "       color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
1714 "       color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
1715
1716 "       gl_FragColor = vec4(color);\n"
1717 "}\n"
1718 "\n"
1719 "#endif // FRAGMENT_SHADER\n"
1720 */
1721
1722 void R_RenderScene(void);
1723
1724 void R_Bloom_StartFrame(void)
1725 {
1726         int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight;
1727
1728         // set bloomwidth and bloomheight to the bloom resolution that will be
1729         // used (often less than the screen resolution for faster rendering)
1730         r_bloomstate.bloomwidth = bound(1, r_bloom_resolution.integer, r_view.width);
1731         r_bloomstate.bloomheight = r_bloomstate.bloomwidth * r_view.height / r_view.width;
1732         r_bloomstate.bloomheight = bound(1, r_bloomstate.bloomheight, r_view.height);
1733
1734         // calculate desired texture sizes
1735         if (gl_support_arb_texture_non_power_of_two)
1736         {
1737                 screentexturewidth = r_view.width;
1738                 screentextureheight = r_view.height;
1739                 bloomtexturewidth = r_bloomstate.bloomwidth;
1740                 bloomtextureheight = r_bloomstate.bloomheight;
1741         }
1742         else
1743         {
1744                 for (screentexturewidth  = 1;screentexturewidth  < vid.width               ;screentexturewidth  *= 2);
1745                 for (screentextureheight = 1;screentextureheight < vid.height              ;screentextureheight *= 2);
1746                 for (bloomtexturewidth   = 1;bloomtexturewidth   < r_bloomstate.bloomwidth ;bloomtexturewidth   *= 2);
1747                 for (bloomtextureheight  = 1;bloomtextureheight  < r_bloomstate.bloomheight;bloomtextureheight  *= 2);
1748         }
1749
1750         if (r_hdr.integer)
1751         {
1752                 screentexturewidth = screentextureheight = 0;
1753         }
1754         else if (r_bloom.integer)
1755         {
1756         }
1757         else
1758         {
1759                 screentexturewidth = screentextureheight = 0;
1760                 bloomtexturewidth = bloomtextureheight = 0;
1761         }
1762
1763         if ((!bloomtexturewidth && !bloomtextureheight) || r_bloom_resolution.integer < 4 || r_bloom_blur.value < 1 || r_bloom_blur.value >= 512 || screentexturewidth > gl_max_texture_size || screentextureheight > gl_max_texture_size || bloomtexturewidth > gl_max_texture_size || bloomtextureheight > gl_max_texture_size)
1764         {
1765                 // can't use bloom if the parameters are too weird
1766                 // can't use bloom if the card does not support the texture size
1767                 if (r_bloomstate.texture_screen)
1768                         R_FreeTexture(r_bloomstate.texture_screen);
1769                 if (r_bloomstate.texture_bloom)
1770                         R_FreeTexture(r_bloomstate.texture_bloom);
1771                 memset(&r_bloomstate, 0, sizeof(r_bloomstate));
1772                 return;
1773         }
1774
1775         r_bloomstate.enabled = true;
1776         r_bloomstate.hdr = r_hdr.integer != 0;
1777
1778         // allocate textures as needed
1779         if (r_bloomstate.screentexturewidth != screentexturewidth || r_bloomstate.screentextureheight != screentextureheight)
1780         {
1781                 if (r_bloomstate.texture_screen)
1782                         R_FreeTexture(r_bloomstate.texture_screen);
1783                 r_bloomstate.texture_screen = NULL;
1784                 r_bloomstate.screentexturewidth = screentexturewidth;
1785                 r_bloomstate.screentextureheight = screentextureheight;
1786                 if (r_bloomstate.screentexturewidth && r_bloomstate.screentextureheight)
1787                         r_bloomstate.texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", r_bloomstate.screentexturewidth, r_bloomstate.screentextureheight, NULL, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
1788         }
1789         if (r_bloomstate.bloomtexturewidth != bloomtexturewidth || r_bloomstate.bloomtextureheight != bloomtextureheight)
1790         {
1791                 if (r_bloomstate.texture_bloom)
1792                         R_FreeTexture(r_bloomstate.texture_bloom);
1793                 r_bloomstate.texture_bloom = NULL;
1794                 r_bloomstate.bloomtexturewidth = bloomtexturewidth;
1795                 r_bloomstate.bloomtextureheight = bloomtextureheight;
1796                 if (r_bloomstate.bloomtexturewidth && r_bloomstate.bloomtextureheight)
1797                         r_bloomstate.texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", r_bloomstate.bloomtexturewidth, r_bloomstate.bloomtextureheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
1798         }
1799
1800         // set up a texcoord array for the full resolution screen image
1801         // (we have to keep this around to copy back during final render)
1802         r_bloomstate.screentexcoord2f[0] = 0;
1803         r_bloomstate.screentexcoord2f[1] = (float)r_view.height / (float)r_bloomstate.screentextureheight;
1804         r_bloomstate.screentexcoord2f[2] = (float)r_view.width / (float)r_bloomstate.screentexturewidth;
1805         r_bloomstate.screentexcoord2f[3] = (float)r_view.height / (float)r_bloomstate.screentextureheight;
1806         r_bloomstate.screentexcoord2f[4] = (float)r_view.width / (float)r_bloomstate.screentexturewidth;
1807         r_bloomstate.screentexcoord2f[5] = 0;
1808         r_bloomstate.screentexcoord2f[6] = 0;
1809         r_bloomstate.screentexcoord2f[7] = 0;
1810
1811         // set up a texcoord array for the reduced resolution bloom image
1812         // (which will be additive blended over the screen image)
1813         r_bloomstate.bloomtexcoord2f[0] = 0;
1814         r_bloomstate.bloomtexcoord2f[1] = (float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
1815         r_bloomstate.bloomtexcoord2f[2] = (float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
1816         r_bloomstate.bloomtexcoord2f[3] = (float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
1817         r_bloomstate.bloomtexcoord2f[4] = (float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
1818         r_bloomstate.bloomtexcoord2f[5] = 0;
1819         r_bloomstate.bloomtexcoord2f[6] = 0;
1820         r_bloomstate.bloomtexcoord2f[7] = 0;
1821 }
1822
1823 void R_Bloom_CopyScreenTexture(float colorscale)
1824 {
1825         r_refdef.stats.bloom++;
1826
1827         R_ResetViewRendering2D();
1828         R_Mesh_VertexPointer(r_screenvertex3f);
1829         R_Mesh_ColorPointer(NULL);
1830         R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f);
1831         R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
1832
1833         // copy view into the screen texture
1834         GL_ActiveTexture(0);
1835         CHECKGLERROR
1836         qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
1837         r_refdef.stats.bloom_copypixels += r_view.width * r_view.height;
1838
1839         // now scale it down to the bloom texture size
1840         CHECKGLERROR
1841         qglViewport(r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
1842         GL_BlendFunc(GL_ONE, GL_ZERO);
1843         GL_Color(colorscale, colorscale, colorscale, 1);
1844         // TODO: optimize with multitexture or GLSL
1845         R_Mesh_Draw(0, 4, 2, polygonelements);
1846         r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
1847
1848         // we now have a bloom image in the framebuffer
1849         // copy it into the bloom image texture for later processing
1850         R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
1851         GL_ActiveTexture(0);
1852         CHECKGLERROR
1853         qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
1854         r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
1855 }
1856
1857 void R_Bloom_CopyHDRTexture(void)
1858 {
1859         R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
1860         GL_ActiveTexture(0);
1861         CHECKGLERROR
1862         qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
1863         r_refdef.stats.bloom_copypixels += r_view.width * r_view.height;
1864 }
1865
1866 void R_Bloom_MakeTexture(void)
1867 {
1868         int x, range, dir;
1869         float xoffset, yoffset, r, brighten;
1870
1871         r_refdef.stats.bloom++;
1872
1873         R_ResetViewRendering2D();
1874         R_Mesh_VertexPointer(r_screenvertex3f);
1875         R_Mesh_ColorPointer(NULL);
1876
1877         // we have a bloom image in the framebuffer
1878         CHECKGLERROR
1879         qglViewport(r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
1880
1881         for (x = 1;x < r_bloom_colorexponent.value;)
1882         {
1883                 x *= 2;
1884                 r = bound(0, r_bloom_colorexponent.value / x, 1);
1885                 GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
1886                 GL_Color(r, r, r, 1);
1887                 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
1888                 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f);
1889                 R_Mesh_Draw(0, 4, 2, polygonelements);
1890                 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
1891
1892                 // copy the vertically blurred bloom view to a texture
1893                 GL_ActiveTexture(0);
1894                 CHECKGLERROR
1895                 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
1896                 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
1897         }
1898
1899         range = r_bloom_blur.integer * r_bloomstate.bloomwidth / 320;
1900         brighten = r_bloom_brighten.value;
1901         if (r_hdr.integer)
1902                 brighten *= r_hdr_range.value;
1903         R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
1904         R_Mesh_TexCoordPointer(0, 2, r_bloomstate.offsettexcoord2f);
1905
1906         for (dir = 0;dir < 2;dir++)
1907         {
1908                 // blend on at multiple vertical offsets to achieve a vertical blur
1909                 // TODO: do offset blends using GLSL
1910                 GL_BlendFunc(GL_ONE, GL_ZERO);
1911                 for (x = -range;x <= range;x++)
1912                 {
1913                         if (!dir){xoffset = 0;yoffset = x;}
1914                         else {xoffset = x;yoffset = 0;}
1915                         xoffset /= (float)r_bloomstate.bloomtexturewidth;
1916                         yoffset /= (float)r_bloomstate.bloomtextureheight;
1917                         // compute a texcoord array with the specified x and y offset
1918                         r_bloomstate.offsettexcoord2f[0] = xoffset+0;
1919                         r_bloomstate.offsettexcoord2f[1] = yoffset+(float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
1920                         r_bloomstate.offsettexcoord2f[2] = xoffset+(float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
1921                         r_bloomstate.offsettexcoord2f[3] = yoffset+(float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
1922                         r_bloomstate.offsettexcoord2f[4] = xoffset+(float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
1923                         r_bloomstate.offsettexcoord2f[5] = yoffset+0;
1924                         r_bloomstate.offsettexcoord2f[6] = xoffset+0;
1925                         r_bloomstate.offsettexcoord2f[7] = yoffset+0;
1926                         // this r value looks like a 'dot' particle, fading sharply to
1927                         // black at the edges
1928                         // (probably not realistic but looks good enough)
1929                         //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
1930                         //r = (dir ? 1.0f : brighten)/(range*2+1);
1931                         r = (dir ? 1.0f : brighten)/(range*2+1)*(1 - x*x/(float)(range*range));
1932                         GL_Color(r, r, r, 1);
1933                         R_Mesh_Draw(0, 4, 2, polygonelements);
1934                         r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
1935                         GL_BlendFunc(GL_ONE, GL_ONE);
1936                 }
1937
1938                 // copy the vertically blurred bloom view to a texture
1939                 GL_ActiveTexture(0);
1940                 CHECKGLERROR
1941                 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
1942                 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
1943         }
1944
1945         // apply subtract last
1946         // (just like it would be in a GLSL shader)
1947         if (r_bloom_colorsubtract.value > 0 && gl_support_ext_blend_subtract)
1948         {
1949                 GL_BlendFunc(GL_ONE, GL_ZERO);
1950                 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
1951                 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f);
1952                 GL_Color(1, 1, 1, 1);
1953                 R_Mesh_Draw(0, 4, 2, polygonelements);
1954                 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
1955
1956                 GL_BlendFunc(GL_ONE, GL_ONE);
1957                 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
1958                 R_Mesh_TexBind(0, R_GetTexture(r_texture_white));
1959                 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f);
1960                 GL_Color(r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, 1);
1961                 R_Mesh_Draw(0, 4, 2, polygonelements);
1962                 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
1963                 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
1964
1965                 // copy the darkened bloom view to a texture
1966                 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
1967                 GL_ActiveTexture(0);
1968                 CHECKGLERROR
1969                 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
1970                 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
1971         }
1972 }
1973
1974 void R_HDR_RenderBloomTexture(void)
1975 {
1976         int oldwidth, oldheight;
1977
1978         oldwidth = r_view.width;
1979         oldheight = r_view.height;
1980         r_view.width = r_bloomstate.bloomwidth;
1981         r_view.height = r_bloomstate.bloomheight;
1982
1983         // TODO: support GL_EXT_framebuffer_object rather than reusing the framebuffer?  it might improve SLI performance.
1984         // TODO: add exposure compensation features
1985         // TODO: add fp16 framebuffer support
1986
1987         r_view.colorscale = r_bloom_colorscale.value * r_hdr_scenebrightness.value;
1988         if (r_hdr.integer)
1989                 r_view.colorscale /= r_hdr_range.value;
1990         R_RenderScene();
1991
1992         R_ResetViewRendering2D();
1993
1994         R_Bloom_CopyHDRTexture();
1995         R_Bloom_MakeTexture();
1996
1997         R_ResetViewRendering3D();
1998
1999         R_ClearScreen();
2000         if (r_timereport_active)
2001                 R_TimeReport("clear");
2002
2003
2004         // restore the view settings
2005         r_view.width = oldwidth;
2006         r_view.height = oldheight;
2007 }
2008
2009 static void R_BlendView(void)
2010 {
2011         if (r_bloomstate.enabled && r_bloomstate.hdr)
2012         {
2013                 // render high dynamic range bloom effect
2014                 // the bloom texture was made earlier this render, so we just need to
2015                 // blend it onto the screen...
2016                 R_ResetViewRendering2D();
2017                 R_Mesh_VertexPointer(r_screenvertex3f);
2018                 R_Mesh_ColorPointer(NULL);
2019                 GL_Color(1, 1, 1, 1);
2020                 GL_BlendFunc(GL_ONE, GL_ONE);
2021                 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2022                 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f);
2023                 R_Mesh_Draw(0, 4, 2, polygonelements);
2024                 r_refdef.stats.bloom_drawpixels += r_view.width * r_view.height;
2025         }
2026         else if (r_bloomstate.enabled)
2027         {
2028                 // render simple bloom effect
2029                 // copy the screen and shrink it and darken it for the bloom process
2030                 R_Bloom_CopyScreenTexture(r_bloom_colorscale.value);
2031                 // make the bloom texture
2032                 R_Bloom_MakeTexture();
2033                 // put the original screen image back in place and blend the bloom
2034                 // texture on it
2035                 R_ResetViewRendering2D();
2036                 R_Mesh_VertexPointer(r_screenvertex3f);
2037                 R_Mesh_ColorPointer(NULL);
2038                 GL_Color(1, 1, 1, 1);
2039                 GL_BlendFunc(GL_ONE, GL_ZERO);
2040                 // do both in one pass if possible
2041                 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2042                 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f);
2043                 if (r_textureunits.integer >= 2 && gl_combine.integer)
2044                 {
2045                         R_Mesh_TexCombine(1, GL_ADD, GL_ADD, 1, 1);
2046                         R_Mesh_TexBind(1, R_GetTexture(r_bloomstate.texture_screen));
2047                         R_Mesh_TexCoordPointer(1, 2, r_bloomstate.screentexcoord2f);
2048                 }
2049                 else
2050                 {
2051                         R_Mesh_Draw(0, 4, 2, polygonelements);
2052                         r_refdef.stats.bloom_drawpixels += r_view.width * r_view.height;
2053                         // now blend on the bloom texture
2054                         GL_BlendFunc(GL_ONE, GL_ONE);
2055                         R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
2056                         R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f);
2057                 }
2058                 R_Mesh_Draw(0, 4, 2, polygonelements);
2059                 r_refdef.stats.bloom_drawpixels += r_view.width * r_view.height;
2060         }
2061         if (r_refdef.viewblend[3] >= (1.0f / 256.0f))
2062         {
2063                 // apply a color tint to the whole view
2064                 R_ResetViewRendering2D();
2065                 R_Mesh_VertexPointer(r_screenvertex3f);
2066                 R_Mesh_ColorPointer(NULL);
2067                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2068                 GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
2069                 R_Mesh_Draw(0, 4, 2, polygonelements);
2070         }
2071 }
2072
2073 void R_RenderScene(void);
2074
2075 matrix4x4_t r_waterscrollmatrix;
2076
2077 void R_UpdateVariables(void)
2078 {
2079         R_Textures_Frame();
2080
2081         r_refdef.farclip = 4096;
2082         if (r_refdef.worldmodel)
2083                 r_refdef.farclip += VectorDistance(r_refdef.worldmodel->normalmins, r_refdef.worldmodel->normalmaxs);
2084         r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
2085
2086         r_refdef.polygonfactor = 0;
2087         r_refdef.polygonoffset = 0;
2088         r_refdef.shadowpolygonfactor = r_refdef.polygonfactor + r_shadow_shadow_polygonfactor.value;
2089         r_refdef.shadowpolygonoffset = r_refdef.polygonoffset + r_shadow_shadow_polygonoffset.value;
2090
2091         r_refdef.rtworld = r_shadow_realtime_world.integer;
2092         r_refdef.rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
2093         r_refdef.rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer && r_dynamic.integer;
2094         r_refdef.rtdlightshadows = r_refdef.rtdlight && (r_refdef.rtworld ? r_shadow_realtime_world_dlightshadows.integer : r_shadow_realtime_dlight_shadows.integer) && gl_stencil;
2095         r_refdef.lightmapintensity = r_refdef.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
2096         if (r_showsurfaces.integer)
2097         {
2098                 r_refdef.rtworld = false;
2099                 r_refdef.rtworldshadows = false;
2100                 r_refdef.rtdlight = false;
2101                 r_refdef.rtdlightshadows = false;
2102                 r_refdef.lightmapintensity = 0;
2103         }
2104
2105         if (gamemode == GAME_NEHAHRA)
2106         {
2107                 if (gl_fogenable.integer)
2108                 {
2109                         r_refdef.oldgl_fogenable = true;
2110                         r_refdef.fog_density = gl_fogdensity.value;
2111                         r_refdef.fog_red = gl_fogred.value;
2112                         r_refdef.fog_green = gl_foggreen.value;
2113                         r_refdef.fog_blue = gl_fogblue.value;
2114                 }
2115                 else if (r_refdef.oldgl_fogenable)
2116                 {
2117                         r_refdef.oldgl_fogenable = false;
2118                         r_refdef.fog_density = 0;
2119                         r_refdef.fog_red = 0;
2120                         r_refdef.fog_green = 0;
2121                         r_refdef.fog_blue = 0;
2122                 }
2123         }
2124         if (r_refdef.fog_density)
2125         {
2126                 r_refdef.fogcolor[0] = bound(0.0f, r_refdef.fog_red  , 1.0f);
2127                 r_refdef.fogcolor[1] = bound(0.0f, r_refdef.fog_green, 1.0f);
2128                 r_refdef.fogcolor[2] = bound(0.0f, r_refdef.fog_blue , 1.0f);
2129         }
2130         if (r_refdef.fog_density)
2131         {
2132                 r_refdef.fogenabled = true;
2133                 // this is the point where the fog reaches 0.9986 alpha, which we
2134                 // consider a good enough cutoff point for the texture
2135                 // (0.9986 * 256 == 255.6)
2136                 r_refdef.fogrange = 400 / r_refdef.fog_density;
2137                 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
2138                 r_refdef.fogtabledistmultiplier = FOGTABLEWIDTH * r_refdef.fograngerecip;
2139                 // fog color was already set
2140         }
2141         else
2142                 r_refdef.fogenabled = false;
2143 }
2144
2145 /*
2146 ================
2147 R_RenderView
2148 ================
2149 */
2150 void R_RenderView(void)
2151 {
2152         if (!r_refdef.entities/* || !r_refdef.worldmodel*/)
2153                 return; //Host_Error ("R_RenderView: NULL worldmodel");
2154
2155         R_Shadow_UpdateWorldLightSelection();
2156
2157         CHECKGLERROR
2158         if (r_timereport_active)
2159                 R_TimeReport("setup");
2160
2161         R_View_Update();
2162         if (r_timereport_active)
2163                 R_TimeReport("visibility");
2164
2165         R_ResetViewRendering3D();
2166
2167         R_ClearScreen();
2168         if (r_timereport_active)
2169                 R_TimeReport("clear");
2170
2171         R_Bloom_StartFrame();
2172
2173         // this produces a bloom texture to be used in R_BlendView() later
2174         if (r_hdr.integer)
2175                 R_HDR_RenderBloomTexture();
2176
2177         r_view.colorscale = r_hdr_scenebrightness.value;
2178         R_RenderScene();
2179
2180         R_BlendView();
2181         if (r_timereport_active)
2182                 R_TimeReport("blendview");
2183
2184         GL_Scissor(0, 0, vid.width, vid.height);
2185         GL_ScissorTest(false);
2186         CHECKGLERROR
2187 }
2188
2189 extern void R_DrawLightningBeams (void);
2190 extern void VM_CL_AddPolygonsToMeshQueue (void);
2191 extern void R_DrawPortals (void);
2192 extern cvar_t cl_locs_show;
2193 static void R_DrawLocs(void);
2194 void R_RenderScene(void)
2195 {
2196         // don't let sound skip if going slow
2197         if (r_refdef.extraupdate)
2198                 S_ExtraUpdate ();
2199
2200         R_ResetViewRendering3D();
2201
2202         R_MeshQueue_BeginScene();
2203
2204         R_SkyStartFrame();
2205
2206         Matrix4x4_CreateTranslate(&r_waterscrollmatrix, sin(r_refdef.time) * 0.025 * r_waterscroll.value, sin(r_refdef.time * 0.8f) * 0.025 * r_waterscroll.value, 0);
2207
2208         if (cl.csqc_vidvars.drawworld)
2209         {
2210                 // don't let sound skip if going slow
2211                 if (r_refdef.extraupdate)
2212                         S_ExtraUpdate ();
2213
2214                 if (r_refdef.worldmodel && r_refdef.worldmodel->DrawSky)
2215                 {
2216                         r_refdef.worldmodel->DrawSky(r_refdef.worldentity);
2217                         if (r_timereport_active)
2218                                 R_TimeReport("worldsky");
2219                 }
2220
2221                 if (R_DrawBrushModelsSky() && r_timereport_active)
2222                         R_TimeReport("bmodelsky");
2223
2224                 if (r_refdef.worldmodel && r_refdef.worldmodel->Draw)
2225                 {
2226                         r_refdef.worldmodel->Draw(r_refdef.worldentity);
2227                         if (r_timereport_active)
2228                                 R_TimeReport("world");
2229                 }
2230         }
2231
2232         // don't let sound skip if going slow
2233         if (r_refdef.extraupdate)
2234                 S_ExtraUpdate ();
2235
2236         R_DrawModels();
2237         if (r_timereport_active)
2238                 R_TimeReport("models");
2239
2240         // don't let sound skip if going slow
2241         if (r_refdef.extraupdate)
2242                 S_ExtraUpdate ();
2243
2244         if (r_shadows.integer > 0 && r_refdef.lightmapintensity > 0)
2245         {
2246                 R_DrawModelShadows();
2247
2248                 R_ResetViewRendering3D();
2249
2250                 // don't let sound skip if going slow
2251                 if (r_refdef.extraupdate)
2252                         S_ExtraUpdate ();
2253         }
2254
2255         R_ShadowVolumeLighting(false);
2256         if (r_timereport_active)
2257                 R_TimeReport("rtlights");
2258
2259         // don't let sound skip if going slow
2260         if (r_refdef.extraupdate)
2261                 S_ExtraUpdate ();
2262
2263         if (cl.csqc_vidvars.drawworld)
2264         {
2265                 R_DrawLightningBeams();
2266                 if (r_timereport_active)
2267                         R_TimeReport("lightning");
2268
2269                 R_DrawParticles();
2270                 if (r_timereport_active)
2271                         R_TimeReport("particles");
2272
2273                 R_DrawExplosions();
2274                 if (r_timereport_active)
2275                         R_TimeReport("explosions");
2276         }
2277
2278         if (gl_support_fragment_shader)
2279         {
2280                 qglUseProgramObjectARB(0);CHECKGLERROR
2281         }
2282         VM_CL_AddPolygonsToMeshQueue();
2283
2284         if (cl_locs_show.integer)
2285         {
2286                 R_DrawLocs();
2287                 if (r_timereport_active)
2288                         R_TimeReport("showlocs");
2289         }
2290
2291         if (r_drawportals.integer)
2292         {
2293                 R_DrawPortals();
2294                 if (r_timereport_active)
2295                         R_TimeReport("portals");
2296         }
2297
2298         if (gl_support_fragment_shader)
2299         {
2300                 qglUseProgramObjectARB(0);CHECKGLERROR
2301         }
2302         R_MeshQueue_RenderTransparent();
2303         if (r_timereport_active)
2304                 R_TimeReport("drawtrans");
2305
2306         if (gl_support_fragment_shader)
2307         {
2308                 qglUseProgramObjectARB(0);CHECKGLERROR
2309         }
2310
2311         if (cl.csqc_vidvars.drawworld)
2312         {
2313                 R_DrawCoronas();
2314                 if (r_timereport_active)
2315                         R_TimeReport("coronas");
2316         }
2317
2318         // don't let sound skip if going slow
2319         if (r_refdef.extraupdate)
2320                 S_ExtraUpdate ();
2321
2322         R_ResetViewRendering2D();
2323 }
2324
2325 /*
2326 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
2327 {
2328         int i;
2329         float *v, *c, f1, f2, diff[3], vertex3f[8*3], color4f[8*4];
2330         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2331         GL_DepthMask(false);
2332         GL_DepthTest(true);
2333         R_Mesh_Matrix(&identitymatrix);
2334
2335         vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2];
2336         vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
2337         vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
2338         vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
2339         vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
2340         vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
2341         vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
2342         vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
2343         R_FillColors(color, 8, cr, cg, cb, ca);
2344         if (r_refdef.fogenabled)
2345         {
2346                 for (i = 0, v = vertex, c = color;i < 8;i++, v += 4, c += 4)
2347                 {
2348                         f2 = VERTEXFOGTABLE(VectorDistance(v, r_view.origin));
2349                         f1 = 1 - f2;
2350                         c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
2351                         c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
2352                         c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
2353                 }
2354         }
2355         R_Mesh_VertexPointer(vertex3f);
2356         R_Mesh_ColorPointer(color);
2357         R_Mesh_ResetTextureState();
2358         R_Mesh_Draw(8, 12);
2359 }
2360 */
2361
2362 int nomodelelements[24] =
2363 {
2364         5, 2, 0,
2365         5, 1, 2,
2366         5, 0, 3,
2367         5, 3, 1,
2368         0, 2, 4,
2369         2, 1, 4,
2370         3, 0, 4,
2371         1, 3, 4
2372 };
2373
2374 float nomodelvertex3f[6*3] =
2375 {
2376         -16,   0,   0,
2377          16,   0,   0,
2378           0, -16,   0,
2379           0,  16,   0,
2380           0,   0, -16,
2381           0,   0,  16
2382 };
2383
2384 float nomodelcolor4f[6*4] =
2385 {
2386         0.0f, 0.0f, 0.5f, 1.0f,
2387         0.0f, 0.0f, 0.5f, 1.0f,
2388         0.0f, 0.5f, 0.0f, 1.0f,
2389         0.0f, 0.5f, 0.0f, 1.0f,
2390         0.5f, 0.0f, 0.0f, 1.0f,
2391         0.5f, 0.0f, 0.0f, 1.0f
2392 };
2393
2394 void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2395 {
2396         int i;
2397         float f1, f2, *c;
2398         float color4f[6*4];
2399         // this is only called once per entity so numsurfaces is always 1, and
2400         // surfacelist is always {0}, so this code does not handle batches
2401         R_Mesh_Matrix(&ent->matrix);
2402
2403         if (ent->flags & EF_ADDITIVE)
2404         {
2405                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2406                 GL_DepthMask(false);
2407         }
2408         else if (ent->alpha < 1)
2409         {
2410                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2411                 GL_DepthMask(false);
2412         }
2413         else
2414         {
2415                 GL_BlendFunc(GL_ONE, GL_ZERO);
2416                 GL_DepthMask(true);
2417         }
2418         GL_DepthTest(!(ent->effects & EF_NODEPTHTEST));
2419         GL_CullFace((ent->effects & EF_DOUBLESIDED) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
2420         R_Mesh_VertexPointer(nomodelvertex3f);
2421         if (r_refdef.fogenabled)
2422         {
2423                 vec3_t org;
2424                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
2425                 R_Mesh_ColorPointer(color4f);
2426                 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2427                 f2 = VERTEXFOGTABLE(VectorDistance(org, r_view.origin));
2428                 f1 = 1 - f2;
2429                 for (i = 0, c = color4f;i < 6;i++, c += 4)
2430                 {
2431                         c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
2432                         c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
2433                         c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
2434                         c[3] *= ent->alpha;
2435                 }
2436         }
2437         else if (ent->alpha != 1)
2438         {
2439                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
2440                 R_Mesh_ColorPointer(color4f);
2441                 for (i = 0, c = color4f;i < 6;i++, c += 4)
2442                         c[3] *= ent->alpha;
2443         }
2444         else
2445                 R_Mesh_ColorPointer(nomodelcolor4f);
2446         R_Mesh_ResetTextureState();
2447         R_Mesh_Draw(0, 6, 8, nomodelelements);
2448 }
2449
2450 void R_DrawNoModel(entity_render_t *ent)
2451 {
2452         vec3_t org;
2453         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2454         //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
2455                 R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_view.origin : org, R_DrawNoModel_TransparentCallback, ent, 0, r_shadow_rtlight);
2456         //else
2457         //      R_DrawNoModelCallback(ent, 0);
2458 }
2459
2460 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
2461 {
2462         vec3_t right1, right2, diff, normal;
2463
2464         VectorSubtract (org2, org1, normal);
2465
2466         // calculate 'right' vector for start
2467         VectorSubtract (r_view.origin, org1, diff);
2468         CrossProduct (normal, diff, right1);
2469         VectorNormalize (right1);
2470
2471         // calculate 'right' vector for end
2472         VectorSubtract (r_view.origin, org2, diff);
2473         CrossProduct (normal, diff, right2);
2474         VectorNormalize (right2);
2475
2476         vert[ 0] = org1[0] + width * right1[0];
2477         vert[ 1] = org1[1] + width * right1[1];
2478         vert[ 2] = org1[2] + width * right1[2];
2479         vert[ 3] = org1[0] - width * right1[0];
2480         vert[ 4] = org1[1] - width * right1[1];
2481         vert[ 5] = org1[2] - width * right1[2];
2482         vert[ 6] = org2[0] - width * right2[0];
2483         vert[ 7] = org2[1] - width * right2[1];
2484         vert[ 8] = org2[2] - width * right2[2];
2485         vert[ 9] = org2[0] + width * right2[0];
2486         vert[10] = org2[1] + width * right2[1];
2487         vert[11] = org2[2] + width * right2[2];
2488 }
2489
2490 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
2491
2492 void R_DrawSprite(int blendfunc1, int blendfunc2, rtexture_t *texture, rtexture_t *fogtexture, int depthdisable, const vec3_t origin, const vec3_t left, const vec3_t up, float scalex1, float scalex2, float scaley1, float scaley2, float cr, float cg, float cb, float ca)
2493 {
2494         float fog = 0.0f, ifog;
2495         float vertex3f[12];
2496
2497         if (r_refdef.fogenabled)
2498                 fog = VERTEXFOGTABLE(VectorDistance(origin, r_view.origin));
2499         ifog = 1 - fog;
2500
2501         R_Mesh_Matrix(&identitymatrix);
2502         GL_BlendFunc(blendfunc1, blendfunc2);
2503         GL_DepthMask(false);
2504         GL_DepthTest(!depthdisable);
2505
2506         vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
2507         vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
2508         vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
2509         vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
2510         vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
2511         vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
2512         vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
2513         vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
2514         vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
2515         vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
2516         vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
2517         vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
2518
2519         R_Mesh_VertexPointer(vertex3f);
2520         R_Mesh_ColorPointer(NULL);
2521         R_Mesh_ResetTextureState();
2522         R_Mesh_TexBind(0, R_GetTexture(texture));
2523         R_Mesh_TexCoordPointer(0, 2, spritetexcoord2f);
2524         // FIXME: fixed function path can't properly handle r_view.colorscale > 1
2525         GL_Color(cr * ifog * r_view.colorscale, cg * ifog * r_view.colorscale, cb * ifog * r_view.colorscale, ca);
2526         R_Mesh_Draw(0, 4, 2, polygonelements);
2527
2528         if (blendfunc2 == GL_ONE_MINUS_SRC_ALPHA)
2529         {
2530                 R_Mesh_TexBind(0, R_GetTexture(fogtexture));
2531                 GL_BlendFunc(blendfunc1, GL_ONE);
2532                 GL_Color(r_refdef.fogcolor[0] * fog * r_view.colorscale, r_refdef.fogcolor[1] * fog * r_view.colorscale, r_refdef.fogcolor[2] * fog * r_view.colorscale, ca);
2533                 R_Mesh_Draw(0, 4, 2, polygonelements);
2534         }
2535 }
2536
2537 int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
2538 {
2539         int i;
2540         float *vertex3f;
2541         float v[3];
2542         VectorSet(v, x, y, z);
2543         for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
2544                 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
2545                         break;
2546         if (i == mesh->numvertices)
2547         {
2548                 if (mesh->numvertices < mesh->maxvertices)
2549                 {
2550                         VectorCopy(v, vertex3f);
2551                         mesh->numvertices++;
2552                 }
2553                 return mesh->numvertices;
2554         }
2555         else
2556                 return i;
2557 }
2558
2559 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
2560 {
2561         int i;
2562         int *e, element[3];
2563         element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
2564         element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
2565         e = mesh->element3i + mesh->numtriangles * 3;
2566         for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
2567         {
2568                 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
2569                 if (mesh->numtriangles < mesh->maxtriangles)
2570                 {
2571                         *e++ = element[0];
2572                         *e++ = element[1];
2573                         *e++ = element[2];
2574                         mesh->numtriangles++;
2575                 }
2576                 element[1] = element[2];
2577         }
2578 }
2579
2580 void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
2581 {
2582         int i;
2583         int *e, element[3];
2584         element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
2585         element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
2586         e = mesh->element3i + mesh->numtriangles * 3;
2587         for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
2588         {
2589                 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
2590                 if (mesh->numtriangles < mesh->maxtriangles)
2591                 {
2592                         *e++ = element[0];
2593                         *e++ = element[1];
2594                         *e++ = element[2];
2595                         mesh->numtriangles++;
2596                 }
2597                 element[1] = element[2];
2598         }
2599 }
2600
2601 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
2602 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
2603 {
2604         int planenum, planenum2;
2605         int w;
2606         int tempnumpoints;
2607         mplane_t *plane, *plane2;
2608         double maxdist;
2609         double temppoints[2][256*3];
2610         // figure out how large a bounding box we need to properly compute this brush
2611         maxdist = 0;
2612         for (w = 0;w < numplanes;w++)
2613                 maxdist = max(maxdist, planes[w].dist);
2614         // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
2615         maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
2616         for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
2617         {
2618                 w = 0;
2619                 tempnumpoints = 4;
2620                 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
2621                 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
2622                 {
2623                         if (planenum2 == planenum)
2624                                 continue;
2625                         PolygonD_Divide(tempnumpoints, temppoints[w], plane2->normal[0], plane2->normal[1], plane2->normal[2], plane2->dist, R_MESH_PLANE_DIST_EPSILON, 0, NULL, NULL, 256, temppoints[!w], &tempnumpoints, NULL);
2626                         w = !w;
2627                 }
2628                 if (tempnumpoints < 3)
2629                         continue;
2630                 // generate elements forming a triangle fan for this polygon
2631                 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
2632         }
2633 }
2634
2635 static void R_DrawCollisionBrush(const colbrushf_t *brush)
2636 {
2637         int i;
2638         R_Mesh_VertexPointer(brush->points->v);
2639         i = (int)(((size_t)brush) / sizeof(colbrushf_t));
2640         GL_Color((i & 31) * (1.0f / 32.0f) * r_view.colorscale, ((i >> 5) & 31) * (1.0f / 32.0f) * r_view.colorscale, ((i >> 10) & 31) * (1.0f / 32.0f) * r_view.colorscale, 0.2f);
2641         GL_LockArrays(0, brush->numpoints);
2642         R_Mesh_Draw(0, brush->numpoints, brush->numtriangles, brush->elements);
2643         GL_LockArrays(0, 0);
2644 }
2645
2646 static void R_DrawCollisionSurface(const entity_render_t *ent, const msurface_t *surface)
2647 {
2648         int i;
2649         if (!surface->num_collisiontriangles)
2650                 return;
2651         R_Mesh_VertexPointer(surface->data_collisionvertex3f);
2652         i = (int)(((size_t)surface) / sizeof(msurface_t));
2653         GL_Color((i & 31) * (1.0f / 32.0f) * r_view.colorscale, ((i >> 5) & 31) * (1.0f / 32.0f) * r_view.colorscale, ((i >> 10) & 31) * (1.0f / 32.0f) * r_view.colorscale, 0.2f);
2654         GL_LockArrays(0, surface->num_collisionvertices);
2655         R_Mesh_Draw(0, surface->num_collisionvertices, surface->num_collisiontriangles, surface->data_collisionelement3i);
2656         GL_LockArrays(0, 0);
2657 }
2658
2659 static void R_Texture_AddLayer(texture_t *t, qboolean depthmask, int blendfunc1, int blendfunc2, texturelayertype_t type, rtexture_t *texture, const matrix4x4_t *matrix, float r, float g, float b, float a)
2660 {
2661         texturelayer_t *layer;
2662         layer = t->currentlayers + t->currentnumlayers++;
2663         layer->type = type;
2664         layer->depthmask = depthmask;
2665         layer->blendfunc1 = blendfunc1;
2666         layer->blendfunc2 = blendfunc2;
2667         layer->texture = texture;
2668         layer->texmatrix = *matrix;
2669         layer->color[0] = r * r_view.colorscale;
2670         layer->color[1] = g * r_view.colorscale;
2671         layer->color[2] = b * r_view.colorscale;
2672         layer->color[3] = a;
2673 }
2674
2675 void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t)
2676 {
2677         model_t *model = ent->model;
2678
2679         // switch to an alternate material if this is a q1bsp animated material
2680         {
2681                 texture_t *texture = t;
2682                 int s = ent->skinnum;
2683                 if ((unsigned int)s >= (unsigned int)model->numskins)
2684                         s = 0;
2685                 if (model->skinscenes)
2686                 {
2687                         if (model->skinscenes[s].framecount > 1)
2688                                 s = model->skinscenes[s].firstframe + (unsigned int) (r_refdef.time * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
2689                         else
2690                                 s = model->skinscenes[s].firstframe;
2691                 }
2692                 if (s > 0)
2693                         t = t + s * model->num_surfaces;
2694                 if (t->animated)
2695                 {
2696                         // use an alternate animation if the entity's frame is not 0,
2697                         // and only if the texture has an alternate animation
2698                         if (ent->frame != 0 && t->anim_total[1])
2699                                 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(r_refdef.time * 5.0f) % t->anim_total[1]) : 0];
2700                         else
2701                                 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(r_refdef.time * 5.0f) % t->anim_total[0]) : 0];
2702                 }
2703                 texture->currentframe = t;
2704         }
2705
2706         // pick a new currentskinframe if the material is animated
2707         if (t->numskinframes >= 2)
2708                 t->currentskinframe = t->skinframes + ((int)(t->skinframerate * (cl.time - ent->frame2time)) % t->numskinframes);
2709         if (t->backgroundnumskinframes >= 2)
2710                 t->backgroundcurrentskinframe = t->backgroundskinframes + ((int)(t->backgroundskinframerate * (cl.time - ent->frame2time)) % t->backgroundnumskinframes);
2711
2712         t->currentmaterialflags = t->basematerialflags;
2713         t->currentalpha = ent->alpha;
2714         if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_novis.integer))
2715                 t->currentalpha *= r_wateralpha.value;
2716         if (!(ent->flags & RENDER_LIGHT))
2717                 t->currentmaterialflags |= MATERIALFLAG_FULLBRIGHT;
2718         if (ent->effects & EF_ADDITIVE)
2719                 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT | MATERIALFLAG_NOSHADOW;
2720         else if (t->currentalpha < 1)
2721                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT | MATERIALFLAG_NOSHADOW;
2722         if (ent->effects & EF_DOUBLESIDED)
2723                 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
2724         if (ent->effects & EF_NODEPTHTEST)
2725                 t->currentmaterialflags |= MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_NOSHADOW;
2726         if (t->currentmaterialflags & MATERIALFLAG_WATER && r_waterscroll.value != 0)
2727                 t->currenttexmatrix = r_waterscrollmatrix;
2728         else
2729                 t->currenttexmatrix = identitymatrix;
2730         if (t->backgroundnumskinframes && !(t->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
2731                 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
2732
2733         t->colormapping = VectorLength2(ent->colormap_pantscolor) + VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f);
2734         t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
2735         t->glosstexture = r_texture_white;
2736         t->backgroundbasetexture = t->backgroundnumskinframes ? ((!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base) : r_texture_white;
2737         t->backgroundglosstexture = r_texture_white;
2738         t->specularpower = r_shadow_glossexponent.value;
2739         t->specularscale = 0;
2740         if (r_shadow_gloss.integer > 0)
2741         {
2742                 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
2743                 {
2744                         if (r_shadow_glossintensity.value > 0)
2745                         {
2746                                 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_black;
2747                                 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_black;
2748                                 t->specularscale = r_shadow_glossintensity.value;
2749                         }
2750                 }
2751                 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
2752                         t->specularscale = r_shadow_gloss2intensity.value;
2753         }
2754
2755         t->currentnumlayers = 0;
2756         if (!(t->currentmaterialflags & MATERIALFLAG_NODRAW))
2757         {
2758                 if (gl_lightmaps.integer)
2759                         R_Texture_AddLayer(t, true, GL_ONE, GL_ZERO, TEXTURELAYERTYPE_LITTEXTURE, r_texture_white, &identitymatrix, 1, 1, 1, 1);
2760                 else if (!(t->currentmaterialflags & MATERIALFLAG_SKY))
2761                 {
2762                         int blendfunc1, blendfunc2, depthmask;
2763                         if (t->currentmaterialflags & MATERIALFLAG_ADD)
2764                         {
2765                                 blendfunc1 = GL_SRC_ALPHA;
2766                                 blendfunc2 = GL_ONE;
2767                         }
2768                         else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
2769                         {
2770                                 blendfunc1 = GL_SRC_ALPHA;
2771                                 blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
2772                         }
2773                         else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
2774                         {
2775                                 blendfunc1 = t->customblendfunc[0];
2776                                 blendfunc2 = t->customblendfunc[1];
2777                         }
2778                         else
2779                         {
2780                                 blendfunc1 = GL_ONE;
2781                                 blendfunc2 = GL_ZERO;
2782                         }
2783                         depthmask = !(t->currentmaterialflags & MATERIALFLAG_BLENDED);
2784                         if (t->currentmaterialflags & (MATERIALFLAG_WATER | MATERIALFLAG_WALL))
2785                         {
2786                                 rtexture_t *currentbasetexture;
2787                                 int layerflags = 0;
2788                                 if (r_refdef.fogenabled && (t->currentmaterialflags & MATERIALFLAG_BLENDED))
2789                                         layerflags |= TEXTURELAYERFLAG_FOGDARKEN;
2790                                 currentbasetexture = (VectorLength2(ent->colormap_pantscolor) + VectorLength2(ent->colormap_shirtcolor) < (1.0f / 1048576.0f) && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
2791                                 if (t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
2792                                 {
2793                                         // fullbright is not affected by r_refdef.lightmapintensity
2794                                         R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_TEXTURE, currentbasetexture, &t->currenttexmatrix, ent->colormod[0], ent->colormod[1], ent->colormod[2], t->currentalpha);
2795                                         if (VectorLength2(ent->colormap_pantscolor) >= (1.0f / 1048576.0f) && t->currentskinframe->pants)
2796                                                 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->pants, &t->currenttexmatrix, ent->colormap_pantscolor[0] * ent->colormod[0], ent->colormap_pantscolor[1] * ent->colormod[1], ent->colormap_pantscolor[2] * ent->colormod[2], t->currentalpha);
2797                                         if (VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->currentskinframe->shirt)
2798                                                 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->shirt, &t->currenttexmatrix, ent->colormap_shirtcolor[0] * ent->colormod[0], ent->colormap_shirtcolor[1] * ent->colormod[1], ent->colormap_shirtcolor[2] * ent->colormod[2], t->currentalpha);
2799                                 }
2800                                 else
2801                                 {
2802                                         float colorscale;
2803                                         colorscale = 2;
2804                                         // q3bsp has no lightmap updates, so the lightstylevalue that
2805                                         // would normally be baked into the lightmap must be
2806                                         // applied to the color
2807                                         if (ent->model->type == mod_brushq3)
2808                                                 colorscale *= r_refdef.lightstylevalue[0] * (1.0f / 256.0f);
2809                                         colorscale *= r_refdef.lightmapintensity;
2810                                         R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE, currentbasetexture, &t->currenttexmatrix, ent->colormod[0] * colorscale, ent->colormod[1] * colorscale, ent->colormod[2] * colorscale, t->currentalpha);
2811                                         if (r_ambient.value >= (1.0f/64.0f))
2812                                                 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, currentbasetexture, &t->currenttexmatrix, ent->colormod[0] * r_ambient.value * (1.0f / 64.0f), ent->colormod[1] * r_ambient.value * (1.0f / 64.0f), ent->colormod[2] * r_ambient.value * (1.0f / 64.0f), t->currentalpha);
2813                                         if (VectorLength2(ent->colormap_pantscolor) >= (1.0f / 1048576.0f) && t->currentskinframe->pants)
2814                                         {
2815                                                 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->currentskinframe->pants, &t->currenttexmatrix, ent->colormap_pantscolor[0] * ent->colormod[0] * colorscale, ent->colormap_pantscolor[1] * ent->colormod[1] * colorscale, ent->colormap_pantscolor[2]  * ent->colormod[2] * colorscale, t->currentalpha);
2816                                                 if (r_ambient.value >= (1.0f/64.0f))
2817                                                         R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->pants, &t->currenttexmatrix, ent->colormap_pantscolor[0] * ent->colormod[0] * r_ambient.value * (1.0f / 64.0f), ent->colormap_pantscolor[1] * ent->colormod[1] * r_ambient.value * (1.0f / 64.0f), ent->colormap_pantscolor[2] * ent->colormod[2] * r_ambient.value * (1.0f / 64.0f), t->currentalpha);
2818                                         }
2819                                         if (VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->currentskinframe->shirt)
2820                                         {
2821                                                 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->currentskinframe->shirt, &t->currenttexmatrix, ent->colormap_shirtcolor[0] * ent->colormod[0] * colorscale, ent->colormap_shirtcolor[1] * ent->colormod[1] * colorscale, ent->colormap_shirtcolor[2] * ent->colormod[2] * colorscale, t->currentalpha);
2822                                                 if (r_ambient.value >= (1.0f/64.0f))
2823                                                         R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->shirt, &t->currenttexmatrix, ent->colormap_shirtcolor[0] * ent->colormod[0] * r_ambient.value * (1.0f / 64.0f), ent->colormap_shirtcolor[1] * ent->colormod[1] * r_ambient.value * (1.0f / 64.0f), ent->colormap_shirtcolor[2] * ent->colormod[2] * r_ambient.value * (1.0f / 64.0f), t->currentalpha);
2824                                         }
2825                                 }
2826                                 if (t->currentskinframe->glow != NULL)
2827                                         R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->glow, &t->currenttexmatrix, r_hdr_glowintensity.value, r_hdr_glowintensity.value, r_hdr_glowintensity.value, t->currentalpha);
2828                                 if (r_refdef.fogenabled && !(t->currentmaterialflags & MATERIALFLAG_ADD))
2829                                 {
2830                                         // if this is opaque use alpha blend which will darken the earlier
2831                                         // passes cheaply.
2832                                         //
2833                                         // if this is an alpha blended material, all the earlier passes
2834                                         // were darkened by fog already, so we only need to add the fog
2835                                         // color ontop through the fog mask texture
2836                                         //
2837                                         // if this is an additive blended material, all the earlier passes
2838                                         // were darkened by fog already, and we should not add fog color
2839                                         // (because the background was not darkened, there is no fog color
2840                                         // that was lost behind it).
2841                                         R_Texture_AddLayer(t, false, GL_SRC_ALPHA, (t->currentmaterialflags & MATERIALFLAG_BLENDED) ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA, TEXTURELAYERTYPE_FOG, t->currentskinframe->fog, &identitymatrix, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], t->currentalpha);
2842                                 }
2843                         }
2844                 }
2845         }
2846 }
2847
2848 void R_UpdateAllTextureInfo(entity_render_t *ent)
2849 {
2850         int i;
2851         if (ent->model)
2852                 for (i = 0;i < ent->model->num_textures;i++)
2853                         R_UpdateTextureInfo(ent, ent->model->data_textures + i);
2854 }
2855
2856 int rsurface_array_size = 0;
2857 float *rsurface_array_modelvertex3f = NULL;
2858 float *rsurface_array_modelsvector3f = NULL;
2859 float *rsurface_array_modeltvector3f = NULL;
2860 float *rsurface_array_modelnormal3f = NULL;
2861 float *rsurface_array_deformedvertex3f = NULL;
2862 float *rsurface_array_deformedsvector3f = NULL;
2863 float *rsurface_array_deformedtvector3f = NULL;
2864 float *rsurface_array_deformednormal3f = NULL;
2865 float *rsurface_array_color4f = NULL;
2866 float *rsurface_array_texcoord3f = NULL;
2867
2868 void R_Mesh_ResizeArrays(int newvertices)
2869 {
2870         float *base;
2871         if (rsurface_array_size >= newvertices)
2872                 return;
2873         if (rsurface_array_modelvertex3f)
2874                 Mem_Free(rsurface_array_modelvertex3f);
2875         rsurface_array_size = (newvertices + 1023) & ~1023;
2876         base = (float *)Mem_Alloc(r_main_mempool, rsurface_array_size * sizeof(float[31]));
2877         rsurface_array_modelvertex3f     = base + rsurface_array_size * 0;
2878         rsurface_array_modelsvector3f    = base + rsurface_array_size * 3;
2879         rsurface_array_modeltvector3f    = base + rsurface_array_size * 6;
2880         rsurface_array_modelnormal3f     = base + rsurface_array_size * 9;
2881         rsurface_array_deformedvertex3f  = base + rsurface_array_size * 12;
2882         rsurface_array_deformedsvector3f = base + rsurface_array_size * 15;
2883         rsurface_array_deformedtvector3f = base + rsurface_array_size * 18;
2884         rsurface_array_deformednormal3f  = base + rsurface_array_size * 21;
2885         rsurface_array_texcoord3f        = base + rsurface_array_size * 24;
2886         rsurface_array_color4f           = base + rsurface_array_size * 27;
2887 }
2888
2889 float *rsurface_modelvertex3f;
2890 float *rsurface_modelsvector3f;
2891 float *rsurface_modeltvector3f;
2892 float *rsurface_modelnormal3f;
2893 float *rsurface_vertex3f;
2894 float *rsurface_svector3f;
2895 float *rsurface_tvector3f;
2896 float *rsurface_normal3f;
2897 float *rsurface_lightmapcolor4f;
2898 vec3_t rsurface_modelorg;
2899 qboolean rsurface_generatedvertex;
2900 const entity_render_t *rsurface_entity;
2901 const model_t *rsurface_model;
2902 texture_t *rsurface_texture;
2903 qboolean rsurface_uselightmaptexture;
2904 rsurfmode_t rsurface_mode;
2905 int rsurface_lightmode; // 0 = lightmap or fullbright, 1 = color array from q3bsp, 2 = vertex shaded model
2906
2907 void RSurf_CleanUp(void)
2908 {
2909         CHECKGLERROR
2910         if (rsurface_mode == RSURFMODE_GLSL)
2911         {
2912                 qglUseProgramObjectARB(0);CHECKGLERROR
2913         }
2914         GL_AlphaTest(false);
2915         rsurface_mode = RSURFMODE_NONE;
2916         rsurface_uselightmaptexture = false;
2917         rsurface_texture = NULL;
2918 }
2919
2920 void RSurf_ActiveWorldEntity(void)
2921 {
2922         RSurf_CleanUp();
2923         rsurface_entity = r_refdef.worldentity;
2924         rsurface_model = r_refdef.worldmodel;
2925         if (rsurface_array_size < rsurface_model->surfmesh.num_vertices)
2926                 R_Mesh_ResizeArrays(rsurface_model->surfmesh.num_vertices);
2927         R_Mesh_Matrix(&identitymatrix);
2928         VectorCopy(r_view.origin, rsurface_modelorg);
2929         rsurface_modelvertex3f  = rsurface_model->surfmesh.data_vertex3f;
2930         rsurface_modelsvector3f = rsurface_model->surfmesh.data_svector3f;
2931         rsurface_modeltvector3f = rsurface_model->surfmesh.data_tvector3f;
2932         rsurface_modelnormal3f  = rsurface_model->surfmesh.data_normal3f;
2933         rsurface_generatedvertex = false;
2934         rsurface_vertex3f  = rsurface_modelvertex3f;
2935         rsurface_svector3f = rsurface_modelsvector3f;
2936         rsurface_tvector3f = rsurface_modeltvector3f;
2937         rsurface_normal3f  = rsurface_modelnormal3f;
2938 }
2939
2940 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
2941 {
2942         RSurf_CleanUp();
2943         rsurface_entity = ent;
2944         rsurface_model = ent->model;
2945         if (rsurface_array_size < rsurface_model->surfmesh.num_vertices)
2946                 R_Mesh_ResizeArrays(rsurface_model->surfmesh.num_vertices);
2947         R_Mesh_Matrix(&ent->matrix);
2948         Matrix4x4_Transform(&ent->inversematrix, r_view.origin, rsurface_modelorg);
2949         if (rsurface_model->surfmesh.isanimated && (rsurface_entity->frameblend[0].lerp != 1 || rsurface_entity->frameblend[0].frame != 0))
2950         {
2951                 if (wanttangents)
2952                 {
2953                         rsurface_modelvertex3f = rsurface_array_modelvertex3f;
2954                         rsurface_modelsvector3f = rsurface_array_modelsvector3f;
2955                         rsurface_modeltvector3f = rsurface_array_modeltvector3f;
2956                         rsurface_modelnormal3f = rsurface_array_modelnormal3f;
2957                         Mod_Alias_GetMesh_Vertices(rsurface_model, rsurface_entity->frameblend, rsurface_array_modelvertex3f, rsurface_array_modelnormal3f, rsurface_array_modelsvector3f, rsurface_array_modeltvector3f);
2958                 }
2959                 else if (wantnormals)
2960                 {
2961                         rsurface_modelvertex3f = rsurface_array_modelvertex3f;
2962                         rsurface_modelsvector3f = NULL;
2963                         rsurface_modeltvector3f = NULL;
2964                         rsurface_modelnormal3f = rsurface_array_modelnormal3f;
2965                         Mod_Alias_GetMesh_Vertices(rsurface_model, rsurface_entity->frameblend, rsurface_array_modelvertex3f, rsurface_array_modelnormal3f, NULL, NULL);
2966                 }
2967                 else
2968                 {
2969                         rsurface_modelvertex3f = rsurface_array_modelvertex3f;
2970                         rsurface_modelsvector3f = NULL;
2971                         rsurface_modeltvector3f = NULL;
2972                         rsurface_modelnormal3f = NULL;
2973                         Mod_Alias_GetMesh_Vertices(rsurface_model, rsurface_entity->frameblend, rsurface_array_modelvertex3f, NULL, NULL, NULL);
2974                 }
2975                 rsurface_generatedvertex = true;
2976         }
2977         else
2978         {
2979                 rsurface_modelvertex3f  = rsurface_model->surfmesh.data_vertex3f;
2980                 rsurface_modelsvector3f = rsurface_model->surfmesh.data_svector3f;
2981                 rsurface_modeltvector3f = rsurface_model->surfmesh.data_tvector3f;
2982                 rsurface_modelnormal3f  = rsurface_model->surfmesh.data_normal3f;
2983                 rsurface_generatedvertex = false;
2984         }
2985         rsurface_vertex3f  = rsurface_modelvertex3f;
2986         rsurface_svector3f = rsurface_modelsvector3f;
2987         rsurface_tvector3f = rsurface_modeltvector3f;
2988         rsurface_normal3f  = rsurface_modelnormal3f;
2989 }
2990
2991 void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generatetangents, int texturenumsurfaces, msurface_t **texturesurfacelist)
2992 {
2993         // if vertices are dynamic (animated models), generate them into the temporary rsurface_array_model* arrays and point rsurface_model* at them instead of the static data from the model itself
2994         if (rsurface_generatedvertex)
2995         {
2996                 if (rsurface_texture->textureflags & (Q3TEXTUREFLAG_AUTOSPRITE | Q3TEXTUREFLAG_AUTOSPRITE2))
2997                         generatetangents = true;
2998                 if (generatetangents)
2999                         generatenormals = true;
3000                 if (generatenormals && !rsurface_modelnormal3f)
3001                 {
3002                         rsurface_normal3f = rsurface_modelnormal3f = rsurface_array_modelnormal3f;
3003                         Mod_BuildNormals(0, rsurface_model->surfmesh.num_vertices, rsurface_model->surfmesh.num_triangles, rsurface_modelvertex3f, rsurface_model->surfmesh.data_element3i, rsurface_array_modelnormal3f, r_smoothnormals_areaweighting.integer);
3004                 }
3005                 if (generatetangents && !rsurface_modelsvector3f)
3006                 {
3007                         rsurface_svector3f = rsurface_modelsvector3f = rsurface_array_modelsvector3f;
3008                         rsurface_tvector3f = rsurface_modeltvector3f = rsurface_array_modeltvector3f;
3009                         Mod_BuildTextureVectorsFromNormals(0, rsurface_model->surfmesh.num_vertices, rsurface_model->surfmesh.num_triangles, rsurface_modelvertex3f, rsurface_model->surfmesh.data_texcoordtexture2f, rsurface_modelnormal3f, rsurface_model->surfmesh.data_element3i, rsurface_array_modelsvector3f, rsurface_array_modeltvector3f, r_smoothnormals_areaweighting.integer);
3010                 }
3011         }
3012         // if vertices are deformed (sprite flares and things in maps, possibly water waves, bulges and other deformations), generate them into rsurface_deform* arrays from whatever the rsurface_model* array pointers point to (may be static model data or generated data for an animated model)
3013         if (rsurface_texture->textureflags & (Q3TEXTUREFLAG_AUTOSPRITE | Q3TEXTUREFLAG_AUTOSPRITE2))
3014         {
3015                 int texturesurfaceindex;
3016                 float center[3], forward[3], right[3], up[3], v[4][3];
3017                 matrix4x4_t matrix1, imatrix1;
3018                 Matrix4x4_Transform(&rsurface_entity->inversematrix, r_view.forward, forward);
3019                 Matrix4x4_Transform(&rsurface_entity->inversematrix, r_view.right, right);
3020                 Matrix4x4_Transform(&rsurface_entity->inversematrix, r_view.up, up);
3021                 // make deformed versions of only the model vertices used by the specified surfaces
3022                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
3023                 {
3024                         int i, j;
3025                         const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
3026                         // a single autosprite surface can contain multiple sprites...
3027                         for (j = 0;j < surface->num_vertices - 3;j += 4)
3028                         {
3029                                 VectorClear(center);
3030                                 for (i = 0;i < 4;i++)
3031                                         VectorAdd(center, (rsurface_modelvertex3f + 3 * surface->num_firstvertex) + (j+i) * 3, center);
3032                                 VectorScale(center, 0.25f, center);
3033                                 if (rsurface_texture->textureflags & Q3TEXTUREFLAG_AUTOSPRITE2)
3034                                 {
3035                                         forward[0] = rsurface_modelorg[0] - center[0];
3036                                         forward[1] = rsurface_modelorg[1] - center[1];
3037                                         forward[2] = 0;
3038                                         VectorNormalize(forward);
3039                                         right[0] = forward[1];
3040                                         right[1] = -forward[0];
3041                                         right[2] = 0;
3042                                         VectorSet(up, 0, 0, 1);
3043                                 }
3044                                 // FIXME: calculate vectors from triangle edges instead of using texture vectors as an easy way out?
3045                                 Matrix4x4_FromVectors(&matrix1, (rsurface_modelnormal3f + 3 * surface->num_firstvertex) + j*3, (rsurface_modelsvector3f + 3 * surface->num_firstvertex) + j*3, (rsurface_modeltvector3f + 3 * surface->num_firstvertex) + j*3, center);
3046                                 Matrix4x4_Invert_Simple(&imatrix1, &matrix1);
3047                                 for (i = 0;i < 4;i++)
3048                                         Matrix4x4_Transform(&imatrix1, (rsurface_modelvertex3f + 3 * surface->num_firstvertex) + (j+i)*3, v[i]);
3049                                 for (i = 0;i < 4;i++)
3050                                         VectorMAMAMAM(1, center, v[i][0], forward, v[i][1], right, v[i][2], up, rsurface_array_deformedvertex3f + (surface->num_firstvertex+i+j) * 3);
3051                         }
3052                         Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface_modelvertex3f, rsurface_model->surfmesh.data_element3i + surface->num_firsttriangle * 3, rsurface_array_deformednormal3f, r_smoothnormals_areaweighting.integer);
3053                         Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface_modelvertex3f, rsurface_model->surfmesh.data_texcoordtexture2f, rsurface_array_deformednormal3f, rsurface_model->surfmesh.data_element3i + surface->num_firsttriangle * 3, rsurface_array_deformedsvector3f, rsurface_array_deformedtvector3f, r_smoothnormals_areaweighting.integer);
3054                 }
3055                 rsurface_vertex3f = rsurface_array_deformedvertex3f;
3056                 rsurface_svector3f = rsurface_array_deformedsvector3f;
3057                 rsurface_tvector3f = rsurface_array_deformedtvector3f;
3058                 rsurface_normal3f = rsurface_array_deformednormal3f;
3059         }
3060         else
3061         {
3062                 rsurface_vertex3f = rsurface_modelvertex3f;
3063                 rsurface_svector3f = rsurface_modelsvector3f;
3064                 rsurface_tvector3f = rsurface_modeltvector3f;
3065                 rsurface_normal3f = rsurface_modelnormal3f;
3066         }
3067         R_Mesh_VertexPointer(rsurface_vertex3f);
3068 }
3069
3070 void RSurf_DrawBatch_Simple(int texturenumsurfaces, msurface_t **texturesurfacelist)
3071 {
3072         int i, j;
3073         const msurface_t *surface = texturesurfacelist[0];
3074         const msurface_t *surface2;
3075         int firstvertex;
3076         int endvertex;
3077         int numvertices;
3078         int numtriangles;
3079         // TODO: lock all array ranges before render, rather than on each surface
3080         if (texturenumsurfaces == 1)
3081         {
3082                 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
3083                 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
3084         }
3085         else if (r_batchmode.integer == 2)
3086         {
3087                 #define MAXBATCHTRIANGLES 4096
3088                 int batchtriangles = 0;
3089                 int batchelements[MAXBATCHTRIANGLES*3];
3090                 for (i = 0;i < texturenumsurfaces;i = j)
3091                 {
3092                         surface = texturesurfacelist[i];
3093                         j = i + 1;
3094                         if (surface->num_triangles > MAXBATCHTRIANGLES)
3095                         {
3096                                 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
3097                                 continue;
3098                         }
3099                         memcpy(batchelements, rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle, surface->num_triangles * sizeof(int[3]));
3100                         batchtriangles = surface->num_triangles;
3101                         firstvertex = surface->num_firstvertex;
3102                         endvertex = surface->num_firstvertex + surface->num_vertices;
3103                         for (;j < texturenumsurfaces;j++)
3104                         {
3105                                 surface2 = texturesurfacelist[j];
3106                                 if (batchtriangles + surface2->num_triangles > MAXBATCHTRIANGLES)
3107                                         break;
3108                                 memcpy(batchelements + batchtriangles * 3, rsurface_model->surfmesh.data_element3i + 3 * surface2->num_firsttriangle, surface2->num_triangles * sizeof(int[3]));
3109                                 batchtriangles += surface2->num_triangles;
3110                                 firstvertex = min(firstvertex, surface2->num_firstvertex);
3111                                 endvertex = max(endvertex, surface2->num_firstvertex + surface2->num_vertices);
3112                         }
3113                         surface2 = texturesurfacelist[j-1];
3114                         numvertices = endvertex - firstvertex;
3115                         R_Mesh_Draw(firstvertex, numvertices, batchtriangles, batchelements);
3116                 }
3117         }
3118         else if (r_batchmode.integer == 1)
3119         {
3120                 for (i = 0;i < texturenumsurfaces;i = j)
3121                 {
3122                         surface = texturesurfacelist[i];
3123                         for (j = i + 1, surface2 = surface + 1;j < texturenumsurfaces;j++, surface2++)
3124                                 if (texturesurfacelist[j] != surface2)
3125                                         break;
3126                         surface2 = texturesurfacelist[j-1];
3127                         numvertices = surface2->num_firstvertex + surface2->num_vertices - surface->num_firstvertex;
3128                         numtriangles = surface2->num_firsttriangle + surface2->num_triangles - surface->num_firsttriangle;
3129                         GL_LockArrays(surface->num_firstvertex, numvertices);
3130                         R_Mesh_Draw(surface->num_firstvertex, numvertices, numtriangles, (rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
3131                 }
3132         }
3133         else
3134         {
3135                 for (i = 0;i < texturenumsurfaces;i++)
3136                 {
3137                         surface = texturesurfacelist[i];
3138                         GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
3139                         R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
3140                 }
3141         }
3142 }
3143
3144 static void RSurf_DrawBatch_WithLightmapSwitching(int texturenumsurfaces, msurface_t **texturesurfacelist, int lightmaptexunit, int deluxemaptexunit)
3145 {
3146         int i;
3147         int j;
3148         const msurface_t *surface = texturesurfacelist[0];
3149         const msurface_t *surface2;
3150         int firstvertex;
3151         int endvertex;
3152         int numvertices;
3153         int numtriangles;
3154         // TODO: lock all array ranges before render, rather than on each surface
3155         if (texturenumsurfaces == 1)
3156         {
3157                 R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
3158                 if (deluxemaptexunit >= 0)
3159                         R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
3160                 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
3161                 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
3162         }
3163         else if (r_batchmode.integer == 2)
3164         {
3165                 #define MAXBATCHTRIANGLES 4096
3166                 int batchtriangles = 0;
3167                 int batchelements[MAXBATCHTRIANGLES*3];
3168                 for (i = 0;i < texturenumsurfaces;i = j)
3169                 {
3170                         surface = texturesurfacelist[i];
3171                         R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
3172                         if (deluxemaptexunit >= 0)
3173                                 R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
3174                         j = i + 1;
3175                         if (surface->num_triangles > MAXBATCHTRIANGLES)
3176                         {
3177                                 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
3178                                 continue;
3179                         }
3180                         memcpy(batchelements, rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle, surface->num_triangles * sizeof(int[3]));
3181                         batchtriangles = surface->num_triangles;
3182                         firstvertex = surface->num_firstvertex;
3183                         endvertex = surface->num_firstvertex + surface->num_vertices;
3184                         for (;j < texturenumsurfaces;j++)
3185                         {
3186                                 surface2 = texturesurfacelist[j];
3187                                 if (surface2->lightmaptexture != surface->lightmaptexture || batchtriangles + surface2->num_triangles > MAXBATCHTRIANGLES)
3188                                         break;
3189                                 memcpy(batchelements + batchtriangles * 3, rsurface_model->surfmesh.data_element3i + 3 * surface2->num_firsttriangle, surface2->num_triangles * sizeof(int[3]));
3190                                 batchtriangles += surface2->num_triangles;
3191                                 firstvertex = min(firstvertex, surface2->num_firstvertex);
3192                                 endvertex = max(endvertex, surface2->num_firstvertex + surface2->num_vertices);
3193                         }
3194                         surface2 = texturesurfacelist[j-1];
3195                         numvertices = endvertex - firstvertex;
3196                         R_Mesh_Draw(firstvertex, numvertices, batchtriangles, batchelements);
3197                 }
3198         }
3199         else if (r_batchmode.integer == 1)
3200         {
3201 #if 0
3202                 Con_Printf("%s batch sizes ignoring lightmap:", rsurface_texture->name);
3203                 for (i = 0;i < texturenumsurfaces;i = j)
3204                 {
3205                         surface = texturesurfacelist[i];
3206                         for (j = i + 1, surface2 = surface + 1;j < texturenumsurfaces;j++, surface2++)
3207                                 if (texturesurfacelist[j] != surface2)
3208                                         break;
3209                         Con_Printf(" %i", j - i);
3210                 }
3211                 Con_Printf("\n");
3212                 Con_Printf("%s batch sizes honoring lightmap:", rsurface_texture->name);
3213 #endif
3214                 for (i = 0;i < texturenumsurfaces;i = j)
3215                 {
3216                         surface = texturesurfacelist[i];
3217                         R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
3218                         if (deluxemaptexunit >= 0)
3219                                 R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
3220                         for (j = i + 1, surface2 = surface + 1;j < texturenumsurfaces;j++, surface2++)
3221                                 if (texturesurfacelist[j] != surface2 || texturesurfacelist[j]->lightmaptexture != surface->lightmaptexture)
3222                                         break;
3223 #if 0
3224                         Con_Printf(" %i", j - i);
3225 #endif
3226                         surface2 = texturesurfacelist[j-1];
3227                         numvertices = surface2->num_firstvertex + surface2->num_vertices - surface->num_firstvertex;
3228                         numtriangles = surface2->num_firsttriangle + surface2->num_triangles - surface->num_firsttriangle;
3229                         GL_LockArrays(surface->num_firstvertex, numvertices);
3230                         R_Mesh_Draw(surface->num_firstvertex, numvertices, numtriangles, (rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
3231                 }
3232 #if 0
3233                 Con_Printf("\n");
3234 #endif
3235         }
3236         else
3237         {
3238                 for (i = 0;i < texturenumsurfaces;i++)
3239                 {
3240                         surface = texturesurfacelist[i];
3241                         R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
3242                         if (deluxemaptexunit >= 0)
3243                                 R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
3244                         GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
3245                         R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
3246                 }
3247         }
3248 }
3249
3250 static void RSurf_DrawBatch_ShowSurfaces(int texturenumsurfaces, msurface_t **texturesurfacelist)
3251 {
3252         int j;
3253         int texturesurfaceindex;
3254         if (r_showsurfaces.integer == 2)
3255         {
3256                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
3257                 {
3258                         const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
3259                         for (j = 0;j < surface->num_triangles;j++)
3260                         {
3261                                 float f = ((j + surface->num_firsttriangle) & 31) * (1.0f / 31.0f) * r_view.colorscale;
3262                                 GL_Color(f, f, f, 1);
3263                                 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, 1, (rsurface_model->surfmesh.data_element3i + 3 * (j + surface->num_firsttriangle)));
3264                         }
3265                 }
3266         }
3267         else
3268         {
3269                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
3270                 {
3271                         const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
3272                         int k = (int)(((size_t)surface) / sizeof(msurface_t));
3273                         GL_Color((k & 15) * (1.0f / 16.0f) * r_view.colorscale, ((k >> 4) & 15) * (1.0f / 16.0f) * r_view.colorscale, ((k >> 8) & 15) * (1.0f / 16.0f) * r_view.colorscale, 1);
3274                         GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
3275                         R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface_model->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
3276                 }
3277         }
3278 }
3279
3280 static void RSurf_DrawBatch_GL11_ApplyFog(int texturenumsurfaces, msurface_t **texturesurfacelist)
3281 {
3282         int texturesurfaceindex;
3283         int i;
3284         float f;
3285         float *v, *c, *c2;
3286         if (rsurface_lightmapcolor4f)
3287         {
3288                 // generate color arrays for the surfaces in this list
3289                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
3290                 {
3291                         const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
3292                         for (i = 0, v = (rsurface_vertex3f + 3 * surface->num_firstvertex), c = (rsurface_lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (rsurface_array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4, c2 += 4)
3293                         {
3294                                 f = 1 - VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
3295                                 c2[0] = c[0] * f;
3296                                 c2[1] = c[1] * f;
3297                                 c2[2] = c[2] * f;
3298                                 c2[3] = c[3];
3299                         }
3300                 }
3301         }
3302         else
3303         {
3304                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
3305                 {
3306                         const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
3307                         for (i = 0, v = (rsurface_vertex3f + 3 * surface->num_firstvertex), c2 = (rsurface_array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c2 += 4)
3308                         {
3309                                 f = 1 - VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
3310                                 c2[0] = f;
3311                                 c2[1] = f;
3312                                 c2[2] = f;
3313                                 c2[3] = 1;
3314                         }
3315                 }
3316         }
3317         rsurface_lightmapcolor4f = rsurface_array_color4f;
3318 }
3319
3320 static void RSurf_DrawBatch_GL11_ApplyColor(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a)
3321 {
3322         int texturesurfaceindex;
3323         int i;
3324         float *c, *c2;
3325         if (!rsurface_lightmapcolor4f)
3326                 return;
3327         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
3328         {
3329                 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
3330                 for (i = 0, c = (rsurface_lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (rsurface_array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, c += 4, c2 += 4)
3331                 {
3332                         c2[0] = c[0] * r;
3333                         c2[1] = c[1] * g;
3334                         c2[2] = c[2] * b;
3335                         c2[3] = c[3] * a;
3336                 }
3337         }
3338         rsurface_lightmapcolor4f = rsurface_array_color4f;
3339 }
3340
3341 static void RSurf_DrawBatch_GL11_Lightmap(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
3342 {
3343         // TODO: optimize
3344         rsurface_lightmapcolor4f = NULL;
3345         if (applyfog)   RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
3346         if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
3347         R_Mesh_ColorPointer(rsurface_lightmapcolor4f);
3348         GL_Color(r, g, b, a);
3349         RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist, 0, -1);
3350 }
3351
3352 static void RSurf_DrawBatch_GL11_Unlit(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
3353 {
3354         // TODO: optimize applyfog && applycolor case
3355         // just apply fog if necessary, and tint the fog color array if necessary
3356         rsurface_lightmapcolor4f = NULL;
3357         if (applyfog)   RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
3358         if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
3359         R_Mesh_ColorPointer(rsurface_lightmapcolor4f);
3360         GL_Color(r, g, b, a);
3361         RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
3362 }
3363
3364 static void RSurf_DrawBatch_GL11_VertexColor(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
3365 {
3366         int texturesurfaceindex;
3367         int i;
3368         float *c;
3369         // TODO: optimize
3370         if (texturesurfacelist[0]->lightmapinfo && texturesurfacelist[0]->lightmapinfo->stainsamples)
3371         {
3372                 // generate color arrays for the surfaces in this list
3373                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
3374                 {
3375                         const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
3376                         for (i = 0, c = rsurface_array_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
3377                         {
3378                                 if (surface->lightmapinfo->samples)
3379                                 {
3380                                         const unsigned char *lm = surface->lightmapinfo->samples + (rsurface_model->surfmesh.data_lightmapoffsets + surface->num_firstvertex)[i];
3381                                         float scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[0]] * (1.0f / 32768.0f);
3382                                         VectorScale(lm, scale, c);
3383                                         if (surface->lightmapinfo->styles[1] != 255)
3384                                         {
3385                                                 int size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
3386                                                 lm += size3;
3387                                                 scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[1]] * (1.0f / 32768.0f);
3388                                                 VectorMA(c, scale, lm, c);
3389                                                 if (surface->lightmapinfo->styles[2] != 255)
3390                                                 {
3391                                                         lm += size3;
3392                                                         scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[2]] * (1.0f / 32768.0f);
3393                                                         VectorMA(c, scale, lm, c);
3394                                                         if (surface->lightmapinfo->styles[3] != 255)
3395                                                         {
3396                                                                 lm += size3;
3397                                                                 scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[3]] * (1.0f / 32768.0f);
3398                                                                 VectorMA(c, scale, lm, c);
3399                                                         }
3400                                                 }
3401                                         }
3402                                 }
3403                                 else
3404                                         VectorClear(c);
3405                                 c[3] = 1;
3406                         }
3407                 }
3408                 rsurface_lightmapcolor4f = rsurface_array_color4f;
3409         }
3410         else
3411                 rsurface_lightmapcolor4f = rsurface_model->surfmesh.data_lightmapcolor4f;
3412         if (applyfog)   RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
3413         if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
3414         R_Mesh_ColorPointer(rsurface_lightmapcolor4f);
3415         GL_Color(r, g, b, a);
3416         RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
3417 }
3418
3419 static void RSurf_DrawBatch_GL11_VertexShade(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
3420 {
3421         int texturesurfaceindex;
3422         int i;
3423         float f;
3424         float *v, *c, *c2;
3425         vec3_t ambientcolor;
3426         vec3_t diffusecolor;
3427         vec3_t lightdir;
3428         // TODO: optimize
3429         // model lighting
3430         VectorCopy(rsurface_entity->modellight_lightdir, lightdir);
3431         ambientcolor[0] = rsurface_entity->modellight_ambient[0] * r * 0.5f;
3432         ambientcolor[1] = rsurface_entity->modellight_ambient[1] * g * 0.5f;
3433         ambientcolor[2] = rsurface_entity->modellight_ambient[2] * b * 0.5f;
3434         diffusecolor[0] = rsurface_entity->modellight_diffuse[0] * r * 0.5f;
3435         diffusecolor[1] = rsurface_entity->modellight_diffuse[1] * g * 0.5f;
3436         diffusecolor[2] = rsurface_entity->modellight_diffuse[2] * b * 0.5f;
3437         if (VectorLength2(diffusecolor) > 0)
3438         {
3439                 // generate color arrays for the surfaces in this list
3440                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
3441                 {
3442                         const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
3443                         int numverts = surface->num_vertices;
3444                         v = rsurface_vertex3f + 3 * surface->num_firstvertex;
3445                         c2 = rsurface_normal3f + 3 * surface->num_firstvertex;
3446                         c = rsurface_array_color4f + 4 * surface->num_firstvertex;
3447                         // q3-style directional shading
3448                         for (i = 0;i < numverts;i++, v += 3, c2 += 3, c += 4)
3449                         {
3450                                 if ((f = DotProduct(c2, lightdir)) > 0)
3451                                         VectorMA(ambientcolor, f, diffusecolor, c);
3452                                 else
3453                                         VectorCopy(ambientcolor, c);
3454                                 c[3] = a;
3455                         }
3456                 }
3457                 r = 1;
3458                 g = 1;
3459                 b = 1;
3460                 a = 1;
3461                 applycolor = false;
3462                 rsurface_lightmapcolor4f = rsurface_array_color4f;
3463         }
3464         else
3465         {
3466                 r = ambientcolor[0];
3467                 g = ambientcolor[1];
3468                 b = ambientcolor[2];
3469                 rsurface_lightmapcolor4f = NULL;
3470         }
3471         if (applyfog)   RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
3472         if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
3473         R_Mesh_ColorPointer(rsurface_lightmapcolor4f);
3474         GL_Color(r, g, b, a);
3475         RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
3476 }
3477
3478 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, msurface_t **texturesurfacelist)
3479 {
3480         GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
3481         GL_CullFace((rsurface_texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
3482         if (rsurface_mode != RSURFMODE_SHOWSURFACES)
3483         {
3484                 rsurface_mode = RSURFMODE_SHOWSURFACES;
3485                 GL_DepthMask(true);
3486                 GL_BlendFunc(GL_ONE, GL_ZERO);
3487                 R_Mesh_ColorPointer(NULL);
3488                 R_Mesh_ResetTextureState();
3489         }
3490         RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
3491         RSurf_DrawBatch_ShowSurfaces(texturenumsurfaces, texturesurfacelist);
3492 }
3493
3494 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, msurface_t **texturesurfacelist)
3495 {
3496         // transparent sky would be ridiculous
3497         if ((rsurface_texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
3498                 return;
3499         if (rsurface_mode != RSURFMODE_SKY)
3500         {
3501                 if (rsurface_mode == RSURFMODE_GLSL)
3502                 {
3503                         qglUseProgramObjectARB(0);CHECKGLERROR
3504                 }
3505                 rsurface_mode = RSURFMODE_SKY;
3506         }
3507         if (skyrendernow)
3508         {
3509                 skyrendernow = false;
3510                 R_Sky();
3511                 // restore entity matrix
3512                 R_Mesh_Matrix(&rsurface_entity->matrix);
3513         }
3514         GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
3515         GL_CullFace((rsurface_texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
3516         GL_DepthMask(true);
3517         // LordHavoc: HalfLife maps have freaky skypolys so don't use
3518         // skymasking on them, and Quake3 never did sky masking (unlike
3519         // software Quake and software Quake2), so disable the sky masking
3520         // in Quake3 maps as it causes problems with q3map2 sky tricks,
3521         // and skymasking also looks very bad when noclipping outside the
3522         // level, so don't use it then either.
3523         if (rsurface_model->type == mod_brushq1 && r_q1bsp_skymasking.integer && !r_viewcache.world_novis)
3524         {
3525                 GL_Color(r_refdef.fogcolor[0] * r_view.colorscale, r_refdef.fogcolor[1] * r_view.colorscale, r_refdef.fogcolor[2] * r_view.colorscale, 1);
3526                 R_Mesh_ColorPointer(NULL);
3527                 R_Mesh_ResetTextureState();
3528                 if (skyrendermasked)
3529                 {
3530                         // depth-only (masking)
3531                         GL_ColorMask(0,0,0,0);
3532                         // just to make sure that braindead drivers don't draw
3533                         // anything despite that colormask...
3534                         GL_BlendFunc(GL_ZERO, GL_ONE);
3535                 }
3536                 else
3537                 {
3538                         // fog sky
3539                         GL_BlendFunc(GL_ONE, GL_ZERO);
3540                 }
3541                 RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
3542                 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
3543                 if (skyrendermasked)
3544                         GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
3545         }
3546 }
3547
3548 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, msurface_t **texturesurfacelist)
3549 {
3550         if (rsurface_mode != RSURFMODE_GLSL)
3551         {
3552                 rsurface_mode = RSURFMODE_GLSL;
3553                 R_Mesh_ResetTextureState();
3554         }
3555
3556         R_SetupSurfaceShader(vec3_origin, rsurface_lightmode == 2);
3557         if (!r_glsl_permutation)
3558                 return;
3559
3560         if (rsurface_lightmode == 2)
3561                 RSurf_PrepareVerticesForBatch(true, r_glsl_permutation->loc_Texture_Normal, texturenumsurfaces, texturesurfacelist);
3562         else
3563                 RSurf_PrepareVerticesForBatch(r_glsl_permutation->loc_Texture_Normal, r_glsl_permutation->loc_Texture_Normal, texturenumsurfaces, texturesurfacelist);
3564         R_Mesh_TexCoordPointer(0, 2, rsurface_model->surfmesh.data_texcoordtexture2f);
3565         R_Mesh_TexCoordPointer(1, 3, rsurface_svector3f);
3566         R_Mesh_TexCoordPointer(2, 3, rsurface_tvector3f);
3567         R_Mesh_TexCoordPointer(3, 3, rsurface_normal3f);
3568         R_Mesh_TexCoordPointer(4, 2, rsurface_model->surfmesh.data_texcoordlightmap2f);
3569
3570         if (rsurface_texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
3571         {
3572                 R_Mesh_TexBind(7, R_GetTexture(r_texture_white));
3573                 if (r_glsl_permutation->loc_Texture_Deluxemap >= 0)
3574                         R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
3575                 R_Mesh_ColorPointer(NULL);
3576         }
3577         else if (rsurface_uselightmaptexture)
3578         {
3579                 R_Mesh_TexBind(7, R_GetTexture(texturesurfacelist[0]->lightmaptexture));
3580                 if (r_glsl_permutation->loc_Texture_Deluxemap >= 0)
3581                         R_Mesh_TexBind(8, R_GetTexture(texturesurfacelist[0]->deluxemaptexture));
3582                 R_Mesh_ColorPointer(NULL);
3583         }
3584         else
3585         {
3586                 R_Mesh_TexBind(7, R_GetTexture(r_texture_white));
3587                 if (r_glsl_permutation->loc_Texture_Deluxemap >= 0)
3588                         R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
3589                 R_Mesh_ColorPointer(rsurface_model->surfmesh.data_lightmapcolor4f);
3590         }
3591
3592         if (rsurface_uselightmaptexture && !(rsurface_texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT))
3593                 RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist, 7, r_glsl_permutation->loc_Texture_Deluxemap >= 0 ? 8 : -1);
3594         else
3595                 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
3596         if (rsurface_texture->backgroundnumskinframes && !(rsurface_texture->currentmaterialflags & MATERIALFLAG_TRANSPARENT))
3597         {
3598         }
3599 }
3600
3601 static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, msurface_t **texturesurfacelist)
3602 {
3603         // OpenGL 1.3 path - anything not completely ancient
3604         int texturesurfaceindex;
3605         qboolean applycolor;
3606         qboolean applyfog;
3607         rmeshstate_t m;
3608         int layerindex;
3609         const texturelayer_t *layer;
3610         if (rsurface_mode != RSURFMODE_MULTIPASS)
3611                 rsurface_mode = RSURFMODE_MULTIPASS;
3612         RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist);
3613         for (layerindex = 0, layer = rsurface_texture->currentlayers;layerindex < rsurface_texture->currentnumlayers;layerindex++, layer++)
3614         {
3615                 vec4_t layercolor;
3616                 int layertexrgbscale;
3617                 if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
3618                 {
3619                         if (layerindex == 0)
3620                                 GL_AlphaTest(true);
3621                         else
3622                         {
3623                                 GL_AlphaTest(false);
3624                                 qglDepthFunc(GL_EQUAL);CHECKGLERROR
3625                         }
3626                 }
3627                 GL_DepthMask(layer->depthmask);
3628                 GL_BlendFunc(layer->blendfunc1, layer->blendfunc2);
3629                 if ((layer->color[0] > 2 || layer->color[1] > 2 || layer->color[2] > 2) && (gl_combine.integer || layer->depthmask))
3630                 {
3631                         layertexrgbscale = 4;
3632                         VectorScale(layer->color, 0.25f, layercolor);
3633                 }
3634                 else if ((layer->color[0] > 1 || layer->color[1] > 1 || layer->color[2] > 1) && (gl_combine.integer || layer->depthmask))
3635                 {
3636                         layertexrgbscale = 2;
3637                         VectorScale(layer->color, 0.5f, layercolor);
3638                 }
3639                 else
3640                 {
3641                         layertexrgbscale = 1;
3642                         VectorScale(layer->color, 1.0f, layercolor);
3643                 }
3644                 layercolor[3] = layer->color[3];
3645                 applycolor = layercolor[0] != 1 || layercolor[1] != 1 || layercolor[2] != 1 || layercolor[3] != 1;
3646                 R_Mesh_ColorPointer(NULL);
3647                 applyfog = (layer->flags & TEXTURELAYERFLAG_FOGDARKEN) != 0;
3648                 switch (layer->type)
3649                 {
3650                 case TEXTURELAYERTYPE_LITTEXTURE:
3651                         memset(&m, 0, sizeof(m));
3652                         m.tex[0] = R_GetTexture(r_texture_white);
3653                         m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordlightmap2f;
3654                         m.tex[1] = R_GetTexture(layer->texture);
3655                         m.texmatrix[1] = layer->texmatrix;
3656                         m.texrgbscale[1] = layertexrgbscale;
3657                         m.pointer_texcoord[1] = rsurface_model->surfmesh.data_texcoordtexture2f;
3658                         R_Mesh_TextureState(&m);
3659                         if (rsurface_lightmode == 2)
3660                                 RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
3661                         else if (rsurface_uselightmaptexture)
3662                                 RSurf_DrawBatch_GL11_Lightmap(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
3663                         else
3664                                 RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
3665                         break;
3666                 case TEXTURELAYERTYPE_TEXTURE:
3667                         memset(&m, 0, sizeof(m));
3668                         m.tex[0] = R_GetTexture(layer->texture);
3669                         m.texmatrix[0] = layer->texmatrix;
3670                         m.texrgbscale[0] = layertexrgbscale;
3671                         m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
3672                         R_Mesh_TextureState(&m);
3673                         RSurf_DrawBatch_GL11_Unlit(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
3674                         break;
3675                 case TEXTURELAYERTYPE_FOG:
3676                         memset(&m, 0, sizeof(m));
3677                         m.texrgbscale[0] = layertexrgbscale;
3678                         if (layer->texture)
3679                         {
3680                                 m.tex[0] = R_GetTexture(layer->texture);
3681                                 m.texmatrix[0] = layer->texmatrix;
3682                                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
3683                         }
3684                         R_Mesh_TextureState(&m);
3685                         // generate a color array for the fog pass
3686                         R_Mesh_ColorPointer(rsurface_array_color4f);
3687                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
3688                         {
3689                                 int i;
3690                                 float f, *v, *c;
3691                                 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
3692                                 for (i = 0, v = (rsurface_vertex3f + 3 * surface->num_firstvertex), c = (rsurface_array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4)
3693                                 {
3694                                         f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
3695                                         c[0] = layercolor[0];
3696                                         c[1] = layercolor[1];
3697                                         c[2] = layercolor[2];
3698                                         c[3] = f * layercolor[3];
3699                                 }
3700                         }
3701                         RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
3702                         break;
3703                 default:
3704                         Con_Printf("R_DrawTextureSurfaceList: unknown layer type %i\n", layer->type);
3705                 }
3706                 GL_LockArrays(0, 0);
3707         }
3708         CHECKGLERROR
3709         if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
3710         {
3711                 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
3712                 GL_AlphaTest(false);
3713         }
3714 }
3715
3716 static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, msurface_t **texturesurfacelist)
3717 {
3718         // OpenGL 1.1 - crusty old voodoo path
3719         int texturesurfaceindex;
3720         qboolean applyfog;
3721         rmeshstate_t m;
3722         int layerindex;
3723         const texturelayer_t *layer;
3724         if (rsurface_mode != RSURFMODE_MULTIPASS)
3725                 rsurface_mode = RSURFMODE_MULTIPASS;
3726         RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist);
3727         for (layerindex = 0, layer = rsurface_texture->currentlayers;layerindex < rsurface_texture->currentnumlayers;layerindex++, layer++)
3728         {
3729                 if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
3730                 {
3731                         if (layerindex == 0)
3732                                 GL_AlphaTest(true);
3733                         else
3734                         {
3735                                 GL_AlphaTest(false);
3736                                 qglDepthFunc(GL_EQUAL);CHECKGLERROR
3737                         }
3738                 }
3739                 GL_DepthMask(layer->depthmask);
3740                 GL_BlendFunc(layer->blendfunc1, layer->blendfunc2);
3741                 R_Mesh_ColorPointer(NULL);
3742                 applyfog = (layer->flags & TEXTURELAYERFLAG_FOGDARKEN) != 0;
3743                 switch (layer->type)
3744                 {
3745                 case TEXTURELAYERTYPE_LITTEXTURE:
3746                         if (layer->blendfunc1 == GL_ONE && layer->blendfunc2 == GL_ZERO)
3747                         {
3748                                 // two-pass lit texture with 2x rgbscale
3749                                 // first the lightmap pass
3750                                 memset(&m, 0, sizeof(m));
3751                                 m.tex[0] = R_GetTexture(r_texture_white);
3752                                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordlightmap2f;
3753                                 R_Mesh_TextureState(&m);
3754                                 if (rsurface_lightmode == 2)
3755                                         RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
3756                                 else if (rsurface_uselightmaptexture)
3757                                         RSurf_DrawBatch_GL11_Lightmap(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
3758                                 else
3759                                         RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
3760                                 GL_LockArrays(0, 0);
3761                                 // then apply the texture to it
3762                                 GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
3763                                 memset(&m, 0, sizeof(m));
3764                                 m.tex[0] = R_GetTexture(layer->texture);
3765                                 m.texmatrix[0] = layer->texmatrix;
3766                                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
3767                                 R_Mesh_TextureState(&m);
3768                                 RSurf_DrawBatch_GL11_Unlit(texturenumsurfaces, texturesurfacelist, layer->color[0] * 0.5f, layer->color[1] * 0.5f, layer->color[2] * 0.5f, layer->color[3], layer->color[0] != 2 || layer->color[1] != 2 || layer->color[2] != 2 || layer->color[3] != 1, false);
3769                         }
3770                         else
3771                         {
3772                                 // single pass vertex-lighting-only texture with 1x rgbscale and transparency support
3773                                 memset(&m, 0, sizeof(m));
3774                                 m.tex[0] = R_GetTexture(layer->texture);
3775                                 m.texmatrix[0] = layer->texmatrix;
3776                                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
3777                                 R_Mesh_TextureState(&m);
3778                                 if (rsurface_lightmode == 2)
3779                                         RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, layer->color[0], layer->color[1], layer->color[2], layer->color[3], layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog);
3780                                 else
3781                                         RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, layer->color[0], layer->color[1], layer->color[2], layer->color[3], layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog);
3782                         }
3783                         break;
3784                 case TEXTURELAYERTYPE_TEXTURE:
3785                         // singletexture unlit texture with transparency support
3786                         memset(&m, 0, sizeof(m));
3787                         m.tex[0] = R_GetTexture(layer->texture);
3788                         m.texmatrix[0] = layer->texmatrix;
3789                         m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
3790                         R_Mesh_TextureState(&m);
3791                         RSurf_DrawBatch_GL11_Unlit(texturenumsurfaces, texturesurfacelist, layer->color[0], layer->color[1], layer->color[2], layer->color[3], layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog);
3792                         break;
3793                 case TEXTURELAYERTYPE_FOG:
3794                         // singletexture fogging
3795                         R_Mesh_ColorPointer(rsurface_array_color4f);
3796                         if (layer->texture)
3797                         {
3798                                 memset(&m, 0, sizeof(m));
3799                                 m.tex[0] = R_GetTexture(layer->texture);
3800                                 m.texmatrix[0] = layer->texmatrix;
3801                                 m.pointer_texcoord[0] = rsurface_model->surfmesh.data_texcoordtexture2f;
3802                                 R_Mesh_TextureState(&m);
3803                         }
3804                         else
3805                                 R_Mesh_ResetTextureState();
3806                         // generate a color array for the fog pass
3807                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
3808                         {
3809                                 int i;
3810                                 float f, *v, *c;
3811                                 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
3812                                 for (i = 0, v = (rsurface_vertex3f + 3 * surface->num_firstvertex), c = (rsurface_array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4)
3813                                 {
3814                                         f = VERTEXFOGTABLE(VectorDistance(v, rsurface_modelorg));
3815                                         c[0] = layer->color[0];
3816                                         c[1] = layer->color[1];
3817                                         c[2] = layer->color[2];
3818                                         c[3] = f * layer->color[3];
3819                                 }
3820                         }
3821                         RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
3822                         break;
3823                 default:
3824                         Con_Printf("R_DrawTextureSurfaceList: unknown layer type %i\n", layer->type);
3825                 }
3826                 GL_LockArrays(0, 0);
3827         }
3828         CHECKGLERROR
3829         if (rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
3830         {
3831                 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
3832                 GL_AlphaTest(false);
3833         }
3834 }
3835
3836 static void R_DrawTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist)
3837 {
3838         if (rsurface_texture->currentmaterialflags & MATERIALFLAG_NODRAW)
3839                 return;
3840         r_shadow_rtlight = NULL;
3841         r_refdef.stats.entities_surfaces += texturenumsurfaces;
3842         CHECKGLERROR
3843         if (r_showsurfaces.integer)
3844                 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist);
3845         else if (rsurface_texture->currentmaterialflags & MATERIALFLAG_SKY)
3846                 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
3847         else if (rsurface_texture->currentnumlayers)
3848         {
3849                 GL_DepthTest(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
3850                 GL_CullFace((rsurface_texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
3851                 GL_BlendFunc(rsurface_texture->currentlayers[0].blendfunc1, rsurface_texture->currentlayers[0].blendfunc2);
3852                 GL_DepthMask(!(rsurface_texture->currentmaterialflags & MATERIALFLAG_BLENDED));
3853                 GL_Color(rsurface_entity->colormod[0], rsurface_entity->colormod[1], rsurface_entity->colormod[2], rsurface_texture->currentalpha);
3854                 GL_AlphaTest((rsurface_texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
3855                 // FIXME: identify models using a better check than rsurface_model->brush.shadowmesh
3856                 rsurface_lightmode = ((rsurface_texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || rsurface_model->brush.shadowmesh) ? 0 : 2;
3857                 if (r_glsl.integer && gl_support_fragment_shader)
3858                         R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist);
3859                 else if (gl_combine.integer && r_textureunits.integer >= 2)
3860                         R_DrawTextureSurfaceList_GL13(texturenumsurfaces, texturesurfacelist);
3861                 else
3862                         R_DrawTextureSurfaceList_GL11(texturenumsurfaces, texturesurfacelist);
3863         }
3864         CHECKGLERROR
3865         GL_LockArrays(0, 0);
3866 }
3867
3868 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3869 {
3870         int i, j;
3871         int texturenumsurfaces, endsurface;
3872         texture_t *texture;
3873         msurface_t *surface;
3874         msurface_t *texturesurfacelist[1024];
3875
3876         // if the model is static it doesn't matter what value we give for
3877         // wantnormals and wanttangents, so this logic uses only rules applicable
3878         // to a model, knowing that they are meaningless otherwise
3879         if (ent == r_refdef.worldentity)
3880                 RSurf_ActiveWorldEntity();
3881         else if ((ent->effects & EF_FULLBRIGHT) || r_showsurfaces.integer || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f))
3882                 RSurf_ActiveModelEntity(ent, false, false);
3883         else
3884                 RSurf_ActiveModelEntity(ent, true, r_glsl.integer && gl_support_fragment_shader);
3885
3886         for (i = 0;i < numsurfaces;i = j)
3887         {
3888                 j = i + 1;
3889                 surface = rsurface_model->data_surfaces + surfacelist[i];
3890                 texture = surface->texture;
3891                 rsurface_texture = texture->currentframe;
3892                 rsurface_uselightmaptexture = surface->lightmaptexture != NULL;
3893                 // scan ahead until we find a different texture
3894                 endsurface = min(i + 1024, numsurfaces);
3895                 texturenumsurfaces = 0;
3896                 texturesurfacelist[texturenumsurfaces++] = surface;
3897                 for (;j < endsurface;j++)
3898                 {
3899                         surface = rsurface_model->data_surfaces + surfacelist[j];
3900                         if (texture != surface->texture || rsurface_uselightmaptexture != (surface->lightmaptexture != NULL))
3901                                 break;
3902                         texturesurfacelist[texturenumsurfaces++] = surface;
3903                 }
3904                 // render the range of surfaces
3905                 R_DrawTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
3906         }
3907
3908         RSurf_CleanUp();
3909 }
3910
3911 void R_QueueSurfaceList(int numsurfaces, msurface_t **surfacelist, int flagsmask)
3912 {
3913         int i, j;
3914         vec3_t tempcenter, center;
3915         texture_t *texture;
3916         // break the surface list down into batches by texture and use of lightmapping
3917         for (i = 0;i < numsurfaces;i = j)
3918         {
3919                 j = i + 1;
3920                 // texture is the base texture pointer, rsurface_texture is the
3921                 // current frame/skin the texture is directing us to use (for example
3922                 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
3923                 // use skin 1 instead)
3924                 texture = surfacelist[i]->texture;
3925                 rsurface_texture = texture->currentframe;
3926                 rsurface_uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
3927                 if (!(rsurface_texture->currentmaterialflags & flagsmask))
3928                 {
3929                         // if this texture is not the kind we want, skip ahead to the next one
3930                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
3931                                 ;
3932                         continue;
3933                 }
3934                 if (rsurface_texture->currentmaterialflags & MATERIALFLAG_BLENDED)
3935                 {
3936                         // transparent surfaces get pushed off into the transparent queue
3937                         const msurface_t *surface = surfacelist[i];
3938                         tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
3939                         tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
3940                         tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
3941                         Matrix4x4_Transform(&rsurface_entity->matrix, tempcenter, center);
3942                         R_MeshQueue_AddTransparent(rsurface_texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_view.origin : center, R_DrawSurface_TransparentCallback, rsurface_entity, surface - rsurface_model->data_surfaces, r_shadow_rtlight);
3943                 }
3944                 else
3945                 {
3946                         // simply scan ahead until we find a different texture or lightmap state
3947                         for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface_uselightmaptexture == (surfacelist[j]->lightmaptexture != NULL);j++)
3948                                 ;
3949                         // render the range of surfaces
3950                         R_DrawTextureSurfaceList(j - i, surfacelist + i);
3951                 }
3952         }
3953 }
3954
3955 float locboxvertex3f[6*4*3] =
3956 {
3957         1,0,1, 1,0,0, 1,1,0, 1,1,1,
3958         0,1,1, 0,1,0, 0,0,0, 0,0,1,
3959         1,1,1, 1,1,0, 0,1,0, 0,1,1,
3960         0,0,1, 0,0,0, 1,0,0, 1,0,1,
3961         0,0,1, 1,0,1, 1,1,1, 0,1,1,
3962         1,0,0, 0,0,0, 0,1,0, 1,1,0
3963 };
3964
3965 int locboxelement3i[6*2*3] =
3966 {
3967          0, 1, 2, 0, 2, 3,
3968          4, 5, 6, 4, 6, 7,
3969          8, 9,10, 8,10,11,
3970         12,13,14, 12,14,15,
3971         16,17,18, 16,18,19,
3972         20,21,22, 20,22,23
3973 };
3974
3975 void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3976 {
3977         int i, j;
3978         cl_locnode_t *loc = (cl_locnode_t *)ent;
3979         vec3_t mins, size;
3980         float vertex3f[6*4*3];
3981         CHECKGLERROR
3982         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3983         GL_DepthMask(false);
3984         GL_DepthTest(true);
3985         GL_CullFace(GL_NONE);
3986         R_Mesh_Matrix(&identitymatrix);
3987
3988         R_Mesh_VertexPointer(vertex3f);
3989         R_Mesh_ColorPointer(NULL);
3990         R_Mesh_ResetTextureState();
3991
3992         i = surfacelist[0];
3993         GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_view.colorscale,
3994                          ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_view.colorscale,
3995                          ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_view.colorscale,
3996                         surfacelist[0] < 0 ? 0.5f : 0.125f);
3997
3998         if (VectorCompare(loc->mins, loc->maxs))
3999         {
4000                 VectorSet(size, 2, 2, 2);
4001                 VectorMA(loc->mins, -0.5f, size, mins);
4002         }
4003         else
4004         {
4005                 VectorCopy(loc->mins, mins);
4006                 VectorSubtract(loc->maxs, loc->mins, size);
4007         }
4008
4009         for (i = 0;i < 6*4*3;)
4010                 for (j = 0;j < 3;j++, i++)
4011                         vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
4012
4013         R_Mesh_Draw(0, 6*4, 6*2, locboxelement3i);
4014 }
4015
4016 void R_DrawLocs(void)
4017 {
4018         int index;
4019         cl_locnode_t *loc, *nearestloc;
4020         vec3_t center;
4021         nearestloc = CL_Locs_FindNearest(cl.movement_origin);
4022         for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
4023         {
4024                 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
4025                 R_MeshQueue_AddTransparent(center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
4026         }
4027 }
4028
4029 void R_DrawCollisionBrushes(entity_render_t *ent)
4030 {
4031         int i;
4032         q3mbrush_t *brush;
4033         msurface_t *surface;
4034         model_t *model = ent->model;
4035         if (!model->brush.num_brushes)
4036                 return;
4037         CHECKGLERROR
4038         R_Mesh_ColorPointer(NULL);
4039         R_Mesh_ResetTextureState();
4040         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
4041         GL_DepthMask(false);
4042         GL_DepthTest(!r_showdisabledepthtest.integer);
4043         qglPolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);CHECKGLERROR
4044         for (i = 0, brush = model->brush.data_brushes + model->firstmodelbrush;i < model->nummodelbrushes;i++, brush++)
4045                 if (brush->colbrushf && brush->colbrushf->numtriangles)
4046                         R_DrawCollisionBrush(brush->colbrushf);
4047         for (i = 0, surface = model->data_surfaces + model->firstmodelsurface;i < model->nummodelsurfaces;i++, surface++)
4048                 if (surface->num_collisiontriangles)
4049                         R_DrawCollisionSurface(ent, surface);
4050         qglPolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);CHECKGLERROR
4051 }
4052
4053 void R_DrawTrianglesAndNormals(entity_render_t *ent, qboolean drawtris, qboolean drawnormals, int flagsmask)
4054 {
4055         int i, j, k, l;
4056         const int *elements;
4057         msurface_t *surface;
4058         model_t *model = ent->model;
4059         vec3_t v;
4060         CHECKGLERROR
4061         GL_DepthTest(!r_showdisabledepthtest.integer);
4062         GL_DepthMask(true);
4063         GL_BlendFunc(GL_ONE, GL_ZERO);
4064         R_Mesh_ColorPointer(NULL);
4065         R_Mesh_ResetTextureState();
4066         for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
4067         {
4068                 if (ent == r_refdef.worldentity && !r_viewcache.world_surfacevisible[j])
4069                         continue;
4070                 rsurface_texture = surface->texture->currentframe;
4071                 if ((rsurface_texture->currentmaterialflags & flagsmask) && surface->num_triangles)
4072                 {
4073                         RSurf_PrepareVerticesForBatch(true, true, 1, &surface);
4074                         if (drawtris)
4075                         {
4076                                 if (!rsurface_texture->currentlayers->depthmask)
4077                                         GL_Color(r_showtris.value * r_view.colorscale, 0, 0, 1);
4078                                 else if (ent == r_refdef.worldentity)
4079                                         GL_Color(r_showtris.value * r_view.colorscale, r_showtris.value * r_view.colorscale, r_showtris.value * r_view.colorscale, 1);
4080                                 else
4081                                         GL_Color(0, r_showtris.value * r_view.colorscale, 0, 1);
4082                                 elements = (ent->model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);
4083                                 CHECKGLERROR
4084                                 qglBegin(GL_LINES);
4085                                 for (k = 0;k < surface->num_triangles;k++, elements += 3)
4086                                 {
4087                                         qglArrayElement(elements[0]);qglArrayElement(elements[1]);
4088                                         qglArrayElement(elements[1]);qglArrayElement(elements[2]);
4089                                         qglArrayElement(elements[2]);qglArrayElement(elements[0]);
4090                                 }
4091                                 qglEnd();
4092                                 CHECKGLERROR
4093                         }
4094                         if (drawnormals)
4095                         {
4096                                 GL_Color(r_shownormals.value * r_view.colorscale, 0, 0, 1);
4097                                 qglBegin(GL_LINES);
4098                                 for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
4099                                 {
4100                                         VectorCopy(rsurface_vertex3f + l * 3, v);
4101                                         qglVertex3f(v[0], v[1], v[2]);
4102                                         VectorMA(v, 8, rsurface_svector3f + l * 3, v);
4103                                         qglVertex3f(v[0], v[1], v[2]);
4104                                 }
4105                                 qglEnd();
4106                                 CHECKGLERROR
4107                                 GL_Color(0, 0, r_shownormals.value * r_view.colorscale, 1);
4108                                 qglBegin(GL_LINES);
4109                                 for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
4110                                 {
4111                                         VectorCopy(rsurface_vertex3f + l * 3, v);
4112                                         qglVertex3f(v[0], v[1], v[2]);
4113                                         VectorMA(v, 8, rsurface_tvector3f + l * 3, v);
4114                                         qglVertex3f(v[0], v[1], v[2]);
4115                                 }
4116                                 qglEnd();
4117                                 CHECKGLERROR
4118                                 GL_Color(0, r_shownormals.value * r_view.colorscale, 0, 1);
4119                                 qglBegin(GL_LINES);
4120                                 for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
4121                                 {
4122                                         VectorCopy(rsurface_vertex3f + l * 3, v);
4123                                         qglVertex3f(v[0], v[1], v[2]);
4124                                         VectorMA(v, 8, rsurface_normal3f + l * 3, v);
4125                                         qglVertex3f(v[0], v[1], v[2]);
4126                                 }
4127                                 qglEnd();
4128                                 CHECKGLERROR
4129                         }
4130                 }
4131         }
4132         rsurface_texture = NULL;
4133 }
4134
4135 extern void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface);
4136 void R_DrawWorldSurfaces(qboolean skysurfaces)
4137 {
4138         int i, j, endj, f, flagsmask;
4139         int counttriangles = 0;
4140         msurface_t *surface, **surfacechain;
4141         texture_t *t;
4142         model_t *model = r_refdef.worldmodel;
4143         const int maxsurfacelist = 1024;
4144         int numsurfacelist = 0;
4145         msurface_t *surfacelist[1024];
4146         if (model == NULL)
4147                 return;
4148
4149         RSurf_ActiveWorldEntity();
4150
4151         // update light styles
4152         if (!skysurfaces && model->brushq1.light_styleupdatechains)
4153         {
4154                 for (i = 0;i < model->brushq1.light_styles;i++)
4155                 {
4156                         if (model->brushq1.light_stylevalue[i] != r_refdef.lightstylevalue[model->brushq1.light_style[i]])
4157                         {
4158                                 model->brushq1.light_stylevalue[i] = r_refdef.lightstylevalue[model->brushq1.light_style[i]];
4159                                 if ((surfacechain = model->brushq1.light_styleupdatechains[i]))
4160                                         for (;(surface = *surfacechain);surfacechain++)
4161                                                 surface->cached_dlight = true;
4162                         }
4163                 }
4164         }
4165
4166         R_UpdateAllTextureInfo(r_refdef.worldentity);
4167         flagsmask = skysurfaces ? MATERIALFLAG_SKY : (MATERIALFLAG_WATER | MATERIALFLAG_WALL);
4168         f = 0;
4169         t = NULL;
4170         rsurface_uselightmaptexture = false;
4171         rsurface_texture = NULL;
4172         numsurfacelist = 0;
4173         j = model->firstmodelsurface;
4174         endj = j + model->nummodelsurfaces;
4175         while (j < endj)
4176         {
4177                 // quickly skip over non-visible surfaces
4178                 for (;j < endj && !r_viewcache.world_surfacevisible[j];j++)
4179                         ;
4180                 // quickly iterate over visible surfaces
4181                 for (;j < endj && r_viewcache.world_surfacevisible[j];j++)
4182                 {
4183                         // process this surface
4184                         surface = model->data_surfaces + j;
4185                         // if this surface fits the criteria, add it to the list
4186                         if (surface->num_triangles)
4187                         {
4188                                 // if lightmap parameters changed, rebuild lightmap texture
4189                                 if (surface->cached_dlight)
4190                                         R_BuildLightMap(r_refdef.worldentity, surface);
4191                                 // add face to draw list
4192                                 surfacelist[numsurfacelist++] = surface;
4193                                 counttriangles += surface->num_triangles;
4194                                 if (numsurfacelist >= maxsurfacelist)
4195                                 {
4196                                         R_QueueSurfaceList(numsurfacelist, surfacelist, flagsmask);
4197                                         numsurfacelist = 0;
4198                                 }
4199                         }
4200                 }
4201         }
4202         if (numsurfacelist)
4203                 R_QueueSurfaceList(numsurfacelist, surfacelist, flagsmask);
4204         r_refdef.stats.entities_triangles += counttriangles;
4205         RSurf_CleanUp();
4206
4207         if (r_showcollisionbrushes.integer && !skysurfaces)
4208                 R_DrawCollisionBrushes(r_refdef.worldentity);
4209
4210         if (r_showtris.integer || r_shownormals.integer)
4211                 R_DrawTrianglesAndNormals(r_refdef.worldentity, r_showtris.integer, r_shownormals.integer, flagsmask);
4212 }
4213
4214 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces)
4215 {
4216         int i, f, flagsmask;
4217         int counttriangles = 0;
4218         msurface_t *surface, *endsurface, **surfacechain;
4219         texture_t *t;
4220         model_t *model = ent->model;
4221         const int maxsurfacelist = 1024;
4222         int numsurfacelist = 0;
4223         msurface_t *surfacelist[1024];
4224         if (model == NULL)
4225                 return;
4226
4227         // if the model is static it doesn't matter what value we give for
4228         // wantnormals and wanttangents, so this logic uses only rules applicable
4229         // to a model, knowing that they are meaningless otherwise
4230         if (ent == r_refdef.worldentity)
4231                 RSurf_ActiveWorldEntity();
4232         else if ((ent->effects & EF_FULLBRIGHT) || r_showsurfaces.integer || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f))
4233                 RSurf_ActiveModelEntity(ent, false, false);
4234         else
4235                 RSurf_ActiveModelEntity(ent, true, r_glsl.integer && gl_support_fragment_shader);
4236
4237         // update light styles
4238         if (!skysurfaces && model->brushq1.light_styleupdatechains)
4239         {
4240                 for (i = 0;i < model->brushq1.light_styles;i++)
4241                 {
4242                         if (model->brushq1.light_stylevalue[i] != r_refdef.lightstylevalue[model->brushq1.light_style[i]])
4243                         {
4244                                 model->brushq1.light_stylevalue[i] = r_refdef.lightstylevalue[model->brushq1.light_style[i]];
4245                                 if ((surfacechain = model->brushq1.light_styleupdatechains[i]))
4246                                         for (;(surface = *surfacechain);surfacechain++)
4247                                                 surface->cached_dlight = true;
4248                         }
4249                 }
4250         }
4251
4252         R_UpdateAllTextureInfo(ent);
4253         flagsmask = skysurfaces ? MATERIALFLAG_SKY : (MATERIALFLAG_WATER | MATERIALFLAG_WALL);
4254         f = 0;
4255         t = NULL;
4256         rsurface_uselightmaptexture = false;
4257         rsurface_texture = NULL;
4258         numsurfacelist = 0;
4259         surface = model->data_surfaces + model->firstmodelsurface;
4260         endsurface = surface + model->nummodelsurfaces;
4261         for (;surface < endsurface;surface++)
4262         {
4263                 // if this surface fits the criteria, add it to the list
4264                 if (surface->num_triangles)
4265                 {
4266                         // if lightmap parameters changed, rebuild lightmap texture
4267                         if (surface->cached_dlight)
4268                                 R_BuildLightMap(ent, surface);
4269                         // add face to draw list
4270                         surfacelist[numsurfacelist++] = surface;
4271                         counttriangles += surface->num_triangles;
4272                         if (numsurfacelist >= maxsurfacelist)
4273                         {
4274                                 R_QueueSurfaceList(numsurfacelist, surfacelist, flagsmask);
4275                                 numsurfacelist = 0;
4276                         }
4277                 }
4278         }
4279         if (numsurfacelist)
4280                 R_QueueSurfaceList(numsurfacelist, surfacelist, flagsmask);
4281         r_refdef.stats.entities_triangles += counttriangles;
4282         RSurf_CleanUp();
4283
4284         if (r_showcollisionbrushes.integer && !skysurfaces)
4285                 R_DrawCollisionBrushes(ent);
4286
4287         if (r_showtris.integer || r_shownormals.integer)
4288                 R_DrawTrianglesAndNormals(ent, r_showtris.integer, r_shownormals.integer, flagsmask);
4289 }