]> icculus.org git repositories - divverent/darkplaces.git/blob - gl_rmain.c
fix the jump-slide bug in the sv_gameplayfix_qwplayerphysics option
[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 #include "image.h"
26
27 mempool_t *r_main_mempool;
28 rtexturepool_t *r_main_texturepool;
29
30 //
31 // screen size info
32 //
33 r_refdef_t r_refdef;
34 r_view_t r_view;
35 r_viewcache_t r_viewcache;
36
37 cvar_t r_depthfirst = {CVAR_SAVE, "r_depthfirst", "1", "renders a depth-only version of the scene before normal rendering begins to eliminate overdraw, values: 0 = off, 1 = world depth, 2 = world and model depth"};
38 cvar_t r_nearclip = {0, "r_nearclip", "1", "distance from camera of nearclip plane" };
39 cvar_t r_showbboxes = {0, "r_showbboxes", "0", "shows bounding boxes of server entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
40 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)"};
41 cvar_t r_showtris = {0, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"};
42 cvar_t r_shownormals = {0, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"};
43 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"};
44 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"};
45 cvar_t r_showcollisionbrushes = {0, "r_showcollisionbrushes", "0", "draws collision brushes in quake3 maps (mode 1), mode 2 disables rendering of world (trippy!)"};
46 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"};
47 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"};
48 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"};
49 cvar_t r_drawportals = {0, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"};
50 cvar_t r_drawentities = {0, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"};
51 cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1", "draw your weapon model"};
52 cvar_t r_cullentities_trace = {0, "r_cullentities_trace", "1", "probabistically cull invisible entities"};
53 cvar_t r_cullentities_trace_samples = {0, "r_cullentities_trace_samples", "2", "number of samples to test for entity culling"};
54 cvar_t r_cullentities_trace_enlarge = {0, "r_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
55 cvar_t r_cullentities_trace_delay = {0, "r_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
56 cvar_t r_speeds = {0, "r_speeds","0", "displays rendering statistics and per-subsystem timings"};
57 cvar_t r_fullbright = {0, "r_fullbright","0", "makes map very bright and renders faster"};
58 cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1", "opacity of water polygons"};
59 cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1", "enables dynamic lights (rocket glow and such)"};
60 cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1", "enables glowing pixels in quake textures (changes need r_restart to take effect)"};
61 cvar_t r_shadows = {CVAR_SAVE, "r_shadows", "0", "casts fake stencil shadows from models onto the world (rtlights are unaffected by this)"};
62 cvar_t r_shadows_throwdistance = {CVAR_SAVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"};
63 cvar_t r_q1bsp_skymasking = {0, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
64 cvar_t r_polygonoffset_submodel_factor = {0, "r_polygonoffset_submodel_factor", "0", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
65 cvar_t r_polygonoffset_submodel_offset = {0, "r_polygonoffset_submodel_offset", "2", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
66
67 cvar_t gl_fogenable = {0, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"};
68 cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"};
69 cvar_t gl_fogred = {0, "gl_fogred","0.3", "nehahra fog color red value (for Nehahra compatibility only)"};
70 cvar_t gl_foggreen = {0, "gl_foggreen","0.3", "nehahra fog color green value (for Nehahra compatibility only)"};
71 cvar_t gl_fogblue = {0, "gl_fogblue","0.3", "nehahra fog color blue value (for Nehahra compatibility only)"};
72 cvar_t gl_fogstart = {0, "gl_fogstart", "0", "nehahra fog start distance (for Nehahra compatibility only)"};
73 cvar_t gl_fogend = {0, "gl_fogend","0", "nehahra fog end distance (for Nehahra compatibility only)"};
74
75 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)"};
76
77 cvar_t r_glsl = {CVAR_SAVE, "r_glsl", "1", "enables use of OpenGL 2.0 pixel shaders for lighting"};
78 cvar_t r_glsl_offsetmapping = {CVAR_SAVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
79 cvar_t r_glsl_offsetmapping_reliefmapping = {CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
80 cvar_t r_glsl_offsetmapping_scale = {CVAR_SAVE, "r_glsl_offsetmapping_scale", "0.04", "how deep the offset mapping effect is"};
81 cvar_t r_glsl_deluxemapping = {CVAR_SAVE, "r_glsl_deluxemapping", "1", "use per pixel lighting on deluxemap-compiled q3bsp maps (or a value of 2 forces deluxemap shading even without deluxemaps)"};
82 cvar_t r_glsl_contrastboost = {CVAR_SAVE, "r_glsl_contrastboost", "1", "by how much to multiply the contrast in dark areas (1 is no change)"};
83
84 cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "1", "enables animation smoothing on sprites (requires r_lerpmodels 1)"};
85 cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
86 cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
87
88 cvar_t r_bloom = {CVAR_SAVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"};
89 cvar_t r_bloom_colorscale = {CVAR_SAVE, "r_bloom_colorscale", "1", "how bright the glow is"};
90 cvar_t r_bloom_brighten = {CVAR_SAVE, "r_bloom_brighten", "2", "how bright the glow is, after subtract/power"};
91 cvar_t r_bloom_blur = {CVAR_SAVE, "r_bloom_blur", "4", "how large the glow is"};
92 cvar_t r_bloom_resolution = {CVAR_SAVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"};
93 cvar_t r_bloom_colorexponent = {CVAR_SAVE, "r_bloom_colorexponent", "1", "how exagerated the glow is"};
94 cvar_t r_bloom_colorsubtract = {CVAR_SAVE, "r_bloom_colorsubtract", "0.125", "reduces bloom colors by a certain amount"};
95
96 cvar_t r_hdr = {CVAR_SAVE, "r_hdr", "0", "enables High Dynamic Range bloom effect (higher quality version of r_bloom)"};
97 cvar_t r_hdr_scenebrightness = {CVAR_SAVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
98 cvar_t r_hdr_glowintensity = {CVAR_SAVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
99 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)"};
100
101 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"};
102
103 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"};
104
105 cvar_t gl_lightmaps = {0, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers)"};
106
107 cvar_t r_test = {0, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
108 cvar_t r_batchmode = {0, "r_batchmode", "1", "selects method of rendering multiple surfaces with one driver call (values are 0, 1, 2, etc...)"};
109
110 extern qboolean v_flipped_state;
111
112 typedef struct r_glsl_bloomshader_s
113 {
114         int program;
115         int loc_Texture_Bloom;
116 }
117 r_glsl_bloomshader_t;
118
119 static struct r_bloomstate_s
120 {
121         qboolean enabled;
122         qboolean hdr;
123
124         int bloomwidth, bloomheight;
125
126         int screentexturewidth, screentextureheight;
127         rtexture_t *texture_screen;
128
129         int bloomtexturewidth, bloomtextureheight;
130         rtexture_t *texture_bloom;
131
132         r_glsl_bloomshader_t *shader;
133
134         // arrays for rendering the screen passes
135         float screentexcoord2f[8];
136         float bloomtexcoord2f[8];
137         float offsettexcoord2f[8];
138 }
139 r_bloomstate;
140
141 // shadow volume bsp struct with automatically growing nodes buffer
142 svbsp_t r_svbsp;
143
144 rtexture_t *r_texture_blanknormalmap;
145 rtexture_t *r_texture_white;
146 rtexture_t *r_texture_black;
147 rtexture_t *r_texture_notexture;
148 rtexture_t *r_texture_whitecube;
149 rtexture_t *r_texture_normalizationcube;
150 rtexture_t *r_texture_fogattenuation;
151 //rtexture_t *r_texture_fogintensity;
152
153 // information about each possible shader permutation
154 r_glsl_permutation_t r_glsl_permutations[SHADERPERMUTATION_MAX];
155 // currently selected permutation
156 r_glsl_permutation_t *r_glsl_permutation;
157
158 char r_qwskincache[MAX_SCOREBOARD][MAX_QPATH];
159 skinframe_t *r_qwskincache_skinframe[MAX_SCOREBOARD];
160
161 // vertex coordinates for a quad that covers the screen exactly
162 const static float r_screenvertex3f[12] =
163 {
164         0, 0, 0,
165         1, 0, 0,
166         1, 1, 0,
167         0, 1, 0
168 };
169
170 extern void R_DrawModelShadows(void);
171
172 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
173 {
174         int i;
175         for (i = 0;i < verts;i++)
176         {
177                 out[0] = in[0] * r;
178                 out[1] = in[1] * g;
179                 out[2] = in[2] * b;
180                 out[3] = in[3];
181                 in += 4;
182                 out += 4;
183         }
184 }
185
186 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
187 {
188         int i;
189         for (i = 0;i < verts;i++)
190         {
191                 out[0] = r;
192                 out[1] = g;
193                 out[2] = b;
194                 out[3] = a;
195                 out += 4;
196         }
197 }
198
199 // FIXME: move this to client?
200 void FOG_clear(void)
201 {
202         if (gamemode == GAME_NEHAHRA)
203         {
204                 Cvar_Set("gl_fogenable", "0");
205                 Cvar_Set("gl_fogdensity", "0.2");
206                 Cvar_Set("gl_fogred", "0.3");
207                 Cvar_Set("gl_foggreen", "0.3");
208                 Cvar_Set("gl_fogblue", "0.3");
209         }
210         r_refdef.fog_density = r_refdef.fog_red = r_refdef.fog_green = r_refdef.fog_blue = 0.0f;
211 }
212
213 float FogPoint_World(const vec3_t p)
214 {
215         int fogmasktableindex = (int)(VectorDistance((p), r_view.origin) * r_refdef.fogmasktabledistmultiplier);
216         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
217 }
218
219 float FogPoint_Model(const vec3_t p)
220 {
221         int fogmasktableindex = (int)(VectorDistance((p), rsurface.modelorg) * r_refdef.fogmasktabledistmultiplier);
222         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
223 }
224
225 static void R_BuildBlankTextures(void)
226 {
227         unsigned char data[4];
228         data[0] = 128; // normal X
229         data[1] = 128; // normal Y
230         data[2] = 255; // normal Z
231         data[3] = 128; // height
232         r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
233         data[0] = 255;
234         data[1] = 255;
235         data[2] = 255;
236         data[3] = 255;
237         r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
238         data[0] = 0;
239         data[1] = 0;
240         data[2] = 0;
241         data[3] = 255;
242         r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
243 }
244
245 static void R_BuildNoTexture(void)
246 {
247         int x, y;
248         unsigned char pix[16][16][4];
249         // this makes a light grey/dark grey checkerboard texture
250         for (y = 0;y < 16;y++)
251         {
252                 for (x = 0;x < 16;x++)
253                 {
254                         if ((y < 8) ^ (x < 8))
255                         {
256                                 pix[y][x][0] = 128;
257                                 pix[y][x][1] = 128;
258                                 pix[y][x][2] = 128;
259                                 pix[y][x][3] = 255;
260                         }
261                         else
262                         {
263                                 pix[y][x][0] = 64;
264                                 pix[y][x][1] = 64;
265                                 pix[y][x][2] = 64;
266                                 pix[y][x][3] = 255;
267                         }
268                 }
269         }
270         r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP, NULL);
271 }
272
273 static void R_BuildWhiteCube(void)
274 {
275         unsigned char data[6*1*1*4];
276         data[ 0] = 255;data[ 1] = 255;data[ 2] = 255;data[ 3] = 255;
277         data[ 4] = 255;data[ 5] = 255;data[ 6] = 255;data[ 7] = 255;
278         data[ 8] = 255;data[ 9] = 255;data[10] = 255;data[11] = 255;
279         data[12] = 255;data[13] = 255;data[14] = 255;data[15] = 255;
280         data[16] = 255;data[17] = 255;data[18] = 255;data[19] = 255;
281         data[20] = 255;data[21] = 255;data[22] = 255;data[23] = 255;
282         r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
283 }
284
285 static void R_BuildNormalizationCube(void)
286 {
287         int x, y, side;
288         vec3_t v;
289         vec_t s, t, intensity;
290 #define NORMSIZE 64
291         unsigned char data[6][NORMSIZE][NORMSIZE][4];
292         for (side = 0;side < 6;side++)
293         {
294                 for (y = 0;y < NORMSIZE;y++)
295                 {
296                         for (x = 0;x < NORMSIZE;x++)
297                         {
298                                 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
299                                 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
300                                 switch(side)
301                                 {
302                                 default:
303                                 case 0:
304                                         v[0] = 1;
305                                         v[1] = -t;
306                                         v[2] = -s;
307                                         break;
308                                 case 1:
309                                         v[0] = -1;
310                                         v[1] = -t;
311                                         v[2] = s;
312                                         break;
313                                 case 2:
314                                         v[0] = s;
315                                         v[1] = 1;
316                                         v[2] = t;
317                                         break;
318                                 case 3:
319                                         v[0] = s;
320                                         v[1] = -1;
321                                         v[2] = -t;
322                                         break;
323                                 case 4:
324                                         v[0] = s;
325                                         v[1] = -t;
326                                         v[2] = 1;
327                                         break;
328                                 case 5:
329                                         v[0] = -s;
330                                         v[1] = -t;
331                                         v[2] = -1;
332                                         break;
333                                 }
334                                 intensity = 127.0f / sqrt(DotProduct(v, v));
335                                 data[side][y][x][0] = (unsigned char)(128.0f + intensity * v[0]);
336                                 data[side][y][x][1] = (unsigned char)(128.0f + intensity * v[1]);
337                                 data[side][y][x][2] = (unsigned char)(128.0f + intensity * v[2]);
338                                 data[side][y][x][3] = 255;
339                         }
340                 }
341         }
342         r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, &data[0][0][0][0], TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
343 }
344
345 static void R_BuildFogTexture(void)
346 {
347         int x, b;
348 #define FOGWIDTH 64
349         unsigned char data1[FOGWIDTH][4];
350         //unsigned char data2[FOGWIDTH][4];
351         for (x = 0;x < FOGWIDTH;x++)
352         {
353                 b = (int)(r_refdef.fogmasktable[x * (FOGMASKTABLEWIDTH - 1) / (FOGWIDTH - 1)] * 255);
354                 data1[x][0] = b;
355                 data1[x][1] = b;
356                 data1[x][2] = b;
357                 data1[x][3] = 255;
358                 //data2[x][0] = 255 - b;
359                 //data2[x][1] = 255 - b;
360                 //data2[x][2] = 255 - b;
361                 //data2[x][3] = 255;
362         }
363         r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
364         //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
365 }
366
367 static const char *builtinshaderstring =
368 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
369 "// written by Forest 'LordHavoc' Hale\n"
370 "\n"
371 "// common definitions between vertex shader and fragment shader:\n"
372 "\n"
373 "#ifdef __GLSL_CG_DATA_TYPES\n"
374 "#define myhalf half\n"
375 "#define myhvec2 hvec2\n"
376 "#define myhvec3 hvec3\n"
377 "#define myhvec4 hvec4\n"
378 "#else\n"
379 "#define myhalf float\n"
380 "#define myhvec2 vec2\n"
381 "#define myhvec3 vec3\n"
382 "#define myhvec4 vec4\n"
383 "#endif\n"
384 "\n"
385 "varying vec2 TexCoord;\n"
386 "varying vec2 TexCoordLightmap;\n"
387 "\n"
388 "varying vec3 CubeVector;\n"
389 "varying vec3 LightVector;\n"
390 "varying vec3 EyeVector;\n"
391 "#ifdef USEFOG\n"
392 "varying vec3 EyeVectorModelSpace;\n"
393 "#endif\n"
394 "\n"
395 "varying vec3 VectorS; // direction of S texcoord (sometimes crudely called tangent)\n"
396 "varying vec3 VectorT; // direction of T texcoord (sometimes crudely called binormal)\n"
397 "varying vec3 VectorR; // direction of R texcoord (surface normal)\n"
398 "\n"
399 "\n"
400 "\n"
401 "\n"
402 "// vertex shader specific:\n"
403 "#ifdef VERTEX_SHADER\n"
404 "\n"
405 "uniform vec3 LightPosition;\n"
406 "uniform vec3 EyePosition;\n"
407 "uniform vec3 LightDir;\n"
408 "\n"
409 "// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3)\n"
410 "\n"
411 "void main(void)\n"
412 "{\n"
413 "       gl_FrontColor = gl_Color;\n"
414 "       // copy the surface texcoord\n"
415 "       TexCoord = vec2(gl_TextureMatrix[0] * gl_MultiTexCoord0);\n"
416 "#if !defined(MODE_LIGHTSOURCE) && !defined(MODE_LIGHTDIRECTION)\n"
417 "       TexCoordLightmap = vec2(gl_MultiTexCoord4);\n"
418 "#endif\n"
419 "\n"
420 "#ifdef MODE_LIGHTSOURCE\n"
421 "       // transform vertex position into light attenuation/cubemap space\n"
422 "       // (-1 to +1 across the light box)\n"
423 "       CubeVector = vec3(gl_TextureMatrix[3] * gl_Vertex);\n"
424 "\n"
425 "       // transform unnormalized light direction into tangent space\n"
426 "       // (we use unnormalized to ensure that it interpolates correctly and then\n"
427 "       //  normalize it per pixel)\n"
428 "       vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n"
429 "       LightVector.x = dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
430 "       LightVector.y = dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
431 "       LightVector.z = dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n"
432 "#endif\n"
433 "\n"
434 "#ifdef MODE_LIGHTDIRECTION\n"
435 "       LightVector.x = dot(LightDir, gl_MultiTexCoord1.xyz);\n"
436 "       LightVector.y = dot(LightDir, gl_MultiTexCoord2.xyz);\n"
437 "       LightVector.z = dot(LightDir, gl_MultiTexCoord3.xyz);\n"
438 "#endif\n"
439 "\n"
440 "       // transform unnormalized eye direction into tangent space\n"
441 "#ifndef USEFOG\n"
442 "       vec3 EyeVectorModelSpace;\n"
443 "#endif\n"
444 "       EyeVectorModelSpace = EyePosition - gl_Vertex.xyz;\n"
445 "       EyeVector.x = dot(EyeVectorModelSpace, gl_MultiTexCoord1.xyz);\n"
446 "       EyeVector.y = dot(EyeVectorModelSpace, gl_MultiTexCoord2.xyz);\n"
447 "       EyeVector.z = dot(EyeVectorModelSpace, gl_MultiTexCoord3.xyz);\n"
448 "\n"
449 "#ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
450 "       VectorS = gl_MultiTexCoord1.xyz;\n"
451 "       VectorT = gl_MultiTexCoord2.xyz;\n"
452 "       VectorR = gl_MultiTexCoord3.xyz;\n"
453 "#endif\n"
454 "\n"
455 "       // transform vertex to camera space, using ftransform to match non-VS\n"
456 "       // rendering\n"
457 "       gl_Position = ftransform();\n"
458 "}\n"
459 "\n"
460 "#endif // VERTEX_SHADER\n"
461 "\n"
462 "\n"
463 "\n"
464 "\n"
465 "// fragment shader specific:\n"
466 "#ifdef FRAGMENT_SHADER\n"
467 "\n"
468 "// 11 textures, we can only use up to 16 on DX9-class hardware\n"
469 "uniform sampler2D Texture_Normal;\n"
470 "uniform sampler2D Texture_Color;\n"
471 "uniform sampler2D Texture_Gloss;\n"
472 "uniform samplerCube Texture_Cube;\n"
473 "uniform sampler2D Texture_Attenuation;\n"
474 "uniform sampler2D Texture_FogMask;\n"
475 "uniform sampler2D Texture_Pants;\n"
476 "uniform sampler2D Texture_Shirt;\n"
477 "uniform sampler2D Texture_Lightmap;\n"
478 "uniform sampler2D Texture_Deluxemap;\n"
479 "uniform sampler2D Texture_Glow;\n"
480 "\n"
481 "uniform myhvec3 LightColor;\n"
482 "uniform myhvec3 AmbientColor;\n"
483 "uniform myhvec3 DiffuseColor;\n"
484 "uniform myhvec3 SpecularColor;\n"
485 "uniform myhvec3 Color_Pants;\n"
486 "uniform myhvec3 Color_Shirt;\n"
487 "uniform myhvec3 FogColor;\n"
488 "\n"
489 "uniform myhalf GlowScale;\n"
490 "uniform myhalf SceneBrightness;\n"
491 "#ifdef USECONTRASTBOOST\n"
492 "uniform myhalf ContrastBoostCoeff;\n"
493 "#endif\n"
494 "\n"
495 "uniform float OffsetMapping_Scale;\n"
496 "uniform float OffsetMapping_Bias;\n"
497 "uniform float FogRangeRecip;\n"
498 "\n"
499 "uniform myhalf AmbientScale;\n"
500 "uniform myhalf DiffuseScale;\n"
501 "uniform myhalf SpecularScale;\n"
502 "uniform myhalf SpecularPower;\n"
503 "\n"
504 "#ifdef USEOFFSETMAPPING\n"
505 "vec2 OffsetMapping(vec2 TexCoord)\n"
506 "{\n"
507 "#ifdef USEOFFSETMAPPING_RELIEFMAPPING\n"
508 "       // 14 sample relief mapping: linear search and then binary search\n"
509 "       // this basically steps forward a small amount repeatedly until it finds\n"
510 "       // itself inside solid, then jitters forward and back using decreasing\n"
511 "       // amounts to find the impact\n"
512 "       //vec3 OffsetVector = vec3(EyeVector.xy * ((1.0 / EyeVector.z) * OffsetMapping_Scale) * vec2(-1, 1), -1);\n"
513 "       //vec3 OffsetVector = vec3(normalize(EyeVector.xy) * OffsetMapping_Scale * vec2(-1, 1), -1);\n"
514 "       vec3 OffsetVector = vec3(normalize(EyeVector).xy * OffsetMapping_Scale * vec2(-1, 1), -1);\n"
515 "       vec3 RT = vec3(TexCoord, 1);\n"
516 "       OffsetVector *= 0.1;\n"
517 "       RT += OffsetVector *  step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
518 "       RT += OffsetVector *  step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
519 "       RT += OffsetVector *  step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
520 "       RT += OffsetVector *  step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
521 "       RT += OffsetVector *  step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
522 "       RT += OffsetVector *  step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
523 "       RT += OffsetVector *  step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
524 "       RT += OffsetVector *  step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
525 "       RT += OffsetVector *  step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
526 "       RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z)          - 0.5);\n"
527 "       RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) * 0.5    - 0.25);\n"
528 "       RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) * 0.25   - 0.125);\n"
529 "       RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) * 0.125  - 0.0625);\n"
530 "       RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) * 0.0625 - 0.03125);\n"
531 "       return RT.xy;\n"
532 "#else\n"
533 "       // 3 sample offset mapping (only 3 samples because of ATI Radeon 9500-9800/X300 limits)\n"
534 "       // this basically moves forward the full distance, and then backs up based\n"
535 "       // on height of samples\n"
536 "       //vec2 OffsetVector = vec2(EyeVector.xy * ((1.0 / EyeVector.z) * OffsetMapping_Scale) * vec2(-1, 1));\n"
537 "       //vec2 OffsetVector = vec2(normalize(EyeVector.xy) * OffsetMapping_Scale * vec2(-1, 1));\n"
538 "       vec2 OffsetVector = vec2(normalize(EyeVector).xy * OffsetMapping_Scale * vec2(-1, 1));\n"
539 "       TexCoord += OffsetVector;\n"
540 "       OffsetVector *= 0.333;\n"
541 "       TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
542 "       TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
543 "       TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
544 "       return TexCoord;\n"
545 "#endif\n"
546 "}\n"
547 "#endif\n"
548 "\n"
549 "void main(void)\n"
550 "{\n"
551 "#ifdef USEOFFSETMAPPING\n"
552 "       // apply offsetmapping\n"
553 "       vec2 TexCoordOffset = OffsetMapping(TexCoord);\n"
554 "#define TexCoord TexCoordOffset\n"
555 "#endif\n"
556 "\n"
557 "       // combine the diffuse textures (base, pants, shirt)\n"
558 "       myhvec4 color = myhvec4(texture2D(Texture_Color, TexCoord));\n"
559 "#ifdef USECOLORMAPPING\n"
560 "       color.rgb += myhvec3(texture2D(Texture_Pants, TexCoord)) * Color_Pants + myhvec3(texture2D(Texture_Shirt, TexCoord)) * Color_Shirt;\n"
561 "#endif\n"
562 "\n"
563 "\n"
564 "\n"
565 "\n"
566 "#ifdef MODE_LIGHTSOURCE\n"
567 "       // light source\n"
568 "\n"
569 "       // calculate surface normal, light normal, and specular normal\n"
570 "       // compute color intensity for the two textures (colormap and glossmap)\n"
571 "       // scale by light color and attenuation as efficiently as possible\n"
572 "       // (do as much scalar math as possible rather than vector math)\n"
573 "#ifdef USESPECULAR\n"
574 "       myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5));\n"
575 "       myhvec3 diffusenormal = myhvec3(normalize(LightVector));\n"
576 "       myhvec3 specularnormal = normalize(diffusenormal + myhvec3(normalize(EyeVector)));\n"
577 "\n"
578 "       // calculate directional shading\n"
579 "       color.rgb = LightColor * myhalf(texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0))) * (color.rgb * (AmbientScale + DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0))) + (SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower)) * myhvec3(texture2D(Texture_Gloss, TexCoord)));\n"
580 "#else\n"
581 "#ifdef USEDIFFUSE\n"
582 "       myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5));\n"
583 "       myhvec3 diffusenormal = myhvec3(normalize(LightVector));\n"
584 "\n"
585 "       // calculate directional shading\n"
586 "       color.rgb = color.rgb * LightColor * (myhalf(texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0))) * (AmbientScale + DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0))));\n"
587 "#else\n"
588 "       // calculate directionless shading\n"
589 "       color.rgb = color.rgb * LightColor * myhalf(texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0)));\n"
590 "#endif\n"
591 "#endif\n"
592 "\n"
593 "#ifdef USECUBEFILTER\n"
594 "       // apply light cubemap filter\n"
595 "       //color.rgb *= normalize(CubeVector) * 0.5 + 0.5;//vec3(textureCube(Texture_Cube, CubeVector));\n"
596 "       color.rgb *= myhvec3(textureCube(Texture_Cube, CubeVector));\n"
597 "#endif\n"
598 "\n"
599 "\n"
600 "\n"
601 "\n"
602 "#elif defined(MODE_LIGHTDIRECTION)\n"
603 "       // directional model lighting\n"
604 "\n"
605 "       // get the surface normal and light normal\n"
606 "       myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5));\n"
607 "       myhvec3 diffusenormal = myhvec3(LightVector);\n"
608 "\n"
609 "       // calculate directional shading\n"
610 "       color.rgb *= AmbientColor + DiffuseColor * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0));\n"
611 "#ifdef USESPECULAR\n"
612 "       myhvec3 specularnormal = normalize(diffusenormal + myhvec3(normalize(EyeVector)));\n"
613 "       color.rgb += myhvec3(texture2D(Texture_Gloss, TexCoord)) * SpecularColor * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
614 "#endif\n"
615 "\n"
616 "\n"
617 "\n"
618 "\n"
619 "#elif defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_LIGHTDIRECTIONMAP_TANGENTSPACE)\n"
620 "       // deluxemap lightmapping using light vectors in modelspace (evil q3map2)\n"
621 "\n"
622 "       // get the surface normal and light normal\n"
623 "       myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5));\n"
624 "\n"
625 "#ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
626 "       myhvec3 diffusenormal_modelspace = myhvec3(texture2D(Texture_Deluxemap, TexCoordLightmap)) - myhvec3(0.5);\n"
627 "       myhvec3 diffusenormal = normalize(myhvec3(dot(diffusenormal_modelspace, myhvec3(VectorS)), dot(diffusenormal_modelspace, myhvec3(VectorT)), dot(diffusenormal_modelspace, myhvec3(VectorR))));\n"
628 "#else\n"
629 "       myhvec3 diffusenormal = normalize(myhvec3(texture2D(Texture_Deluxemap, TexCoordLightmap)) - myhvec3(0.5));\n"
630 "#endif\n"
631 "       // calculate directional shading\n"
632 "       myhvec3 tempcolor = color.rgb * (DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0)));\n"
633 "#ifdef USESPECULAR\n"
634 "       myhvec3 specularnormal = myhvec3(normalize(diffusenormal + myhvec3(normalize(EyeVector))));\n"
635 "       tempcolor += myhvec3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
636 "#endif\n"
637 "\n"
638 "       // apply lightmap color\n"
639 "       color.rgb = tempcolor * myhvec3(texture2D(Texture_Lightmap, TexCoordLightmap)) + color.rgb * AmbientScale;\n"
640 "\n"
641 "\n"
642 "#else // MODE none (lightmap)\n"
643 "       // apply lightmap color\n"
644 "       color.rgb *= myhvec3(texture2D(Texture_Lightmap, TexCoordLightmap)) * DiffuseScale + myhvec3(AmbientScale);\n"
645 "#endif // MODE\n"
646 "\n"
647 "       color *= myhvec4(gl_Color);\n"
648 "\n"
649 "#ifdef USEGLOW\n"
650 "       color.rgb += myhvec3(texture2D(Texture_Glow, TexCoord)) * GlowScale;\n"
651 "#endif\n"
652 "\n"
653 "#ifdef USEFOG\n"
654 "       // apply fog\n"
655 "       color.rgb = mix(FogColor, color.rgb, myhalf(texture2D(Texture_FogMask, myhvec2(length(EyeVectorModelSpace)*FogRangeRecip, 0.0))));\n"
656 "#endif\n"
657 "\n"
658 "#ifdef USECONTRASTBOOST\n"
659 "       color.rgb = color.rgb * SceneBrightness / (ContrastBoostCoeff * color.rgb + myhvec3(1, 1, 1));\n"
660 "#else\n"
661 "       color.rgb *= SceneBrightness;\n"
662 "#endif\n"
663 "\n"
664 "       gl_FragColor = vec4(color);\n"
665 "}\n"
666 "\n"
667 "#endif // FRAGMENT_SHADER\n"
668 ;
669
670 // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
671 const char *permutationinfo[][2] =
672 {
673         {"#define MODE_LIGHTSOURCE\n", " lightsource"},
674         {"#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
675         {"#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
676         {"#define MODE_LIGHTDIRECTION\n", " lightdirection"},
677         {"#define USEGLOW\n", " glow"},
678         {"#define USEFOG\n", " fog"},
679         {"#define USECOLORMAPPING\n", " colormapping"},
680         {"#define USEDIFFUSE\n", " diffuse"},
681         {"#define USECONTRASTBOOST\n", " contrastboost"},
682         {"#define USESPECULAR\n", " specular"},
683         {"#define USECUBEFILTER\n", " cubefilter"},
684         {"#define USEOFFSETMAPPING\n", " offsetmapping"},
685         {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
686         {NULL, NULL}
687 };
688
689 void R_GLSL_CompilePermutation(const char *filename, int permutation)
690 {
691         int i;
692         qboolean shaderfound;
693         r_glsl_permutation_t *p = r_glsl_permutations + (permutation & SHADERPERMUTATION_MASK);
694         int vertstrings_count;
695         int geomstrings_count;
696         int fragstrings_count;
697         char *shaderstring;
698         const char *vertstrings_list[32+1];
699         const char *geomstrings_list[32+1];
700         const char *fragstrings_list[32+1];
701         char permutationname[256];
702         if (p->compiled)
703                 return;
704         p->compiled = true;
705         p->program = 0;
706         vertstrings_list[0] = "#define VERTEX_SHADER\n";
707         geomstrings_list[0] = "#define GEOMETRY_SHADER\n";
708         fragstrings_list[0] = "#define FRAGMENT_SHADER\n";
709         vertstrings_count = 1;
710         geomstrings_count = 1;
711         fragstrings_count = 1;
712         permutationname[0] = 0;
713         for (i = 0;permutationinfo[i][0];i++)
714         {
715                 if (permutation & (1<<i))
716                 {
717                         vertstrings_list[vertstrings_count++] = permutationinfo[i][0];
718                         geomstrings_list[geomstrings_count++] = permutationinfo[i][0];
719                         fragstrings_list[fragstrings_count++] = permutationinfo[i][0];
720                         strlcat(permutationname, permutationinfo[i][1], sizeof(permutationname));
721                 }
722                 else
723                 {
724                         // keep line numbers correct
725                         vertstrings_list[vertstrings_count++] = "\n";
726                         geomstrings_list[geomstrings_count++] = "\n";
727                         fragstrings_list[fragstrings_count++] = "\n";
728                 }
729         }
730         shaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL);
731         shaderfound = false;
732         if (shaderstring)
733         {
734                 Con_DPrintf("GLSL shader text for \"%s\" loaded from disk\n", filename);
735                 vertstrings_list[vertstrings_count++] = shaderstring;
736                 geomstrings_list[geomstrings_count++] = shaderstring;
737                 fragstrings_list[fragstrings_count++] = shaderstring;
738                 shaderfound = true;
739         }
740         else if (!strcmp(filename, "glsl/default.glsl"))
741         {
742                 Con_DPrintf("GLSL shader text for \"%s\" loaded from engine\n", filename);
743                 vertstrings_list[vertstrings_count++] = builtinshaderstring;
744                 geomstrings_list[geomstrings_count++] = builtinshaderstring;
745                 fragstrings_list[fragstrings_count++] = builtinshaderstring;
746                 shaderfound = true;
747         }
748         // clear any lists that are not needed by this shader
749         if (!(permutation & SHADERPERMUTATION_USES_VERTEXSHADER))
750                 vertstrings_count = 0;
751         if (!(permutation & SHADERPERMUTATION_USES_GEOMETRYSHADER))
752                 geomstrings_count = 0;
753         if (!(permutation & SHADERPERMUTATION_USES_FRAGMENTSHADER))
754                 fragstrings_count = 0;
755         // compile the shader program
756         if (shaderfound && vertstrings_count + geomstrings_count + fragstrings_count)
757                 p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
758         if (p->program)
759         {
760                 CHECKGLERROR
761                 qglUseProgramObjectARB(p->program);CHECKGLERROR
762                 // look up all the uniform variable names we care about, so we don't
763                 // have to look them up every time we set them
764                 p->loc_Texture_Normal      = qglGetUniformLocationARB(p->program, "Texture_Normal");
765                 p->loc_Texture_Color       = qglGetUniformLocationARB(p->program, "Texture_Color");
766                 p->loc_Texture_Gloss       = qglGetUniformLocationARB(p->program, "Texture_Gloss");
767                 p->loc_Texture_Cube        = qglGetUniformLocationARB(p->program, "Texture_Cube");
768                 p->loc_Texture_Attenuation = qglGetUniformLocationARB(p->program, "Texture_Attenuation");
769                 p->loc_Texture_FogMask     = qglGetUniformLocationARB(p->program, "Texture_FogMask");
770                 p->loc_Texture_Pants       = qglGetUniformLocationARB(p->program, "Texture_Pants");
771                 p->loc_Texture_Shirt       = qglGetUniformLocationARB(p->program, "Texture_Shirt");
772                 p->loc_Texture_Lightmap    = qglGetUniformLocationARB(p->program, "Texture_Lightmap");
773                 p->loc_Texture_Deluxemap   = qglGetUniformLocationARB(p->program, "Texture_Deluxemap");
774                 p->loc_Texture_Glow        = qglGetUniformLocationARB(p->program, "Texture_Glow");
775                 p->loc_FogColor            = qglGetUniformLocationARB(p->program, "FogColor");
776                 p->loc_LightPosition       = qglGetUniformLocationARB(p->program, "LightPosition");
777                 p->loc_EyePosition         = qglGetUniformLocationARB(p->program, "EyePosition");
778                 p->loc_LightColor          = qglGetUniformLocationARB(p->program, "LightColor");
779                 p->loc_Color_Pants         = qglGetUniformLocationARB(p->program, "Color_Pants");
780                 p->loc_Color_Shirt         = qglGetUniformLocationARB(p->program, "Color_Shirt");
781                 p->loc_FogRangeRecip       = qglGetUniformLocationARB(p->program, "FogRangeRecip");
782                 p->loc_AmbientScale        = qglGetUniformLocationARB(p->program, "AmbientScale");
783                 p->loc_DiffuseScale        = qglGetUniformLocationARB(p->program, "DiffuseScale");
784                 p->loc_SpecularPower       = qglGetUniformLocationARB(p->program, "SpecularPower");
785                 p->loc_SpecularScale       = qglGetUniformLocationARB(p->program, "SpecularScale");
786                 p->loc_GlowScale           = qglGetUniformLocationARB(p->program, "GlowScale");
787                 p->loc_SceneBrightness     = qglGetUniformLocationARB(p->program, "SceneBrightness");
788                 p->loc_OffsetMapping_Scale = qglGetUniformLocationARB(p->program, "OffsetMapping_Scale");
789                 p->loc_AmbientColor        = qglGetUniformLocationARB(p->program, "AmbientColor");
790                 p->loc_DiffuseColor        = qglGetUniformLocationARB(p->program, "DiffuseColor");
791                 p->loc_SpecularColor       = qglGetUniformLocationARB(p->program, "SpecularColor");
792                 p->loc_LightDir            = qglGetUniformLocationARB(p->program, "LightDir");
793                 p->loc_ContrastBoostCoeff  = qglGetUniformLocationARB(p->program, "ContrastBoostCoeff");
794                 // initialize the samplers to refer to the texture units we use
795                 if (p->loc_Texture_Normal >= 0)    qglUniform1iARB(p->loc_Texture_Normal, 0);
796                 if (p->loc_Texture_Color >= 0)     qglUniform1iARB(p->loc_Texture_Color, 1);
797                 if (p->loc_Texture_Gloss >= 0)     qglUniform1iARB(p->loc_Texture_Gloss, 2);
798                 if (p->loc_Texture_Cube >= 0)      qglUniform1iARB(p->loc_Texture_Cube, 3);
799                 if (p->loc_Texture_FogMask >= 0)   qglUniform1iARB(p->loc_Texture_FogMask, 4);
800                 if (p->loc_Texture_Pants >= 0)     qglUniform1iARB(p->loc_Texture_Pants, 5);
801                 if (p->loc_Texture_Shirt >= 0)     qglUniform1iARB(p->loc_Texture_Shirt, 6);
802                 if (p->loc_Texture_Lightmap >= 0)  qglUniform1iARB(p->loc_Texture_Lightmap, 7);
803                 if (p->loc_Texture_Deluxemap >= 0) qglUniform1iARB(p->loc_Texture_Deluxemap, 8);
804                 if (p->loc_Texture_Glow >= 0)      qglUniform1iARB(p->loc_Texture_Glow, 9);
805                 if (p->loc_Texture_Attenuation >= 0) qglUniform1iARB(p->loc_Texture_Attenuation, 10);
806                 CHECKGLERROR
807                 qglUseProgramObjectARB(0);CHECKGLERROR
808         }
809         else
810                 Con_Printf("permutation%s failed for shader %s, some features may not work properly!\n", permutationname, filename);
811         if (shaderstring)
812                 Mem_Free(shaderstring);
813 }
814
815 void R_GLSL_Restart_f(void)
816 {
817         int i;
818         for (i = 0;i < SHADERPERMUTATION_MAX;i++)
819                 if (r_glsl_permutations[i].program)
820                         GL_Backend_FreeProgram(r_glsl_permutations[i].program);
821         memset(r_glsl_permutations, 0, sizeof(r_glsl_permutations));
822 }
823
824 void R_GLSL_DumpShader_f(void)
825 {
826         int i;
827
828         qfile_t *file = FS_Open("glsl/default.glsl", "w", false, false);
829         if(!file)
830         {
831                 Con_Printf("failed to write to glsl/default.glsl\n");
832                 return;
833         }
834
835         FS_Print(file, "// The engine may define the following macros:\n");
836         FS_Print(file, "// #define VERTEX_SHADER\n// #define GEOMETRY_SHADER\n// #define FRAGMENT_SHADER\n");
837         for (i = 0;permutationinfo[i][0];i++)
838                 FS_Printf(file, "// %s", permutationinfo[i][0]);
839         FS_Print(file, "\n");
840         FS_Print(file, builtinshaderstring);
841         FS_Close(file);
842
843         Con_Printf("data/default.glsl written\n");
844 }
845
846 extern rtexture_t *r_shadow_attenuationgradienttexture;
847 extern rtexture_t *r_shadow_attenuation2dtexture;
848 extern rtexture_t *r_shadow_attenuation3dtexture;
849 int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, float ambientscale, float diffusescale, float specularscale)
850 {
851         // select a permutation of the lighting shader appropriate to this
852         // combination of texture, entity, light source, and fogging, only use the
853         // minimum features necessary to avoid wasting rendering time in the
854         // fragment shader on features that are not being used
855         const char *shaderfilename = NULL;
856         unsigned int permutation = 0;
857         r_glsl_permutation = NULL;
858         // TODO: implement geometry-shader based shadow volumes someday
859         if (rsurface.rtlight)
860         {
861                 // light source
862                 shaderfilename = "glsl/default.glsl";
863                 permutation = SHADERPERMUTATION_MODE_LIGHTSOURCE | SHADERPERMUTATION_USES_VERTEXSHADER | SHADERPERMUTATION_USES_FRAGMENTSHADER;
864                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
865                         permutation |= SHADERPERMUTATION_CUBEFILTER;
866                 if (diffusescale > 0)
867                         permutation |= SHADERPERMUTATION_DIFFUSE;
868                 if (specularscale > 0)
869                         permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
870                 if (r_refdef.fogenabled)
871                         permutation |= SHADERPERMUTATION_FOG;
872                 if (rsurface.texture->colormapping)
873                         permutation |= SHADERPERMUTATION_COLORMAPPING;
874                 if (r_glsl_offsetmapping.integer)
875                 {
876                         permutation |= SHADERPERMUTATION_OFFSETMAPPING;
877                         if (r_glsl_offsetmapping_reliefmapping.integer)
878                                 permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
879                 }
880                 if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
881                         permutation |= SHADERPERMUTATION_CONTRASTBOOST;
882         }
883         else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
884         {
885                 // bright unshaded geometry
886                 shaderfilename = "glsl/default.glsl";
887                 permutation = SHADERPERMUTATION_USES_VERTEXSHADER | SHADERPERMUTATION_USES_FRAGMENTSHADER;
888                 if (rsurface.texture->currentskinframe->glow)
889                         permutation |= SHADERPERMUTATION_GLOW;
890                 if (r_refdef.fogenabled)
891                         permutation |= SHADERPERMUTATION_FOG;
892                 if (rsurface.texture->colormapping)
893                         permutation |= SHADERPERMUTATION_COLORMAPPING;
894                 if (r_glsl_offsetmapping.integer)
895                 {
896                         permutation |= SHADERPERMUTATION_OFFSETMAPPING;
897                         if (r_glsl_offsetmapping_reliefmapping.integer)
898                                 permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
899                 }
900                 if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
901                         permutation |= SHADERPERMUTATION_CONTRASTBOOST;
902         }
903         else if (modellighting)
904         {
905                 // directional model lighting
906                 shaderfilename = "glsl/default.glsl";
907                 permutation = SHADERPERMUTATION_USES_VERTEXSHADER | SHADERPERMUTATION_USES_FRAGMENTSHADER;
908                 permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTION;
909                 if (rsurface.texture->currentskinframe->glow)
910                         permutation |= SHADERPERMUTATION_GLOW;
911                 if (specularscale > 0)
912                         permutation |= SHADERPERMUTATION_SPECULAR;
913                 if (r_refdef.fogenabled)
914                         permutation |= SHADERPERMUTATION_FOG;
915                 if (rsurface.texture->colormapping)
916                         permutation |= SHADERPERMUTATION_COLORMAPPING;
917                 if (r_glsl_offsetmapping.integer)
918                 {
919                         permutation |= SHADERPERMUTATION_OFFSETMAPPING;
920                         if (r_glsl_offsetmapping_reliefmapping.integer)
921                                 permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
922                 }
923                 if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
924                         permutation |= SHADERPERMUTATION_CONTRASTBOOST;
925         }
926         else
927         {
928                 // lightmapped wall
929                 shaderfilename = "glsl/default.glsl";
930                 permutation = SHADERPERMUTATION_USES_VERTEXSHADER | SHADERPERMUTATION_USES_FRAGMENTSHADER;
931                 if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping)
932                 {
933                         // deluxemapping (light direction texture)
934                         if (rsurface.uselightmaptexture && r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping && r_refdef.worldmodel->brushq3.deluxemapping_modelspace)
935                                 permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_MODELSPACE;
936                         else
937                                 permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
938                         if (specularscale > 0)
939                                 permutation |= SHADERPERMUTATION_SPECULAR;
940                 }
941                 else if (r_glsl_deluxemapping.integer >= 2)
942                 {
943                         // fake deluxemapping (uniform light direction in tangentspace)
944                         permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
945                         if (specularscale > 0)
946                                 permutation |= SHADERPERMUTATION_SPECULAR;
947                 }
948                 else
949                 {
950                         // ordinary lightmapping
951                         permutation |= 0;
952                 }
953                 if (rsurface.texture->currentskinframe->glow)
954                         permutation |= SHADERPERMUTATION_GLOW;
955                 if (r_refdef.fogenabled)
956                         permutation |= SHADERPERMUTATION_FOG;
957                 if (rsurface.texture->colormapping)
958                         permutation |= SHADERPERMUTATION_COLORMAPPING;
959                 if (r_glsl_offsetmapping.integer)
960                 {
961                         permutation |= SHADERPERMUTATION_OFFSETMAPPING;
962                         if (r_glsl_offsetmapping_reliefmapping.integer)
963                                 permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
964                 }
965                 if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
966                         permutation |= SHADERPERMUTATION_CONTRASTBOOST;
967         }
968         if (!r_glsl_permutations[permutation & SHADERPERMUTATION_MASK].program)
969         {
970                 if (!r_glsl_permutations[permutation & SHADERPERMUTATION_MASK].compiled)
971                         R_GLSL_CompilePermutation(shaderfilename, permutation);
972                 if (!r_glsl_permutations[permutation & SHADERPERMUTATION_MASK].program)
973                 {
974                         // remove features until we find a valid permutation
975                         unsigned int i;
976                         for (i = (SHADERPERMUTATION_MAX >> 1);;i>>=1)
977                         {
978                                 if (!i)
979                                         return 0; // no bit left to clear
980                                 // reduce i more quickly whenever it would not remove any bits
981                                 if (!(permutation & i))
982                                         continue;
983                                 permutation &= ~i;
984                                 if (!r_glsl_permutations[permutation & SHADERPERMUTATION_MASK].compiled)
985                                         R_GLSL_CompilePermutation(shaderfilename, permutation);
986                                 if (r_glsl_permutations[permutation & SHADERPERMUTATION_MASK].program)
987                                         break;
988                         }
989                 }
990         }
991         r_glsl_permutation = r_glsl_permutations + (permutation & SHADERPERMUTATION_MASK);
992         CHECKGLERROR
993         qglUseProgramObjectARB(r_glsl_permutation->program);CHECKGLERROR
994         R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
995         if (permutation & SHADERPERMUTATION_MODE_LIGHTSOURCE)
996         {
997                 if (r_glsl_permutation->loc_Texture_Cube >= 0 && rsurface.rtlight) R_Mesh_TexBindCubeMap(3, R_GetTexture(rsurface.rtlight->currentcubemap));
998                 if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
999                 if (permutation & SHADERPERMUTATION_DIFFUSE)
1000                 {
1001                         if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightColor, lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);
1002                         if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, ambientscale);
1003                         if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, diffusescale);
1004                         if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, specularscale);
1005                 }
1006                 else
1007                 {
1008                         // ambient only is simpler
1009                         if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightColor, lightcolorbase[0] * ambientscale, lightcolorbase[1] * ambientscale, lightcolorbase[2] * ambientscale);
1010                         if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, 1);
1011                         if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, 0);
1012                         if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, 0);
1013                 }
1014         }
1015         else if (permutation & SHADERPERMUTATION_MODE_LIGHTDIRECTION)
1016         {
1017                 if (r_glsl_permutation->loc_AmbientColor >= 0)
1018                         qglUniform3fARB(r_glsl_permutation->loc_AmbientColor, rsurface.modellight_ambient[0] * ambientscale, rsurface.modellight_ambient[1] * ambientscale, rsurface.modellight_ambient[2] * ambientscale);
1019                 if (r_glsl_permutation->loc_DiffuseColor >= 0)
1020                         qglUniform3fARB(r_glsl_permutation->loc_DiffuseColor, rsurface.modellight_diffuse[0] * diffusescale, rsurface.modellight_diffuse[1] * diffusescale, rsurface.modellight_diffuse[2] * diffusescale);
1021                 if (r_glsl_permutation->loc_SpecularColor >= 0)
1022                         qglUniform3fARB(r_glsl_permutation->loc_SpecularColor, rsurface.modellight_diffuse[0] * specularscale, rsurface.modellight_diffuse[1] * specularscale, rsurface.modellight_diffuse[2] * specularscale);
1023                 if (r_glsl_permutation->loc_LightDir >= 0)
1024                         qglUniform3fARB(r_glsl_permutation->loc_LightDir, rsurface.modellight_lightdir[0], rsurface.modellight_lightdir[1], rsurface.modellight_lightdir[2]);
1025         }
1026         else
1027         {
1028                 if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, r_ambient.value * 2.0f / 128.0f);
1029                 if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, r_refdef.lightmapintensity * 2.0f);
1030                 if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, r_refdef.lightmapintensity * specularscale * 2.0f);
1031         }
1032         if (r_glsl_permutation->loc_Texture_Normal >= 0) R_Mesh_TexBind(0, R_GetTexture(rsurface.texture->currentskinframe->nmap));
1033         if (r_glsl_permutation->loc_Texture_Color >= 0) R_Mesh_TexBind(1, R_GetTexture(rsurface.texture->basetexture));
1034         if (r_glsl_permutation->loc_Texture_Gloss >= 0) R_Mesh_TexBind(2, R_GetTexture(rsurface.texture->glosstexture));
1035         //if (r_glsl_permutation->loc_Texture_Cube >= 0 && permutation & SHADERPERMUTATION_MODE_LIGHTSOURCE) R_Mesh_TexBindCubeMap(3, R_GetTexture(rsurface.rtlight->currentcubemap));
1036         if (r_glsl_permutation->loc_Texture_Attenuation >= 0) R_Mesh_TexBind(10, R_GetTexture(r_shadow_attenuationgradienttexture));
1037         if (r_glsl_permutation->loc_Texture_FogMask >= 0) R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation));
1038         if (r_glsl_permutation->loc_Texture_Pants >= 0) R_Mesh_TexBind(5, R_GetTexture(rsurface.texture->currentskinframe->pants));
1039         if (r_glsl_permutation->loc_Texture_Shirt >= 0) R_Mesh_TexBind(6, R_GetTexture(rsurface.texture->currentskinframe->shirt));
1040         //if (r_glsl_permutation->loc_Texture_Lightmap >= 0) R_Mesh_TexBind(7, R_GetTexture(r_texture_white));
1041         //if (r_glsl_permutation->loc_Texture_Deluxemap >= 0) R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
1042         if (r_glsl_permutation->loc_Texture_Glow >= 0) R_Mesh_TexBind(9, R_GetTexture(rsurface.texture->currentskinframe->glow));
1043         if (r_glsl_permutation->loc_GlowScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_GlowScale, r_hdr_glowintensity.value);
1044         if (r_glsl_permutation->loc_ContrastBoostCoeff >= 0)
1045         {
1046                 // The formula used is actually:
1047                 //   color.rgb *= SceneBrightness;
1048                 //   color.rgb *= ContrastBoost / ((ContrastBoost - 1) * color.rgb + 1);
1049                 // I simplify that to
1050                 //   color.rgb *= [[SceneBrightness * ContrastBoost]];
1051                 //   color.rgb /= [[(ContrastBoost - 1) / ContrastBoost]] * color.rgb + 1;
1052                 // and Black:
1053                 //   color.rgb = [[SceneBrightness * ContrastBoost]] / ([[(ContrastBoost - 1) * SceneBrightness]] + 1 / color.rgb);
1054                 // and do [[calculations]] here in the engine
1055                 qglUniform1fARB(r_glsl_permutation->loc_ContrastBoostCoeff, (r_glsl_contrastboost.value - 1) * r_view.colorscale);
1056                 if (r_glsl_permutation->loc_SceneBrightness >= 0) qglUniform1fARB(r_glsl_permutation->loc_SceneBrightness, r_view.colorscale * r_glsl_contrastboost.value);
1057         }
1058         else
1059                 if (r_glsl_permutation->loc_SceneBrightness >= 0) qglUniform1fARB(r_glsl_permutation->loc_SceneBrightness, r_view.colorscale);
1060         if (r_glsl_permutation->loc_FogColor >= 0)
1061         {
1062                 // additive passes are only darkened by fog, not tinted
1063                 if (rsurface.rtlight || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ADD))
1064                         qglUniform3fARB(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1065                 else
1066                         qglUniform3fARB(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1067         }
1068         if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_EyePosition, rsurface.modelorg[0], rsurface.modelorg[1], rsurface.modelorg[2]);
1069         if (r_glsl_permutation->loc_Color_Pants >= 0)
1070         {
1071                 if (rsurface.texture->currentskinframe->pants)
1072                         qglUniform3fARB(r_glsl_permutation->loc_Color_Pants, rsurface.colormap_pantscolor[0], rsurface.colormap_pantscolor[1], rsurface.colormap_pantscolor[2]);
1073                 else
1074                         qglUniform3fARB(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
1075         }
1076         if (r_glsl_permutation->loc_Color_Shirt >= 0)
1077         {
1078                 if (rsurface.texture->currentskinframe->shirt)
1079                         qglUniform3fARB(r_glsl_permutation->loc_Color_Shirt, rsurface.colormap_shirtcolor[0], rsurface.colormap_shirtcolor[1], rsurface.colormap_shirtcolor[2]);
1080                 else
1081                         qglUniform3fARB(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
1082         }
1083         if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1fARB(r_glsl_permutation->loc_FogRangeRecip, r_refdef.fograngerecip);
1084         if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularPower, rsurface.texture->specularpower);
1085         if (r_glsl_permutation->loc_OffsetMapping_Scale >= 0) qglUniform1fARB(r_glsl_permutation->loc_OffsetMapping_Scale, r_glsl_offsetmapping_scale.value);
1086         CHECKGLERROR
1087         return permutation;
1088 }
1089
1090 void R_SwitchSurfaceShader(int permutation)
1091 {
1092         if (r_glsl_permutation != r_glsl_permutations + (permutation & SHADERPERMUTATION_MASK))
1093         {
1094                 r_glsl_permutation = r_glsl_permutations + (permutation & SHADERPERMUTATION_MASK);
1095                 CHECKGLERROR
1096                 qglUseProgramObjectARB(r_glsl_permutation->program);
1097                 CHECKGLERROR
1098         }
1099 }
1100
1101 #define SKINFRAME_HASH 1024
1102
1103 struct
1104 {
1105         int loadsequence; // incremented each level change
1106         memexpandablearray_t array;
1107         skinframe_t *hash[SKINFRAME_HASH];
1108 }
1109 r_skinframe;
1110
1111 void R_SkinFrame_PrepareForPurge(void)
1112 {
1113         r_skinframe.loadsequence++;
1114         // wrap it without hitting zero
1115         if (r_skinframe.loadsequence >= 200)
1116                 r_skinframe.loadsequence = 1;
1117 }
1118
1119 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
1120 {
1121         if (!skinframe)
1122                 return;
1123         // mark the skinframe as used for the purging code
1124         skinframe->loadsequence = r_skinframe.loadsequence;
1125 }
1126
1127 void R_SkinFrame_Purge(void)
1128 {
1129         int i;
1130         skinframe_t *s;
1131         for (i = 0;i < SKINFRAME_HASH;i++)
1132         {
1133                 for (s = r_skinframe.hash[i];s;s = s->next)
1134                 {
1135                         if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
1136                         {
1137                                 if (s->base == r_texture_notexture)     s->base   = NULL;
1138                                 if (s->nmap == r_texture_blanknormalmap)s->nmap   = NULL;
1139                                 if (s->merged == s->base)               s->merged = NULL;
1140                                 if (s->stain ) R_FreeTexture(s->stain );s->stain  = NULL;
1141                                 if (s->merged) R_FreeTexture(s->merged);s->merged = NULL;
1142                                 if (s->base  ) R_FreeTexture(s->base  );s->base   = NULL;
1143                                 if (s->pants ) R_FreeTexture(s->pants );s->pants  = NULL;
1144                                 if (s->shirt ) R_FreeTexture(s->shirt );s->shirt  = NULL;
1145                                 if (s->nmap  ) R_FreeTexture(s->nmap  );s->nmap   = NULL;
1146                                 if (s->gloss ) R_FreeTexture(s->gloss );s->gloss  = NULL;
1147                                 if (s->glow  ) R_FreeTexture(s->glow  );s->glow   = NULL;
1148                                 if (s->fog   ) R_FreeTexture(s->fog   );s->fog    = NULL;
1149                                 s->loadsequence = 0;
1150                         }
1151                 }
1152         }
1153 }
1154
1155 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qboolean add)
1156 {
1157         skinframe_t *item;
1158         int hashindex;
1159         char basename[MAX_QPATH];
1160
1161         Image_StripImageExtension(name, basename, sizeof(basename));
1162
1163         hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
1164         for (item = r_skinframe.hash[hashindex];item;item = item->next)
1165                 if (!strcmp(item->basename, basename) && item->textureflags == textureflags && item->comparewidth == comparewidth && item->compareheight == compareheight && item->comparecrc == comparecrc)
1166                         break;
1167         if (!item)
1168         {
1169                 if (!add)
1170                         return NULL;
1171                 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
1172                 memset(item, 0, sizeof(*item));
1173                 strlcpy(item->basename, basename, sizeof(item->basename));
1174                 item->textureflags = textureflags;
1175                 item->comparewidth = comparewidth;
1176                 item->compareheight = compareheight;
1177                 item->comparecrc = comparecrc;
1178                 item->next = r_skinframe.hash[hashindex];
1179                 r_skinframe.hash[hashindex] = item;
1180         }
1181         R_SkinFrame_MarkUsed(item);
1182         return item;
1183 }
1184
1185 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain)
1186 {
1187         // FIXME: it should be possible to disable loading various layers using
1188         // cvars, to prevent wasted loading time and memory usage if the user does
1189         // not want them
1190         qboolean loadnormalmap = true;
1191         qboolean loadgloss = true;
1192         qboolean loadpantsandshirt = true;
1193         qboolean loadglow = true;
1194         int j;
1195         unsigned char *pixels;
1196         unsigned char *bumppixels;
1197         unsigned char *basepixels = NULL;
1198         int basepixels_width;
1199         int basepixels_height;
1200         skinframe_t *skinframe;
1201
1202         if (cls.state == ca_dedicated)
1203                 return NULL;
1204
1205         // return an existing skinframe if already loaded
1206         // if loading of the first image fails, don't make a new skinframe as it
1207         // would cause all future lookups of this to be missing
1208         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
1209         if (skinframe && skinframe->base)
1210                 return skinframe;
1211
1212         basepixels = loadimagepixels(name, complain, 0, 0);
1213         if (basepixels == NULL)
1214                 return NULL;
1215
1216         // we've got some pixels to store, so really allocate this new texture now
1217         if (!skinframe)
1218                 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
1219         skinframe->stain = NULL;
1220         skinframe->merged = NULL;
1221         skinframe->base = r_texture_notexture;
1222         skinframe->pants = NULL;
1223         skinframe->shirt = NULL;
1224         skinframe->nmap = r_texture_blanknormalmap;
1225         skinframe->gloss = NULL;
1226         skinframe->glow = NULL;
1227         skinframe->fog = NULL;
1228
1229         basepixels_width = image_width;
1230         basepixels_height = image_height;
1231         skinframe->base = R_LoadTexture2D (r_main_texturepool, skinframe->basename, basepixels_width, basepixels_height, basepixels, TEXTYPE_RGBA, skinframe->textureflags, NULL);
1232
1233         if (textureflags & TEXF_ALPHA)
1234         {
1235                 for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
1236                         if (basepixels[j] < 255)
1237                                 break;
1238                 if (j < basepixels_width * basepixels_height * 4)
1239                 {
1240                         // has transparent pixels
1241                         pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
1242                         for (j = 0;j < image_width * image_height * 4;j += 4)
1243                         {
1244                                 pixels[j+0] = 255;
1245                                 pixels[j+1] = 255;
1246                                 pixels[j+2] = 255;
1247                                 pixels[j+3] = basepixels[j+3];
1248                         }
1249                         skinframe->fog = R_LoadTexture2D (r_main_texturepool, va("%s_mask", skinframe->basename), image_width, image_height, pixels, TEXTYPE_RGBA, skinframe->textureflags, NULL);
1250                         Mem_Free(pixels);
1251                 }
1252         }
1253
1254         // _norm is the name used by tenebrae and has been adopted as standard
1255         if (loadnormalmap)
1256         {
1257                 if ((pixels = loadimagepixels(va("%s_norm", skinframe->basename), false, 0, 0)) != NULL)
1258                 {
1259                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va("%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_RGBA, skinframe->textureflags, NULL);
1260                         Mem_Free(pixels);
1261                         pixels = NULL;
1262                 }
1263                 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixels(va("%s_bump", skinframe->basename), false, 0, 0)) != NULL)
1264                 {
1265                         pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
1266                         Image_HeightmapToNormalmap(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
1267                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va("%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_RGBA, skinframe->textureflags, NULL);
1268                         Mem_Free(pixels);
1269                         Mem_Free(bumppixels);
1270                 }
1271                 else if (r_shadow_bumpscale_basetexture.value > 0)
1272                 {
1273                         pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
1274                         Image_HeightmapToNormalmap(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
1275                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va("%s_nmap", skinframe->basename), basepixels_width, basepixels_height, pixels, TEXTYPE_RGBA, skinframe->textureflags, NULL);
1276                         Mem_Free(pixels);
1277                 }
1278         }
1279         // _luma is supported for tenebrae compatibility
1280         // (I think it's a very stupid name, but oh well)
1281         // _glow is the preferred name
1282         if (loadglow          && ((pixels = loadimagepixels(va("%s_glow", skinframe->basename), false, 0, 0)) != NULL || (pixels = loadimagepixels(va("%s_luma", skinframe->basename), false, 0, 0)) != NULL)) {skinframe->glow = R_LoadTexture2D (r_main_texturepool, va("%s_glow", skinframe->basename), image_width, image_height, pixels, TEXTYPE_RGBA, skinframe->textureflags, NULL);Mem_Free(pixels);pixels = NULL;}
1283         if (loadgloss         && (pixels = loadimagepixels(va("%s_gloss", skinframe->basename), false, 0, 0)) != NULL) {skinframe->gloss = R_LoadTexture2D (r_main_texturepool, va("%s_gloss", skinframe->basename), image_width, image_height, pixels, TEXTYPE_RGBA, skinframe->textureflags, NULL);Mem_Free(pixels);pixels = NULL;}
1284         if (loadpantsandshirt && (pixels = loadimagepixels(va("%s_pants", skinframe->basename), false, 0, 0)) != NULL) {skinframe->pants = R_LoadTexture2D (r_main_texturepool, va("%s_pants", skinframe->basename), image_width, image_height, pixels, TEXTYPE_RGBA, skinframe->textureflags, NULL);Mem_Free(pixels);pixels = NULL;}
1285         if (loadpantsandshirt && (pixels = loadimagepixels(va("%s_shirt", skinframe->basename), false, 0, 0)) != NULL) {skinframe->shirt = R_LoadTexture2D (r_main_texturepool, va("%s_shirt", skinframe->basename), image_width, image_height, pixels, TEXTYPE_RGBA, skinframe->textureflags, NULL);Mem_Free(pixels);pixels = NULL;}
1286
1287         if (basepixels)
1288                 Mem_Free(basepixels);
1289
1290         return skinframe;
1291 }
1292
1293 static rtexture_t *R_SkinFrame_TextureForSkinLayer(const unsigned char *in, int width, int height, const char *name, const unsigned int *palette, int textureflags, qboolean force)
1294 {
1295         int i;
1296         if (!force)
1297         {
1298                 for (i = 0;i < width*height;i++)
1299                         if (((unsigned char *)&palette[in[i]])[3] > 0)
1300                                 break;
1301                 if (i == width*height)
1302                         return NULL;
1303         }
1304         return R_LoadTexture2D (r_main_texturepool, name, width, height, in, TEXTYPE_PALETTE, textureflags, palette);
1305 }
1306
1307 skinframe_t *R_SkinFrame_LoadInternal(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height, int bitsperpixel, const unsigned int *palette, const unsigned int *alphapalette)
1308 {
1309         int i;
1310         unsigned char *temp1, *temp2;
1311         skinframe_t *skinframe;
1312
1313         if (cls.state == ca_dedicated)
1314                 return NULL;
1315
1316         // if already loaded just return it, otherwise make a new skinframe
1317         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height*bitsperpixel/8) : 0, true);
1318         if (skinframe && skinframe->base)
1319                 return skinframe;
1320
1321         skinframe->stain = NULL;
1322         skinframe->merged = NULL;
1323         skinframe->base = r_texture_notexture;
1324         skinframe->pants = NULL;
1325         skinframe->shirt = NULL;
1326         skinframe->nmap = r_texture_blanknormalmap;
1327         skinframe->gloss = NULL;
1328         skinframe->glow = NULL;
1329         skinframe->fog = NULL;
1330
1331         // if no data was provided, then clearly the caller wanted to get a blank skinframe
1332         if (!skindata)
1333                 return NULL;
1334
1335         if (bitsperpixel == 32)
1336         {
1337                 if (r_shadow_bumpscale_basetexture.value > 0)
1338                 {
1339                         temp1 = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
1340                         temp2 = temp1 + width * height * 4;
1341                         Image_HeightmapToNormalmap(skindata, temp2, width, height, false, r_shadow_bumpscale_basetexture.value);
1342                         skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va("%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_RGBA, textureflags | TEXF_ALPHA, NULL);
1343                         Mem_Free(temp1);
1344                 }
1345                 skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_RGBA, textureflags, NULL);
1346                 if (textureflags & TEXF_ALPHA)
1347                 {
1348                         for (i = 3;i < width * height * 4;i += 4)
1349                                 if (skindata[i] < 255)
1350                                         break;
1351                         if (i < width * height * 4)
1352                         {
1353                                 unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
1354                                 memcpy(fogpixels, skindata, width * height * 4);
1355                                 for (i = 0;i < width * height * 4;i += 4)
1356                                         fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
1357                                 skinframe->fog = R_LoadTexture2D(r_main_texturepool, va("%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_RGBA, textureflags, NULL);
1358                                 Mem_Free(fogpixels);
1359                         }
1360                 }
1361         }
1362         else if (bitsperpixel == 8)
1363         {
1364                 if (r_shadow_bumpscale_basetexture.value > 0)
1365                 {
1366                         temp1 = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
1367                         temp2 = temp1 + width * height * 4;
1368                         if (bitsperpixel == 32)
1369                                 Image_HeightmapToNormalmap(skindata, temp2, width, height, false, r_shadow_bumpscale_basetexture.value);
1370                         else
1371                         {
1372                                 // use either a custom palette or the quake palette
1373                                 Image_Copy8bitRGBA(skindata, temp1, width * height, palette ? palette : palette_complete);
1374                                 Image_HeightmapToNormalmap(temp1, temp2, width, height, false, r_shadow_bumpscale_basetexture.value);
1375                         }
1376                         skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va("%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_RGBA, textureflags | TEXF_ALPHA, NULL);
1377                         Mem_Free(temp1);
1378                 }
1379                 // use either a custom palette, or the quake palette
1380                 skinframe->base = skinframe->merged = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_merged", skinframe->basename), palette ? palette : (loadglowtexture ? palette_nofullbrights : ((textureflags & TEXF_ALPHA) ? palette_transparent : palette_complete)), textureflags, true); // all
1381                 if (!palette && loadglowtexture)
1382                         skinframe->glow = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_glow", skinframe->basename), palette_onlyfullbrights, textureflags, false); // glow
1383                 if (!palette && loadpantsandshirt)
1384                 {
1385                         skinframe->pants = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_pants", skinframe->basename), palette_pantsaswhite, textureflags, false); // pants
1386                         skinframe->shirt = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_shirt", skinframe->basename), palette_shirtaswhite, textureflags, false); // shirt
1387                 }
1388                 if (skinframe->pants || skinframe->shirt)
1389                         skinframe->base = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_nospecial", skinframe->basename),loadglowtexture ? palette_nocolormapnofullbrights : palette_nocolormap, textureflags, false); // no special colors
1390                 if (textureflags & TEXF_ALPHA)
1391                 {
1392                         // if not using a custom alphapalette, use the quake one
1393                         if (!alphapalette)
1394                                 alphapalette = palette_alpha;
1395                         for (i = 0;i < width * height;i++)
1396                                 if (((unsigned char *)alphapalette)[skindata[i]*4+3] < 255)
1397                                         break;
1398                         if (i < width * height)
1399                                 skinframe->fog = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_fog", skinframe->basename), alphapalette, textureflags, true); // fog mask
1400                 }
1401         }
1402
1403         return skinframe;
1404 }
1405
1406 skinframe_t *R_SkinFrame_LoadMissing(void)
1407 {
1408         skinframe_t *skinframe;
1409
1410         if (cls.state == ca_dedicated)
1411                 return NULL;
1412
1413         skinframe = R_SkinFrame_Find("missing", TEXF_PRECACHE, 0, 0, 0, true);
1414         skinframe->stain = NULL;
1415         skinframe->merged = NULL;
1416         skinframe->base = r_texture_notexture;
1417         skinframe->pants = NULL;
1418         skinframe->shirt = NULL;
1419         skinframe->nmap = r_texture_blanknormalmap;
1420         skinframe->gloss = NULL;
1421         skinframe->glow = NULL;
1422         skinframe->fog = NULL;
1423
1424         return skinframe;
1425 }
1426
1427 void gl_main_start(void)
1428 {
1429         int x;
1430         double r, alpha;
1431
1432         r = (-1.0/256.0) * (FOGMASKTABLEWIDTH * FOGMASKTABLEWIDTH);
1433         for (x = 0;x < FOGMASKTABLEWIDTH;x++)
1434         {
1435                 alpha = 1 - exp(r / ((double)x*(double)x));
1436                 if (x == FOGMASKTABLEWIDTH - 1)
1437                         alpha = 0;
1438                 r_refdef.fogmasktable[x] = bound(0, alpha, 1);
1439         }
1440
1441         memset(r_qwskincache, 0, sizeof(r_qwskincache));
1442         memset(r_qwskincache_skinframe, 0, sizeof(r_qwskincache_skinframe));
1443
1444         // set up r_skinframe loading system for textures
1445         memset(&r_skinframe, 0, sizeof(r_skinframe));
1446         r_skinframe.loadsequence = 1;
1447         Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
1448
1449         r_main_texturepool = R_AllocTexturePool();
1450         R_BuildBlankTextures();
1451         R_BuildNoTexture();
1452         if (gl_texturecubemap)
1453         {
1454                 R_BuildWhiteCube();
1455                 R_BuildNormalizationCube();
1456         }
1457         R_BuildFogTexture();
1458         memset(&r_bloomstate, 0, sizeof(r_bloomstate));
1459         memset(r_glsl_permutations, 0, sizeof(r_glsl_permutations));
1460         memset(&r_svbsp, 0, sizeof (r_svbsp));
1461 }
1462
1463 void gl_main_shutdown(void)
1464 {
1465         memset(r_qwskincache, 0, sizeof(r_qwskincache));
1466         memset(r_qwskincache_skinframe, 0, sizeof(r_qwskincache_skinframe));
1467
1468         // clear out the r_skinframe state
1469         Mem_ExpandableArray_FreeArray(&r_skinframe.array);
1470         memset(&r_skinframe, 0, sizeof(r_skinframe));
1471
1472         if (r_svbsp.nodes)
1473                 Mem_Free(r_svbsp.nodes);
1474         memset(&r_svbsp, 0, sizeof (r_svbsp));
1475         R_FreeTexturePool(&r_main_texturepool);
1476         r_texture_blanknormalmap = NULL;
1477         r_texture_white = NULL;
1478         r_texture_black = NULL;
1479         r_texture_whitecube = NULL;
1480         r_texture_normalizationcube = NULL;
1481         memset(&r_bloomstate, 0, sizeof(r_bloomstate));
1482         R_GLSL_Restart_f();
1483 }
1484
1485 extern void CL_ParseEntityLump(char *entitystring);
1486 void gl_main_newmap(void)
1487 {
1488         // FIXME: move this code to client
1489         int l;
1490         char *entities, entname[MAX_QPATH];
1491         if (cl.worldmodel)
1492         {
1493                 strlcpy(entname, cl.worldmodel->name, sizeof(entname));
1494                 l = (int)strlen(entname) - 4;
1495                 if (l >= 0 && !strcmp(entname + l, ".bsp"))
1496                 {
1497                         memcpy(entname + l, ".ent", 5);
1498                         if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
1499                         {
1500                                 CL_ParseEntityLump(entities);
1501                                 Mem_Free(entities);
1502                                 return;
1503                         }
1504                 }
1505                 if (cl.worldmodel->brush.entities)
1506                         CL_ParseEntityLump(cl.worldmodel->brush.entities);
1507         }
1508 }
1509
1510 void GL_Main_Init(void)
1511 {
1512         r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
1513
1514         Cmd_AddCommand("r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
1515         Cmd_AddCommand("r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
1516         // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
1517         if (gamemode == GAME_NEHAHRA)
1518         {
1519                 Cvar_RegisterVariable (&gl_fogenable);
1520                 Cvar_RegisterVariable (&gl_fogdensity);
1521                 Cvar_RegisterVariable (&gl_fogred);
1522                 Cvar_RegisterVariable (&gl_foggreen);
1523                 Cvar_RegisterVariable (&gl_fogblue);
1524                 Cvar_RegisterVariable (&gl_fogstart);
1525                 Cvar_RegisterVariable (&gl_fogend);
1526         }
1527         Cvar_RegisterVariable(&r_depthfirst);
1528         Cvar_RegisterVariable(&r_nearclip);
1529         Cvar_RegisterVariable(&r_showbboxes);
1530         Cvar_RegisterVariable(&r_showsurfaces);
1531         Cvar_RegisterVariable(&r_showtris);
1532         Cvar_RegisterVariable(&r_shownormals);
1533         Cvar_RegisterVariable(&r_showlighting);
1534         Cvar_RegisterVariable(&r_showshadowvolumes);
1535         Cvar_RegisterVariable(&r_showcollisionbrushes);
1536         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
1537         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
1538         Cvar_RegisterVariable(&r_showdisabledepthtest);
1539         Cvar_RegisterVariable(&r_drawportals);
1540         Cvar_RegisterVariable(&r_drawentities);
1541         Cvar_RegisterVariable(&r_cullentities_trace);
1542         Cvar_RegisterVariable(&r_cullentities_trace_samples);
1543         Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
1544         Cvar_RegisterVariable(&r_cullentities_trace_delay);
1545         Cvar_RegisterVariable(&r_drawviewmodel);
1546         Cvar_RegisterVariable(&r_speeds);
1547         Cvar_RegisterVariable(&r_fullbrights);
1548         Cvar_RegisterVariable(&r_wateralpha);
1549         Cvar_RegisterVariable(&r_dynamic);
1550         Cvar_RegisterVariable(&r_fullbright);
1551         Cvar_RegisterVariable(&r_shadows);
1552         Cvar_RegisterVariable(&r_shadows_throwdistance);
1553         Cvar_RegisterVariable(&r_q1bsp_skymasking);
1554         Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
1555         Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
1556         Cvar_RegisterVariable(&r_textureunits);
1557         Cvar_RegisterVariable(&r_glsl);
1558         Cvar_RegisterVariable(&r_glsl_offsetmapping);
1559         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
1560         Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
1561         Cvar_RegisterVariable(&r_glsl_deluxemapping);
1562         Cvar_RegisterVariable(&r_lerpsprites);
1563         Cvar_RegisterVariable(&r_lerpmodels);
1564         Cvar_RegisterVariable(&r_waterscroll);
1565         Cvar_RegisterVariable(&r_bloom);
1566         Cvar_RegisterVariable(&r_bloom_colorscale);
1567         Cvar_RegisterVariable(&r_bloom_brighten);
1568         Cvar_RegisterVariable(&r_bloom_blur);
1569         Cvar_RegisterVariable(&r_bloom_resolution);
1570         Cvar_RegisterVariable(&r_bloom_colorexponent);
1571         Cvar_RegisterVariable(&r_bloom_colorsubtract);
1572         Cvar_RegisterVariable(&r_hdr);
1573         Cvar_RegisterVariable(&r_hdr_scenebrightness);
1574         Cvar_RegisterVariable(&r_glsl_contrastboost);
1575         Cvar_RegisterVariable(&r_hdr_glowintensity);
1576         Cvar_RegisterVariable(&r_hdr_range);
1577         Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
1578         Cvar_RegisterVariable(&developer_texturelogging);
1579         Cvar_RegisterVariable(&gl_lightmaps);
1580         Cvar_RegisterVariable(&r_test);
1581         Cvar_RegisterVariable(&r_batchmode);
1582         if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
1583                 Cvar_SetValue("r_fullbrights", 0);
1584         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
1585 }
1586
1587 extern void R_Textures_Init(void);
1588 extern void GL_Draw_Init(void);
1589 extern void GL_Main_Init(void);
1590 extern void R_Shadow_Init(void);
1591 extern void R_Sky_Init(void);
1592 extern void GL_Surf_Init(void);
1593 extern void R_Light_Init(void);
1594 extern void R_Particles_Init(void);
1595 extern void R_Explosion_Init(void);
1596 extern void gl_backend_init(void);
1597 extern void Sbar_Init(void);
1598 extern void R_LightningBeams_Init(void);
1599 extern void Mod_RenderInit(void);
1600
1601 void Render_Init(void)
1602 {
1603         gl_backend_init();
1604         R_Textures_Init();
1605         GL_Main_Init();
1606         GL_Draw_Init();
1607         R_Shadow_Init();
1608         R_Sky_Init();
1609         GL_Surf_Init();
1610         Sbar_Init();
1611         R_Light_Init();
1612         R_Particles_Init();
1613         R_Explosion_Init();
1614         R_LightningBeams_Init();
1615         Mod_RenderInit();
1616 }
1617
1618 /*
1619 ===============
1620 GL_Init
1621 ===============
1622 */
1623 extern char *ENGINE_EXTENSIONS;
1624 void GL_Init (void)
1625 {
1626         VID_CheckExtensions();
1627
1628         // LordHavoc: report supported extensions
1629         Con_DPrintf("\nQuakeC extensions for server and client: %s\nQuakeC extensions for menu: %s\n", vm_sv_extensions, vm_m_extensions );
1630
1631         // clear to black (loading plaque will be seen over this)
1632         CHECKGLERROR
1633         qglClearColor(0,0,0,1);CHECKGLERROR
1634         qglClear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
1635 }
1636
1637 int R_CullBox(const vec3_t mins, const vec3_t maxs)
1638 {
1639         int i;
1640         mplane_t *p;
1641         for (i = 0;i < 4;i++)
1642         {
1643                 p = r_view.frustum + i;
1644                 switch(p->signbits)
1645                 {
1646                 default:
1647                 case 0:
1648                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
1649                                 return true;
1650                         break;
1651                 case 1:
1652                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
1653                                 return true;
1654                         break;
1655                 case 2:
1656                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
1657                                 return true;
1658                         break;
1659                 case 3:
1660                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
1661                                 return true;
1662                         break;
1663                 case 4:
1664                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
1665                                 return true;
1666                         break;
1667                 case 5:
1668                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
1669                                 return true;
1670                         break;
1671                 case 6:
1672                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
1673                                 return true;
1674                         break;
1675                 case 7:
1676                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
1677                                 return true;
1678                         break;
1679                 }
1680         }
1681         return false;
1682 }
1683
1684 int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
1685 {
1686         int i;
1687         const mplane_t *p;
1688         for (i = 0;i < numplanes;i++)
1689         {
1690                 p = planes + i;
1691                 switch(p->signbits)
1692                 {
1693                 default:
1694                 case 0:
1695                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
1696                                 return true;
1697                         break;
1698                 case 1:
1699                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
1700                                 return true;
1701                         break;
1702                 case 2:
1703                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
1704                                 return true;
1705                         break;
1706                 case 3:
1707                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
1708                                 return true;
1709                         break;
1710                 case 4:
1711                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
1712                                 return true;
1713                         break;
1714                 case 5:
1715                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
1716                                 return true;
1717                         break;
1718                 case 6:
1719                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
1720                                 return true;
1721                         break;
1722                 case 7:
1723                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
1724                                 return true;
1725                         break;
1726                 }
1727         }
1728         return false;
1729 }
1730
1731 //==================================================================================
1732
1733 static void R_UpdateEntityLighting(entity_render_t *ent)
1734 {
1735         vec3_t tempdiffusenormal;
1736
1737         // fetch the lighting from the worldmodel data
1738         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));
1739         VectorClear(ent->modellight_diffuse);
1740         VectorClear(tempdiffusenormal);
1741         if ((ent->flags & RENDER_LIGHT) && r_refdef.worldmodel && r_refdef.worldmodel->brush.LightPoint)
1742         {
1743                 vec3_t org;
1744                 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
1745                 r_refdef.worldmodel->brush.LightPoint(r_refdef.worldmodel, org, ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal);
1746         }
1747         else // highly rare
1748                 VectorSet(ent->modellight_ambient, 1, 1, 1);
1749
1750         // move the light direction into modelspace coordinates for lighting code
1751         Matrix4x4_Transform3x3(&ent->inversematrix, tempdiffusenormal, ent->modellight_lightdir);
1752         if(VectorLength2(ent->modellight_lightdir) > 0)
1753         {
1754                 VectorNormalize(ent->modellight_lightdir);
1755         }
1756         else
1757         {
1758                 VectorSet(ent->modellight_lightdir, 0, 0, 1); // have to set SOME valid vector here
1759         }
1760
1761         // scale ambient and directional light contributions according to rendering variables
1762         ent->modellight_ambient[0] *= ent->colormod[0] * r_refdef.lightmapintensity;
1763         ent->modellight_ambient[1] *= ent->colormod[1] * r_refdef.lightmapintensity;
1764         ent->modellight_ambient[2] *= ent->colormod[2] * r_refdef.lightmapintensity;
1765         ent->modellight_diffuse[0] *= ent->colormod[0] * r_refdef.lightmapintensity;
1766         ent->modellight_diffuse[1] *= ent->colormod[1] * r_refdef.lightmapintensity;
1767         ent->modellight_diffuse[2] *= ent->colormod[2] * r_refdef.lightmapintensity;
1768 }
1769
1770 static void R_View_UpdateEntityVisible (void)
1771 {
1772         int i, renderimask;
1773         entity_render_t *ent;
1774
1775         if (!r_drawentities.integer)
1776                 return;
1777
1778         renderimask = r_refdef.envmap ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL) : (chase_active.integer ? 0 : RENDER_EXTERIORMODEL);
1779         if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingVisibleLeafs)
1780         {
1781                 // worldmodel can check visibility
1782                 for (i = 0;i < r_refdef.numentities;i++)
1783                 {
1784                         ent = r_refdef.entities[i];
1785                         r_viewcache.entityvisible[i] = !(ent->flags & renderimask) && !R_CullBox(ent->mins, ent->maxs) && ((ent->effects & EF_NODEPTHTEST) || (ent->flags & RENDER_VIEWMODEL) || r_refdef.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.worldmodel, r_viewcache.world_leafvisible, ent->mins, ent->maxs));
1786                 }
1787                 if(r_cullentities_trace.integer)
1788                 {
1789                         for (i = 0;i < r_refdef.numentities;i++)
1790                         {
1791                                 ent = r_refdef.entities[i];
1792                                 if(r_viewcache.entityvisible[i] && !(ent->effects & EF_NODEPTHTEST) && !(ent->flags & RENDER_VIEWMODEL) && !(ent->model && (ent->model->name[0] == '*')))
1793                                 {
1794                                         if(Mod_CanSeeBox_Trace(r_cullentities_trace_samples.integer, r_cullentities_trace_enlarge.value, r_refdef.worldmodel, r_view.origin, ent->mins, ent->maxs))
1795                                                 ent->last_trace_visibility = realtime;
1796                                         if(ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
1797                                                 r_viewcache.entityvisible[i] = 0;
1798                                 }
1799                         }
1800                 }
1801         }
1802         else
1803         {
1804                 // no worldmodel or it can't check visibility
1805                 for (i = 0;i < r_refdef.numentities;i++)
1806                 {
1807                         ent = r_refdef.entities[i];
1808                         r_viewcache.entityvisible[i] = !(ent->flags & renderimask) && !R_CullBox(ent->mins, ent->maxs);
1809                 }
1810         }
1811
1812         // update entity lighting (even on hidden entities for r_shadows)
1813         for (i = 0;i < r_refdef.numentities;i++)
1814                 R_UpdateEntityLighting(r_refdef.entities[i]);
1815 }
1816
1817 // only used if skyrendermasked, and normally returns false
1818 int R_DrawBrushModelsSky (void)
1819 {
1820         int i, sky;
1821         entity_render_t *ent;
1822
1823         if (!r_drawentities.integer)
1824                 return false;
1825
1826         sky = false;
1827         for (i = 0;i < r_refdef.numentities;i++)
1828         {
1829                 if (!r_viewcache.entityvisible[i])
1830                         continue;
1831                 ent = r_refdef.entities[i];
1832                 if (!ent->model || !ent->model->DrawSky)
1833                         continue;
1834                 ent->model->DrawSky(ent);
1835                 sky = true;
1836         }
1837         return sky;
1838 }
1839
1840 void R_DrawNoModel(entity_render_t *ent);
1841 void R_DrawModels(void)
1842 {
1843         int i;
1844         entity_render_t *ent;
1845
1846         if (!r_drawentities.integer)
1847                 return;
1848
1849         for (i = 0;i < r_refdef.numentities;i++)
1850         {
1851                 if (!r_viewcache.entityvisible[i])
1852                         continue;
1853                 ent = r_refdef.entities[i];
1854                 r_refdef.stats.entities++;
1855                 if (ent->model && ent->model->Draw != NULL)
1856                         ent->model->Draw(ent);
1857                 else
1858                         R_DrawNoModel(ent);
1859         }
1860 }
1861
1862 void R_DrawModelsDepth(void)
1863 {
1864         int i;
1865         entity_render_t *ent;
1866
1867         if (!r_drawentities.integer)
1868                 return;
1869
1870         for (i = 0;i < r_refdef.numentities;i++)
1871         {
1872                 if (!r_viewcache.entityvisible[i])
1873                         continue;
1874                 ent = r_refdef.entities[i];
1875                 r_refdef.stats.entities++;
1876                 if (ent->model && ent->model->DrawDepth != NULL)
1877                         ent->model->DrawDepth(ent);
1878         }
1879 }
1880
1881 static void R_View_SetFrustum(void)
1882 {
1883         double slopex, slopey;
1884
1885         // break apart the view matrix into vectors for various purposes
1886         Matrix4x4_ToVectors(&r_view.matrix, r_view.forward, r_view.left, r_view.up, r_view.origin);
1887         VectorNegate(r_view.left, r_view.right);
1888
1889 #if 0
1890         r_view.frustum[0].normal[0] = 0 - 1.0 / r_view.frustum_x;
1891         r_view.frustum[0].normal[1] = 0 - 0;
1892         r_view.frustum[0].normal[2] = -1 - 0;
1893         r_view.frustum[1].normal[0] = 0 + 1.0 / r_view.frustum_x;
1894         r_view.frustum[1].normal[1] = 0 + 0;
1895         r_view.frustum[1].normal[2] = -1 + 0;
1896         r_view.frustum[2].normal[0] = 0 - 0;
1897         r_view.frustum[2].normal[1] = 0 - 1.0 / r_view.frustum_y;
1898         r_view.frustum[2].normal[2] = -1 - 0;
1899         r_view.frustum[3].normal[0] = 0 + 0;
1900         r_view.frustum[3].normal[1] = 0 + 1.0 / r_view.frustum_y;
1901         r_view.frustum[3].normal[2] = -1 + 0;
1902 #endif
1903
1904 #if 0
1905         zNear = r_refdef.nearclip;
1906         nudge = 1.0 - 1.0 / (1<<23);
1907         r_view.frustum[4].normal[0] = 0 - 0;
1908         r_view.frustum[4].normal[1] = 0 - 0;
1909         r_view.frustum[4].normal[2] = -1 - -nudge;
1910         r_view.frustum[4].dist = 0 - -2 * zNear * nudge;
1911         r_view.frustum[5].normal[0] = 0 + 0;
1912         r_view.frustum[5].normal[1] = 0 + 0;
1913         r_view.frustum[5].normal[2] = -1 + -nudge;
1914         r_view.frustum[5].dist = 0 + -2 * zNear * nudge;
1915 #endif
1916
1917
1918
1919 #if 0
1920         r_view.frustum[0].normal[0] = m[3] - m[0];
1921         r_view.frustum[0].normal[1] = m[7] - m[4];
1922         r_view.frustum[0].normal[2] = m[11] - m[8];
1923         r_view.frustum[0].dist = m[15] - m[12];
1924
1925         r_view.frustum[1].normal[0] = m[3] + m[0];
1926         r_view.frustum[1].normal[1] = m[7] + m[4];
1927         r_view.frustum[1].normal[2] = m[11] + m[8];
1928         r_view.frustum[1].dist = m[15] + m[12];
1929
1930         r_view.frustum[2].normal[0] = m[3] - m[1];
1931         r_view.frustum[2].normal[1] = m[7] - m[5];
1932         r_view.frustum[2].normal[2] = m[11] - m[9];
1933         r_view.frustum[2].dist = m[15] - m[13];
1934
1935         r_view.frustum[3].normal[0] = m[3] + m[1];
1936         r_view.frustum[3].normal[1] = m[7] + m[5];
1937         r_view.frustum[3].normal[2] = m[11] + m[9];
1938         r_view.frustum[3].dist = m[15] + m[13];
1939
1940         r_view.frustum[4].normal[0] = m[3] - m[2];
1941         r_view.frustum[4].normal[1] = m[7] - m[6];
1942         r_view.frustum[4].normal[2] = m[11] - m[10];
1943         r_view.frustum[4].dist = m[15] - m[14];
1944
1945         r_view.frustum[5].normal[0] = m[3] + m[2];
1946         r_view.frustum[5].normal[1] = m[7] + m[6];
1947         r_view.frustum[5].normal[2] = m[11] + m[10];
1948         r_view.frustum[5].dist = m[15] + m[14];
1949 #endif
1950
1951
1952
1953         if (r_view.useperspective)
1954         {
1955                 slopex = 1.0 / r_view.frustum_x;
1956                 slopey = 1.0 / r_view.frustum_y;
1957                 VectorMA(r_view.forward, -slopex, r_view.left, r_view.frustum[0].normal);
1958                 VectorMA(r_view.forward,  slopex, r_view.left, r_view.frustum[1].normal);
1959                 VectorMA(r_view.forward, -slopey, r_view.up  , r_view.frustum[2].normal);
1960                 VectorMA(r_view.forward,  slopey, r_view.up  , r_view.frustum[3].normal);
1961                 VectorCopy(r_view.forward, r_view.frustum[4].normal);
1962
1963                 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
1964                 VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, -1024 * slopex, r_view.left, -1024 * slopey, r_view.up, r_view.frustumcorner[0]);
1965                 VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward,  1024 * slopex, r_view.left, -1024 * slopey, r_view.up, r_view.frustumcorner[1]);
1966                 VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, -1024 * slopex, r_view.left,  1024 * slopey, r_view.up, r_view.frustumcorner[2]);
1967                 VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward,  1024 * slopex, r_view.left,  1024 * slopey, r_view.up, r_view.frustumcorner[3]);
1968
1969                 r_view.frustum[0].dist = DotProduct (r_view.origin, r_view.frustum[0].normal);
1970                 r_view.frustum[1].dist = DotProduct (r_view.origin, r_view.frustum[1].normal);
1971                 r_view.frustum[2].dist = DotProduct (r_view.origin, r_view.frustum[2].normal);
1972                 r_view.frustum[3].dist = DotProduct (r_view.origin, r_view.frustum[3].normal);
1973                 r_view.frustum[4].dist = DotProduct (r_view.origin, r_view.frustum[4].normal) + r_refdef.nearclip;
1974         }
1975         else
1976         {
1977                 VectorScale(r_view.left, -r_view.ortho_x, r_view.frustum[0].normal);
1978                 VectorScale(r_view.left,  r_view.ortho_x, r_view.frustum[1].normal);
1979                 VectorScale(r_view.up, -r_view.ortho_y, r_view.frustum[2].normal);
1980                 VectorScale(r_view.up,  r_view.ortho_y, r_view.frustum[3].normal);
1981                 VectorCopy(r_view.forward, r_view.frustum[4].normal);
1982                 r_view.frustum[0].dist = DotProduct (r_view.origin, r_view.frustum[0].normal) + r_view.ortho_x;
1983                 r_view.frustum[1].dist = DotProduct (r_view.origin, r_view.frustum[1].normal) + r_view.ortho_x;
1984                 r_view.frustum[2].dist = DotProduct (r_view.origin, r_view.frustum[2].normal) + r_view.ortho_y;
1985                 r_view.frustum[3].dist = DotProduct (r_view.origin, r_view.frustum[3].normal) + r_view.ortho_y;
1986                 r_view.frustum[4].dist = DotProduct (r_view.origin, r_view.frustum[4].normal) + r_refdef.nearclip;
1987         }
1988
1989         PlaneClassify(&r_view.frustum[0]);
1990         PlaneClassify(&r_view.frustum[1]);
1991         PlaneClassify(&r_view.frustum[2]);
1992         PlaneClassify(&r_view.frustum[3]);
1993         PlaneClassify(&r_view.frustum[4]);
1994
1995         // LordHavoc: note to all quake engine coders, Quake had a special case
1996         // for 90 degrees which assumed a square view (wrong), so I removed it,
1997         // Quake2 has it disabled as well.
1998
1999         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
2000         //RotatePointAroundVector( r_view.frustum[0].normal, r_view.up, r_view.forward, -(90 - r_refdef.fov_x / 2));
2001         //r_view.frustum[0].dist = DotProduct (r_view.origin, frustum[0].normal);
2002         //PlaneClassify(&frustum[0]);
2003
2004         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
2005         //RotatePointAroundVector( r_view.frustum[1].normal, r_view.up, r_view.forward, (90 - r_refdef.fov_x / 2));
2006         //r_view.frustum[1].dist = DotProduct (r_view.origin, frustum[1].normal);
2007         //PlaneClassify(&frustum[1]);
2008
2009         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
2010         //RotatePointAroundVector( r_view.frustum[2].normal, r_view.left, r_view.forward, -(90 - r_refdef.fov_y / 2));
2011         //r_view.frustum[2].dist = DotProduct (r_view.origin, frustum[2].normal);
2012         //PlaneClassify(&frustum[2]);
2013
2014         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
2015         //RotatePointAroundVector( r_view.frustum[3].normal, r_view.left, r_view.forward, (90 - r_refdef.fov_y / 2));
2016         //r_view.frustum[3].dist = DotProduct (r_view.origin, frustum[3].normal);
2017         //PlaneClassify(&frustum[3]);
2018
2019         // nearclip plane
2020         //VectorCopy(r_view.forward, r_view.frustum[4].normal);
2021         //r_view.frustum[4].dist = DotProduct (r_view.origin, frustum[4].normal) + r_nearclip.value;
2022         //PlaneClassify(&frustum[4]);
2023 }
2024
2025 void R_View_Update(void)
2026 {
2027         R_View_SetFrustum();
2028         R_View_WorldVisibility();
2029         R_View_UpdateEntityVisible();
2030 }
2031
2032 void R_SetupView(const matrix4x4_t *matrix)
2033 {
2034         if (!r_view.useperspective)
2035                 GL_SetupView_Mode_Ortho(-r_view.ortho_x, -r_view.ortho_y, r_view.ortho_x, r_view.ortho_y, -r_refdef.farclip, r_refdef.farclip);
2036         else if (r_refdef.rtworldshadows || r_refdef.rtdlightshadows)
2037                 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view.frustum_x, r_view.frustum_y, r_refdef.nearclip);
2038         else
2039                 GL_SetupView_Mode_Perspective(r_view.frustum_x, r_view.frustum_y, r_refdef.nearclip, r_refdef.farclip);
2040
2041         GL_SetupView_Orientation_FromEntity(matrix);
2042 }
2043
2044 void R_ResetViewRendering2D(void)
2045 {
2046         if (gl_support_fragment_shader)
2047         {
2048                 qglUseProgramObjectARB(0);CHECKGLERROR
2049         }
2050
2051         DrawQ_Finish();
2052
2053         // GL is weird because it's bottom to top, r_view.y is top to bottom
2054         qglViewport(r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
2055         GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
2056         GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2057         GL_Color(1, 1, 1, 1);
2058         GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2059         GL_BlendFunc(GL_ONE, GL_ZERO);
2060         GL_AlphaTest(false);
2061         GL_ScissorTest(false);
2062         GL_DepthMask(false);
2063         GL_DepthRange(0, 1);
2064         GL_DepthTest(false);
2065         R_Mesh_Matrix(&identitymatrix);
2066         R_Mesh_ResetTextureState();
2067         GL_PolygonOffset(0, 0);
2068         qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
2069         qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2070         qglDisable(GL_STENCIL_TEST);CHECKGLERROR
2071         qglStencilMask(~0);CHECKGLERROR
2072         qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
2073         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
2074         GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
2075 }
2076
2077 void R_ResetViewRendering3D(void)
2078 {
2079         if (gl_support_fragment_shader)
2080         {
2081                 qglUseProgramObjectARB(0);CHECKGLERROR
2082         }
2083
2084         DrawQ_Finish();
2085
2086         // GL is weird because it's bottom to top, r_view.y is top to bottom
2087         qglViewport(r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
2088         R_SetupView(&r_view.matrix);
2089         GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2090         GL_Color(1, 1, 1, 1);
2091         GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2092         GL_BlendFunc(GL_ONE, GL_ZERO);
2093         GL_AlphaTest(false);
2094         GL_ScissorTest(true);
2095         GL_DepthMask(true);
2096         GL_DepthRange(0, 1);
2097         GL_DepthTest(true);
2098         R_Mesh_Matrix(&identitymatrix);
2099         R_Mesh_ResetTextureState();
2100         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
2101         qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
2102         qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2103         qglDisable(GL_STENCIL_TEST);CHECKGLERROR
2104         qglStencilMask(~0);CHECKGLERROR
2105         qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
2106         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
2107         GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
2108 }
2109
2110 /*
2111         R_Bloom_SetupShader(
2112 "// bloom shader\n"
2113 "// written by Forest 'LordHavoc' Hale\n"
2114 "\n"
2115 "// common definitions between vertex shader and fragment shader:\n"
2116 "\n"
2117 "#ifdef __GLSL_CG_DATA_TYPES\n"
2118 "#define myhalf half\n"
2119 "#define myhvec2 hvec2\n"
2120 "#define myhvec3 hvec3\n"
2121 "#define myhvec4 hvec4\n"
2122 "#else\n"
2123 "#define myhalf float\n"
2124 "#define myhvec2 vec2\n"
2125 "#define myhvec3 vec3\n"
2126 "#define myhvec4 vec4\n"
2127 "#endif\n"
2128 "\n"
2129 "varying vec2 ScreenTexCoord;\n"
2130 "varying vec2 BloomTexCoord;\n"
2131 "\n"
2132 "\n"
2133 "\n"
2134 "\n"
2135 "// vertex shader specific:\n"
2136 "#ifdef VERTEX_SHADER\n"
2137 "\n"
2138 "void main(void)\n"
2139 "{\n"
2140 "       ScreenTexCoord = vec2(gl_MultiTexCoord0);\n"
2141 "       BloomTexCoord = vec2(gl_MultiTexCoord1);\n"
2142 "       // transform vertex to camera space, using ftransform to match non-VS\n"
2143 "       // rendering\n"
2144 "       gl_Position = ftransform();\n"
2145 "}\n"
2146 "\n"
2147 "#endif // VERTEX_SHADER\n"
2148 "\n"
2149 "\n"
2150 "\n"
2151 "\n"
2152 "// fragment shader specific:\n"
2153 "#ifdef FRAGMENT_SHADER\n"
2154 "\n"
2155 "void main(void)\n"
2156 "{\n"
2157 "       int x, y;
2158 "       myhvec3 color = myhvec3(texture2D(Texture_Screen, ScreenTexCoord));\n"
2159 "       for (x = -BLUR_X;x <= BLUR_X;x++)
2160 "       color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
2161 "       color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
2162 "       color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
2163 "       color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
2164
2165 "       gl_FragColor = vec4(color);\n"
2166 "}\n"
2167 "\n"
2168 "#endif // FRAGMENT_SHADER\n"
2169 */
2170
2171 void R_RenderScene(void);
2172
2173 void R_Bloom_StartFrame(void)
2174 {
2175         int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight;
2176
2177         // set bloomwidth and bloomheight to the bloom resolution that will be
2178         // used (often less than the screen resolution for faster rendering)
2179         r_bloomstate.bloomwidth = bound(1, r_bloom_resolution.integer, r_view.width);
2180         r_bloomstate.bloomheight = r_bloomstate.bloomwidth * r_view.height / r_view.width;
2181         r_bloomstate.bloomheight = bound(1, r_bloomstate.bloomheight, r_view.height);
2182
2183         // calculate desired texture sizes
2184         if (gl_support_arb_texture_non_power_of_two)
2185         {
2186                 screentexturewidth = r_view.width;
2187                 screentextureheight = r_view.height;
2188                 bloomtexturewidth = r_bloomstate.bloomwidth;
2189                 bloomtextureheight = r_bloomstate.bloomheight;
2190         }
2191         else
2192         {
2193                 for (screentexturewidth  = 1;screentexturewidth  < vid.width               ;screentexturewidth  *= 2);
2194                 for (screentextureheight = 1;screentextureheight < vid.height              ;screentextureheight *= 2);
2195                 for (bloomtexturewidth   = 1;bloomtexturewidth   < r_bloomstate.bloomwidth ;bloomtexturewidth   *= 2);
2196                 for (bloomtextureheight  = 1;bloomtextureheight  < r_bloomstate.bloomheight;bloomtextureheight  *= 2);
2197         }
2198
2199         if (r_hdr.integer)
2200         {
2201                 screentexturewidth = screentextureheight = 0;
2202         }
2203         else if (r_bloom.integer)
2204         {
2205         }
2206         else
2207         {
2208                 screentexturewidth = screentextureheight = 0;
2209                 bloomtexturewidth = bloomtextureheight = 0;
2210         }
2211
2212         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)
2213         {
2214                 // can't use bloom if the parameters are too weird
2215                 // can't use bloom if the card does not support the texture size
2216                 if (r_bloomstate.texture_screen)
2217                         R_FreeTexture(r_bloomstate.texture_screen);
2218                 if (r_bloomstate.texture_bloom)
2219                         R_FreeTexture(r_bloomstate.texture_bloom);
2220                 memset(&r_bloomstate, 0, sizeof(r_bloomstate));
2221                 return;
2222         }
2223
2224         r_bloomstate.enabled = true;
2225         r_bloomstate.hdr = r_hdr.integer != 0;
2226
2227         // allocate textures as needed
2228         if (r_bloomstate.screentexturewidth != screentexturewidth || r_bloomstate.screentextureheight != screentextureheight)
2229         {
2230                 if (r_bloomstate.texture_screen)
2231                         R_FreeTexture(r_bloomstate.texture_screen);
2232                 r_bloomstate.texture_screen = NULL;
2233                 r_bloomstate.screentexturewidth = screentexturewidth;
2234                 r_bloomstate.screentextureheight = screentextureheight;
2235                 if (r_bloomstate.screentexturewidth && r_bloomstate.screentextureheight)
2236                         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);
2237         }
2238         if (r_bloomstate.bloomtexturewidth != bloomtexturewidth || r_bloomstate.bloomtextureheight != bloomtextureheight)
2239         {
2240                 if (r_bloomstate.texture_bloom)
2241                         R_FreeTexture(r_bloomstate.texture_bloom);
2242                 r_bloomstate.texture_bloom = NULL;
2243                 r_bloomstate.bloomtexturewidth = bloomtexturewidth;
2244                 r_bloomstate.bloomtextureheight = bloomtextureheight;
2245                 if (r_bloomstate.bloomtexturewidth && r_bloomstate.bloomtextureheight)
2246                         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);
2247         }
2248
2249         // set up a texcoord array for the full resolution screen image
2250         // (we have to keep this around to copy back during final render)
2251         r_bloomstate.screentexcoord2f[0] = 0;
2252         r_bloomstate.screentexcoord2f[1] = (float)r_view.height / (float)r_bloomstate.screentextureheight;
2253         r_bloomstate.screentexcoord2f[2] = (float)r_view.width / (float)r_bloomstate.screentexturewidth;
2254         r_bloomstate.screentexcoord2f[3] = (float)r_view.height / (float)r_bloomstate.screentextureheight;
2255         r_bloomstate.screentexcoord2f[4] = (float)r_view.width / (float)r_bloomstate.screentexturewidth;
2256         r_bloomstate.screentexcoord2f[5] = 0;
2257         r_bloomstate.screentexcoord2f[6] = 0;
2258         r_bloomstate.screentexcoord2f[7] = 0;
2259
2260         // set up a texcoord array for the reduced resolution bloom image
2261         // (which will be additive blended over the screen image)
2262         r_bloomstate.bloomtexcoord2f[0] = 0;
2263         r_bloomstate.bloomtexcoord2f[1] = (float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
2264         r_bloomstate.bloomtexcoord2f[2] = (float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
2265         r_bloomstate.bloomtexcoord2f[3] = (float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
2266         r_bloomstate.bloomtexcoord2f[4] = (float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
2267         r_bloomstate.bloomtexcoord2f[5] = 0;
2268         r_bloomstate.bloomtexcoord2f[6] = 0;
2269         r_bloomstate.bloomtexcoord2f[7] = 0;
2270 }
2271
2272 void R_Bloom_CopyScreenTexture(float colorscale)
2273 {
2274         r_refdef.stats.bloom++;
2275
2276         R_ResetViewRendering2D();
2277         R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
2278         R_Mesh_ColorPointer(NULL, 0, 0);
2279         R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
2280         R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
2281
2282         // copy view into the screen texture
2283         GL_ActiveTexture(0);
2284         CHECKGLERROR
2285         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
2286         r_refdef.stats.bloom_copypixels += r_view.width * r_view.height;
2287
2288         // now scale it down to the bloom texture size
2289         CHECKGLERROR
2290         qglViewport(r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
2291         GL_BlendFunc(GL_ONE, GL_ZERO);
2292         GL_Color(colorscale, colorscale, colorscale, 1);
2293         // TODO: optimize with multitexture or GLSL
2294         R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2295         r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2296
2297         // we now have a bloom image in the framebuffer
2298         // copy it into the bloom image texture for later processing
2299         R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2300         GL_ActiveTexture(0);
2301         CHECKGLERROR
2302         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
2303         r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2304 }
2305
2306 void R_Bloom_CopyHDRTexture(void)
2307 {
2308         R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2309         GL_ActiveTexture(0);
2310         CHECKGLERROR
2311         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
2312         r_refdef.stats.bloom_copypixels += r_view.width * r_view.height;
2313 }
2314
2315 void R_Bloom_MakeTexture(void)
2316 {
2317         int x, range, dir;
2318         float xoffset, yoffset, r, brighten;
2319
2320         r_refdef.stats.bloom++;
2321
2322         R_ResetViewRendering2D();
2323         R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
2324         R_Mesh_ColorPointer(NULL, 0, 0);
2325
2326         // we have a bloom image in the framebuffer
2327         CHECKGLERROR
2328         qglViewport(r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
2329
2330         for (x = 1;x < r_bloom_colorexponent.value;)
2331         {
2332                 x *= 2;
2333                 r = bound(0, r_bloom_colorexponent.value / x, 1);
2334                 GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
2335                 GL_Color(r, r, r, 1);
2336                 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2337                 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
2338                 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2339                 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2340
2341                 // copy the vertically blurred bloom view to a texture
2342                 GL_ActiveTexture(0);
2343                 CHECKGLERROR
2344                 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
2345                 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2346         }
2347
2348         range = r_bloom_blur.integer * r_bloomstate.bloomwidth / 320;
2349         brighten = r_bloom_brighten.value;
2350         if (r_hdr.integer)
2351                 brighten *= r_hdr_range.value;
2352         R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2353         R_Mesh_TexCoordPointer(0, 2, r_bloomstate.offsettexcoord2f, 0, 0);
2354
2355         for (dir = 0;dir < 2;dir++)
2356         {
2357                 // blend on at multiple vertical offsets to achieve a vertical blur
2358                 // TODO: do offset blends using GLSL
2359                 GL_BlendFunc(GL_ONE, GL_ZERO);
2360                 for (x = -range;x <= range;x++)
2361                 {
2362                         if (!dir){xoffset = 0;yoffset = x;}
2363                         else {xoffset = x;yoffset = 0;}
2364                         xoffset /= (float)r_bloomstate.bloomtexturewidth;
2365                         yoffset /= (float)r_bloomstate.bloomtextureheight;
2366                         // compute a texcoord array with the specified x and y offset
2367                         r_bloomstate.offsettexcoord2f[0] = xoffset+0;
2368                         r_bloomstate.offsettexcoord2f[1] = yoffset+(float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
2369                         r_bloomstate.offsettexcoord2f[2] = xoffset+(float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
2370                         r_bloomstate.offsettexcoord2f[3] = yoffset+(float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
2371                         r_bloomstate.offsettexcoord2f[4] = xoffset+(float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
2372                         r_bloomstate.offsettexcoord2f[5] = yoffset+0;
2373                         r_bloomstate.offsettexcoord2f[6] = xoffset+0;
2374                         r_bloomstate.offsettexcoord2f[7] = yoffset+0;
2375                         // this r value looks like a 'dot' particle, fading sharply to
2376                         // black at the edges
2377                         // (probably not realistic but looks good enough)
2378                         //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
2379                         //r = (dir ? 1.0f : brighten)/(range*2+1);
2380                         r = (dir ? 1.0f : brighten)/(range*2+1)*(1 - x*x/(float)(range*range));
2381                         GL_Color(r, r, r, 1);
2382                         R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2383                         r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2384                         GL_BlendFunc(GL_ONE, GL_ONE);
2385                 }
2386
2387                 // copy the vertically blurred bloom view to a texture
2388                 GL_ActiveTexture(0);
2389                 CHECKGLERROR
2390                 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
2391                 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2392         }
2393
2394         // apply subtract last
2395         // (just like it would be in a GLSL shader)
2396         if (r_bloom_colorsubtract.value > 0 && gl_support_ext_blend_subtract)
2397         {
2398                 GL_BlendFunc(GL_ONE, GL_ZERO);
2399                 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2400                 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
2401                 GL_Color(1, 1, 1, 1);
2402                 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2403                 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2404
2405                 GL_BlendFunc(GL_ONE, GL_ONE);
2406                 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2407                 R_Mesh_TexBind(0, R_GetTexture(r_texture_white));
2408                 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
2409                 GL_Color(r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, 1);
2410                 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2411                 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2412                 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2413
2414                 // copy the darkened bloom view to a texture
2415                 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2416                 GL_ActiveTexture(0);
2417                 CHECKGLERROR
2418                 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
2419                 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2420         }
2421 }
2422
2423 void R_HDR_RenderBloomTexture(void)
2424 {
2425         int oldwidth, oldheight;
2426
2427         oldwidth = r_view.width;
2428         oldheight = r_view.height;
2429         r_view.width = r_bloomstate.bloomwidth;
2430         r_view.height = r_bloomstate.bloomheight;
2431
2432         // TODO: support GL_EXT_framebuffer_object rather than reusing the framebuffer?  it might improve SLI performance.
2433         // TODO: add exposure compensation features
2434         // TODO: add fp16 framebuffer support
2435
2436         r_view.colorscale = r_bloom_colorscale.value * r_hdr_scenebrightness.value;
2437         if (r_hdr.integer)
2438                 r_view.colorscale /= r_hdr_range.value;
2439         R_RenderScene();
2440
2441         R_ResetViewRendering2D();
2442
2443         R_Bloom_CopyHDRTexture();
2444         R_Bloom_MakeTexture();
2445
2446         R_ResetViewRendering3D();
2447
2448         R_ClearScreen();
2449         if (r_timereport_active)
2450                 R_TimeReport("clear");
2451
2452
2453         // restore the view settings
2454         r_view.width = oldwidth;
2455         r_view.height = oldheight;
2456 }
2457
2458 static void R_BlendView(void)
2459 {
2460         if (r_bloomstate.enabled && r_bloomstate.hdr)
2461         {
2462                 // render high dynamic range bloom effect
2463                 // the bloom texture was made earlier this render, so we just need to
2464                 // blend it onto the screen...
2465                 R_ResetViewRendering2D();
2466                 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
2467                 R_Mesh_ColorPointer(NULL, 0, 0);
2468                 GL_Color(1, 1, 1, 1);
2469                 GL_BlendFunc(GL_ONE, GL_ONE);
2470                 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2471                 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
2472                 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2473                 r_refdef.stats.bloom_drawpixels += r_view.width * r_view.height;
2474         }
2475         else if (r_bloomstate.enabled)
2476         {
2477                 // render simple bloom effect
2478                 // copy the screen and shrink it and darken it for the bloom process
2479                 R_Bloom_CopyScreenTexture(r_bloom_colorscale.value);
2480                 // make the bloom texture
2481                 R_Bloom_MakeTexture();
2482                 // put the original screen image back in place and blend the bloom
2483                 // texture on it
2484                 R_ResetViewRendering2D();
2485                 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
2486                 R_Mesh_ColorPointer(NULL, 0, 0);
2487                 GL_Color(1, 1, 1, 1);
2488                 GL_BlendFunc(GL_ONE, GL_ZERO);
2489                 // do both in one pass if possible
2490                 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2491                 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
2492                 if (r_textureunits.integer >= 2 && gl_combine.integer)
2493                 {
2494                         R_Mesh_TexCombine(1, GL_ADD, GL_ADD, 1, 1);
2495                         R_Mesh_TexBind(1, R_GetTexture(r_bloomstate.texture_screen));
2496                         R_Mesh_TexCoordPointer(1, 2, r_bloomstate.screentexcoord2f, 0, 0);
2497                 }
2498                 else
2499                 {
2500                         R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2501                         r_refdef.stats.bloom_drawpixels += r_view.width * r_view.height;
2502                         // now blend on the bloom texture
2503                         GL_BlendFunc(GL_ONE, GL_ONE);
2504                         R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
2505                         R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
2506                 }
2507                 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2508                 r_refdef.stats.bloom_drawpixels += r_view.width * r_view.height;
2509         }
2510         if (r_refdef.viewblend[3] >= (1.0f / 256.0f))
2511         {
2512                 // apply a color tint to the whole view
2513                 R_ResetViewRendering2D();
2514                 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
2515                 R_Mesh_ColorPointer(NULL, 0, 0);
2516                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2517                 GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
2518                 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2519         }
2520 }
2521
2522 void R_RenderScene(void);
2523
2524 matrix4x4_t r_waterscrollmatrix;
2525
2526 void R_UpdateVariables(void)
2527 {
2528         R_Textures_Frame();
2529
2530         r_refdef.farclip = 4096;
2531         if (r_refdef.worldmodel)
2532                 r_refdef.farclip += VectorDistance(r_refdef.worldmodel->normalmins, r_refdef.worldmodel->normalmaxs);
2533         r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
2534
2535         if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
2536                 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
2537         r_refdef.polygonfactor = 0;
2538         r_refdef.polygonoffset = 0;
2539         r_refdef.shadowpolygonfactor = r_refdef.polygonfactor + r_shadow_polygonfactor.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
2540         r_refdef.shadowpolygonoffset = r_refdef.polygonoffset + r_shadow_polygonoffset.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
2541
2542         r_refdef.rtworld = r_shadow_realtime_world.integer;
2543         r_refdef.rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
2544         r_refdef.rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer && r_dynamic.integer;
2545         r_refdef.rtdlightshadows = r_refdef.rtdlight && r_shadow_realtime_dlight_shadows.integer && gl_stencil;
2546         r_refdef.lightmapintensity = r_refdef.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
2547         if (r_showsurfaces.integer)
2548         {
2549                 r_refdef.rtworld = false;
2550                 r_refdef.rtworldshadows = false;
2551                 r_refdef.rtdlight = false;
2552                 r_refdef.rtdlightshadows = false;
2553                 r_refdef.lightmapintensity = 0;
2554         }
2555
2556         if (gamemode == GAME_NEHAHRA)
2557         {
2558                 if (gl_fogenable.integer)
2559                 {
2560                         r_refdef.oldgl_fogenable = true;
2561                         r_refdef.fog_density = gl_fogdensity.value;
2562                         r_refdef.fog_red = gl_fogred.value;
2563                         r_refdef.fog_green = gl_foggreen.value;
2564                         r_refdef.fog_blue = gl_fogblue.value;
2565                 }
2566                 else if (r_refdef.oldgl_fogenable)
2567                 {
2568                         r_refdef.oldgl_fogenable = false;
2569                         r_refdef.fog_density = 0;
2570                         r_refdef.fog_red = 0;
2571                         r_refdef.fog_green = 0;
2572                         r_refdef.fog_blue = 0;
2573                 }
2574         }
2575         if (r_refdef.fog_density)
2576         {
2577                 r_refdef.fogcolor[0] = bound(0.0f, r_refdef.fog_red  , 1.0f);
2578                 r_refdef.fogcolor[1] = bound(0.0f, r_refdef.fog_green, 1.0f);
2579                 r_refdef.fogcolor[2] = bound(0.0f, r_refdef.fog_blue , 1.0f);
2580         }
2581         if (r_refdef.fog_density)
2582         {
2583                 r_refdef.fogenabled = true;
2584                 // this is the point where the fog reaches 0.9986 alpha, which we
2585                 // consider a good enough cutoff point for the texture
2586                 // (0.9986 * 256 == 255.6)
2587                 r_refdef.fogrange = 400 / r_refdef.fog_density;
2588                 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
2589                 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
2590                 // fog color was already set
2591         }
2592         else
2593                 r_refdef.fogenabled = false;
2594 }
2595
2596 /*
2597 ================
2598 R_RenderView
2599 ================
2600 */
2601 void R_RenderView(void)
2602 {
2603         if (!r_refdef.entities/* || !r_refdef.worldmodel*/)
2604                 return; //Host_Error ("R_RenderView: NULL worldmodel");
2605
2606         R_Shadow_UpdateWorldLightSelection();
2607
2608         CHECKGLERROR
2609         if (r_timereport_active)
2610                 R_TimeReport("setup");
2611
2612         R_View_Update();
2613         if (r_timereport_active)
2614                 R_TimeReport("visibility");
2615
2616         R_ResetViewRendering3D();
2617
2618         R_ClearScreen();
2619         if (r_timereport_active)
2620                 R_TimeReport("clear");
2621
2622         R_Bloom_StartFrame();
2623
2624         // this produces a bloom texture to be used in R_BlendView() later
2625         if (r_hdr.integer)
2626                 R_HDR_RenderBloomTexture();
2627
2628         r_view.colorscale = r_hdr_scenebrightness.value;
2629         R_RenderScene();
2630
2631         R_BlendView();
2632         if (r_timereport_active)
2633                 R_TimeReport("blendview");
2634
2635         GL_Scissor(0, 0, vid.width, vid.height);
2636         GL_ScissorTest(false);
2637         CHECKGLERROR
2638 }
2639
2640 extern void R_DrawLightningBeams (void);
2641 extern void VM_CL_AddPolygonsToMeshQueue (void);
2642 extern void R_DrawPortals (void);
2643 extern cvar_t cl_locs_show;
2644 static void R_DrawLocs(void);
2645 static void R_DrawEntityBBoxes(void);
2646 void R_RenderScene(void)
2647 {
2648         // don't let sound skip if going slow
2649         if (r_refdef.extraupdate)
2650                 S_ExtraUpdate ();
2651
2652         R_ResetViewRendering3D();
2653
2654         R_MeshQueue_BeginScene();
2655
2656         R_SkyStartFrame();
2657
2658         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);
2659
2660         if (cl.csqc_vidvars.drawworld)
2661         {
2662                 // don't let sound skip if going slow
2663                 if (r_refdef.extraupdate)
2664                         S_ExtraUpdate ();
2665
2666                 if (r_refdef.worldmodel && r_refdef.worldmodel->DrawSky)
2667                 {
2668                         r_refdef.worldmodel->DrawSky(r_refdef.worldentity);
2669                         if (r_timereport_active)
2670                                 R_TimeReport("worldsky");
2671                 }
2672
2673                 if (R_DrawBrushModelsSky() && r_timereport_active)
2674                         R_TimeReport("bmodelsky");
2675         }
2676
2677         if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.worldmodel && r_refdef.worldmodel->DrawDepth)
2678         {
2679                 r_refdef.worldmodel->DrawDepth(r_refdef.worldentity);
2680                 if (r_timereport_active)
2681                         R_TimeReport("worlddepth");
2682         }
2683         if (r_depthfirst.integer >= 2)
2684         {
2685                 R_DrawModelsDepth();
2686                 if (r_timereport_active)
2687                         R_TimeReport("modeldepth");
2688         }
2689
2690         if (cl.csqc_vidvars.drawworld && r_refdef.worldmodel && r_refdef.worldmodel->Draw)
2691         {
2692                 r_refdef.worldmodel->Draw(r_refdef.worldentity);
2693                 if (r_timereport_active)
2694                         R_TimeReport("world");
2695         }
2696
2697         // don't let sound skip if going slow
2698         if (r_refdef.extraupdate)
2699                 S_ExtraUpdate ();
2700
2701         R_DrawModels();
2702         if (r_timereport_active)
2703                 R_TimeReport("models");
2704
2705         // don't let sound skip if going slow
2706         if (r_refdef.extraupdate)
2707                 S_ExtraUpdate ();
2708
2709         if (r_shadows.integer > 0 && r_refdef.lightmapintensity > 0)
2710         {
2711                 R_DrawModelShadows();
2712
2713                 R_ResetViewRendering3D();
2714
2715                 // don't let sound skip if going slow
2716                 if (r_refdef.extraupdate)
2717                         S_ExtraUpdate ();
2718         }
2719
2720         R_ShadowVolumeLighting(false);
2721         if (r_timereport_active)
2722                 R_TimeReport("rtlights");
2723
2724         // don't let sound skip if going slow
2725         if (r_refdef.extraupdate)
2726                 S_ExtraUpdate ();
2727
2728         if (cl.csqc_vidvars.drawworld)
2729         {
2730                 R_DrawLightningBeams();
2731                 if (r_timereport_active)
2732                         R_TimeReport("lightning");
2733
2734                 R_DrawParticles();
2735                 if (r_timereport_active)
2736                         R_TimeReport("particles");
2737
2738                 R_DrawExplosions();
2739                 if (r_timereport_active)
2740                         R_TimeReport("explosions");
2741         }
2742
2743         if (gl_support_fragment_shader)
2744         {
2745                 qglUseProgramObjectARB(0);CHECKGLERROR
2746         }
2747         VM_CL_AddPolygonsToMeshQueue();
2748
2749         if (cl_locs_show.integer)
2750         {
2751                 R_DrawLocs();
2752                 if (r_timereport_active)
2753                         R_TimeReport("showlocs");
2754         }
2755
2756         if (r_drawportals.integer)
2757         {
2758                 R_DrawPortals();
2759                 if (r_timereport_active)
2760                         R_TimeReport("portals");
2761         }
2762
2763         if (r_showbboxes.value > 0)
2764         {
2765                 R_DrawEntityBBoxes();
2766                 if (r_timereport_active)
2767                         R_TimeReport("bboxes");
2768         }
2769
2770         if (gl_support_fragment_shader)
2771         {
2772                 qglUseProgramObjectARB(0);CHECKGLERROR
2773         }
2774         R_MeshQueue_RenderTransparent();
2775         if (r_timereport_active)
2776                 R_TimeReport("drawtrans");
2777
2778         if (gl_support_fragment_shader)
2779         {
2780                 qglUseProgramObjectARB(0);CHECKGLERROR
2781         }
2782
2783         if (cl.csqc_vidvars.drawworld)
2784         {
2785                 R_DrawCoronas();
2786                 if (r_timereport_active)
2787                         R_TimeReport("coronas");
2788         }
2789
2790         // don't let sound skip if going slow
2791         if (r_refdef.extraupdate)
2792                 S_ExtraUpdate ();
2793
2794         R_ResetViewRendering2D();
2795 }
2796
2797 static const int bboxelements[36] =
2798 {
2799         5, 1, 3, 5, 3, 7,
2800         6, 2, 0, 6, 0, 4,
2801         7, 3, 2, 7, 2, 6,
2802         4, 0, 1, 4, 1, 5,
2803         4, 5, 7, 4, 7, 6,
2804         1, 0, 2, 1, 2, 3,
2805 };
2806
2807 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
2808 {
2809         int i;
2810         float *v, *c, f1, f2, vertex3f[8*3], color4f[8*4];
2811         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2812         GL_DepthMask(false);
2813         GL_DepthRange(0, 1);
2814         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
2815         R_Mesh_Matrix(&identitymatrix);
2816         R_Mesh_ResetTextureState();
2817
2818         vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2]; //
2819         vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
2820         vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
2821         vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
2822         vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
2823         vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
2824         vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
2825         vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
2826         R_FillColors(color4f, 8, cr, cg, cb, ca);
2827         if (r_refdef.fogenabled)
2828         {
2829                 for (i = 0, v = vertex3f, c = color4f;i < 8;i++, v += 3, c += 4)
2830                 {
2831                         f1 = FogPoint_World(v);
2832                         f2 = 1 - f1;
2833                         c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
2834                         c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
2835                         c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
2836                 }
2837         }
2838         R_Mesh_VertexPointer(vertex3f, 0, 0);
2839         R_Mesh_ColorPointer(color4f, 0, 0);
2840         R_Mesh_ResetTextureState();
2841         R_Mesh_Draw(0, 8, 12, bboxelements, 0, 0);
2842 }
2843
2844 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2845 {
2846         int i;
2847         float color[4];
2848         prvm_edict_t *edict;
2849         // this function draws bounding boxes of server entities
2850         if (!sv.active)
2851                 return;
2852         SV_VM_Begin();
2853         for (i = 0;i < numsurfaces;i++)
2854         {
2855                 edict = PRVM_EDICT_NUM(surfacelist[i]);
2856                 switch ((int)edict->fields.server->solid)
2857                 {
2858                         case SOLID_NOT:      Vector4Set(color, 1, 1, 1, 0.05);break;
2859                         case SOLID_TRIGGER:  Vector4Set(color, 1, 0, 1, 0.10);break;
2860                         case SOLID_BBOX:     Vector4Set(color, 0, 1, 0, 0.10);break;
2861                         case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
2862                         case SOLID_BSP:      Vector4Set(color, 0, 0, 1, 0.05);break;
2863                         default:             Vector4Set(color, 0, 0, 0, 0.50);break;
2864                 }
2865                 color[3] *= r_showbboxes.value;
2866                 color[3] = bound(0, color[3], 1);
2867                 GL_DepthTest(!r_showdisabledepthtest.integer);
2868                 GL_CullFace(GL_BACK);
2869                 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
2870         }
2871         SV_VM_End();
2872 }
2873
2874 static void R_DrawEntityBBoxes(void)
2875 {
2876         int i;
2877         prvm_edict_t *edict;
2878         vec3_t center;
2879         // this function draws bounding boxes of server entities
2880         if (!sv.active)
2881                 return;
2882         SV_VM_Begin();
2883         for (i = 0;i < prog->num_edicts;i++)
2884         {
2885                 edict = PRVM_EDICT_NUM(i);
2886                 if (edict->priv.server->free)
2887                         continue;
2888                 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
2889                 R_MeshQueue_AddTransparent(center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)NULL);
2890         }
2891         SV_VM_End();
2892 }
2893
2894 int nomodelelements[24] =
2895 {
2896         5, 2, 0,
2897         5, 1, 2,
2898         5, 0, 3,
2899         5, 3, 1,
2900         0, 2, 4,
2901         2, 1, 4,
2902         3, 0, 4,
2903         1, 3, 4
2904 };
2905
2906 float nomodelvertex3f[6*3] =
2907 {
2908         -16,   0,   0,
2909          16,   0,   0,
2910           0, -16,   0,
2911           0,  16,   0,
2912           0,   0, -16,
2913           0,   0,  16
2914 };
2915
2916 float nomodelcolor4f[6*4] =
2917 {
2918         0.0f, 0.0f, 0.5f, 1.0f,
2919         0.0f, 0.0f, 0.5f, 1.0f,
2920         0.0f, 0.5f, 0.0f, 1.0f,
2921         0.0f, 0.5f, 0.0f, 1.0f,
2922         0.5f, 0.0f, 0.0f, 1.0f,
2923         0.5f, 0.0f, 0.0f, 1.0f
2924 };
2925
2926 void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2927 {
2928         int i;
2929         float f1, f2, *c;
2930         float color4f[6*4];
2931         // this is only called once per entity so numsurfaces is always 1, and
2932         // surfacelist is always {0}, so this code does not handle batches
2933         R_Mesh_Matrix(&ent->matrix);
2934
2935         if (ent->flags & EF_ADDITIVE)
2936         {
2937                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2938                 GL_DepthMask(false);
2939         }
2940         else if (ent->alpha < 1)
2941         {
2942                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2943                 GL_DepthMask(false);
2944         }
2945         else
2946         {
2947                 GL_BlendFunc(GL_ONE, GL_ZERO);
2948                 GL_DepthMask(true);
2949         }
2950         GL_DepthRange(0, (ent->flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
2951         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
2952         GL_DepthTest(!(ent->effects & EF_NODEPTHTEST));
2953         GL_CullFace((ent->effects & EF_DOUBLESIDED) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
2954         R_Mesh_VertexPointer(nomodelvertex3f, 0, 0);
2955         if (r_refdef.fogenabled)
2956         {
2957                 vec3_t org;
2958                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
2959                 R_Mesh_ColorPointer(color4f, 0, 0);
2960                 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2961                 f1 = FogPoint_World(org);
2962                 f2 = 1 - f1;
2963                 for (i = 0, c = color4f;i < 6;i++, c += 4)
2964                 {
2965                         c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
2966                         c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
2967                         c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
2968                         c[3] *= ent->alpha;
2969                 }
2970         }
2971         else if (ent->alpha != 1)
2972         {
2973                 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
2974                 R_Mesh_ColorPointer(color4f, 0, 0);
2975                 for (i = 0, c = color4f;i < 6;i++, c += 4)
2976                         c[3] *= ent->alpha;
2977         }
2978         else
2979                 R_Mesh_ColorPointer(nomodelcolor4f, 0, 0);
2980         R_Mesh_ResetTextureState();
2981         R_Mesh_Draw(0, 6, 8, nomodelelements, 0, 0);
2982 }
2983
2984 void R_DrawNoModel(entity_render_t *ent)
2985 {
2986         vec3_t org;
2987         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2988         //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
2989                 R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_view.origin : org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
2990         //else
2991         //      R_DrawNoModelCallback(ent, 0);
2992 }
2993
2994 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
2995 {
2996         vec3_t right1, right2, diff, normal;
2997
2998         VectorSubtract (org2, org1, normal);
2999
3000         // calculate 'right' vector for start
3001         VectorSubtract (r_view.origin, org1, diff);
3002         CrossProduct (normal, diff, right1);
3003         VectorNormalize (right1);
3004
3005         // calculate 'right' vector for end
3006         VectorSubtract (r_view.origin, org2, diff);
3007         CrossProduct (normal, diff, right2);
3008         VectorNormalize (right2);
3009
3010         vert[ 0] = org1[0] + width * right1[0];
3011         vert[ 1] = org1[1] + width * right1[1];
3012         vert[ 2] = org1[2] + width * right1[2];
3013         vert[ 3] = org1[0] - width * right1[0];
3014         vert[ 4] = org1[1] - width * right1[1];
3015         vert[ 5] = org1[2] - width * right1[2];
3016         vert[ 6] = org2[0] - width * right2[0];
3017         vert[ 7] = org2[1] - width * right2[1];
3018         vert[ 8] = org2[2] - width * right2[2];
3019         vert[ 9] = org2[0] + width * right2[0];
3020         vert[10] = org2[1] + width * right2[1];
3021         vert[11] = org2[2] + width * right2[2];
3022 }
3023
3024 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
3025
3026 void R_DrawSprite(int blendfunc1, int blendfunc2, rtexture_t *texture, rtexture_t *fogtexture, qboolean depthdisable, qboolean depthshort, 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)
3027 {
3028         float fog = 1.0f;
3029         float vertex3f[12];
3030
3031         if (r_refdef.fogenabled)
3032                 fog = FogPoint_World(origin);
3033
3034         R_Mesh_Matrix(&identitymatrix);
3035         GL_BlendFunc(blendfunc1, blendfunc2);
3036
3037         if(v_flipped_state)
3038         {
3039                 scalex1 = -scalex1;
3040                 scalex2 = -scalex2;
3041                 GL_CullFace(GL_BACK);
3042         }
3043         else
3044                 GL_CullFace(GL_FRONT);
3045
3046         GL_DepthMask(false);
3047         GL_DepthRange(0, depthshort ? 0.0625 : 1);
3048         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
3049         GL_DepthTest(!depthdisable);
3050
3051         vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
3052         vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
3053         vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
3054         vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
3055         vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
3056         vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
3057         vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
3058         vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
3059         vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
3060         vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
3061         vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
3062         vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
3063
3064         R_Mesh_VertexPointer(vertex3f, 0, 0);
3065         R_Mesh_ColorPointer(NULL, 0, 0);
3066         R_Mesh_ResetTextureState();
3067         R_Mesh_TexBind(0, R_GetTexture(texture));
3068         R_Mesh_TexCoordPointer(0, 2, spritetexcoord2f, 0, 0);
3069         // FIXME: fixed function path can't properly handle r_view.colorscale > 1
3070         GL_Color(cr * fog * r_view.colorscale, cg * fog * r_view.colorscale, cb * fog * r_view.colorscale, ca);
3071         R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3072
3073         if (blendfunc2 == GL_ONE_MINUS_SRC_ALPHA)
3074         {
3075                 R_Mesh_TexBind(0, R_GetTexture(fogtexture));
3076                 GL_BlendFunc(blendfunc1, GL_ONE);
3077                 fog = 1 - fog;
3078                 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);
3079                 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3080         }
3081 }
3082
3083 int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
3084 {
3085         int i;
3086         float *vertex3f;
3087         float v[3];
3088         VectorSet(v, x, y, z);
3089         for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
3090                 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
3091                         break;
3092         if (i == mesh->numvertices)
3093         {
3094                 if (mesh->numvertices < mesh->maxvertices)
3095                 {
3096                         VectorCopy(v, vertex3f);
3097                         mesh->numvertices++;
3098                 }
3099                 return mesh->numvertices;
3100         }
3101         else
3102                 return i;
3103 }
3104
3105 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
3106 {
3107         int i;
3108         int *e, element[3];
3109         element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
3110         element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
3111         e = mesh->element3i + mesh->numtriangles * 3;
3112         for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
3113         {
3114                 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
3115                 if (mesh->numtriangles < mesh->maxtriangles)
3116                 {
3117                         *e++ = element[0];
3118                         *e++ = element[1];
3119                         *e++ = element[2];
3120                         mesh->numtriangles++;
3121                 }
3122                 element[1] = element[2];
3123         }
3124 }
3125
3126 void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
3127 {
3128         int i;
3129         int *e, element[3];
3130         element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
3131         element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
3132         e = mesh->element3i + mesh->numtriangles * 3;
3133         for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
3134         {
3135                 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
3136                 if (mesh->numtriangles < mesh->maxtriangles)
3137                 {
3138                         *e++ = element[0];
3139                         *e++ = element[1];
3140                         *e++ = element[2];
3141                         mesh->numtriangles++;
3142                 }
3143                 element[1] = element[2];
3144         }
3145 }
3146
3147 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
3148 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
3149 {
3150         int planenum, planenum2;
3151         int w;
3152         int tempnumpoints;
3153         mplane_t *plane, *plane2;
3154         double maxdist;
3155         double temppoints[2][256*3];
3156         // figure out how large a bounding box we need to properly compute this brush
3157         maxdist = 0;
3158         for (w = 0;w < numplanes;w++)
3159                 maxdist = max(maxdist, planes[w].dist);
3160         // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
3161         maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
3162         for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
3163         {
3164                 w = 0;
3165                 tempnumpoints = 4;
3166                 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
3167                 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
3168                 {
3169                         if (planenum2 == planenum)
3170                                 continue;
3171                         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);
3172                         w = !w;
3173                 }
3174                 if (tempnumpoints < 3)
3175                         continue;
3176                 // generate elements forming a triangle fan for this polygon
3177                 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
3178         }
3179 }
3180
3181 static void R_DrawCollisionBrush(const colbrushf_t *brush)
3182 {
3183         int i;
3184         R_Mesh_VertexPointer(brush->points->v, 0, 0);
3185         i = (int)(((size_t)brush) / sizeof(colbrushf_t));
3186         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);
3187         GL_LockArrays(0, brush->numpoints);
3188         R_Mesh_Draw(0, brush->numpoints, brush->numtriangles, brush->elements, 0, 0);
3189         GL_LockArrays(0, 0);
3190 }
3191
3192 static void R_DrawCollisionSurface(const entity_render_t *ent, const msurface_t *surface)
3193 {
3194         int i;
3195         if (!surface->num_collisiontriangles)
3196                 return;
3197         R_Mesh_VertexPointer(surface->data_collisionvertex3f, 0, 0);
3198         i = (int)(((size_t)surface) / sizeof(msurface_t));
3199         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);
3200         GL_LockArrays(0, surface->num_collisionvertices);
3201         R_Mesh_Draw(0, surface->num_collisionvertices, surface->num_collisiontriangles, surface->data_collisionelement3i, 0, 0);
3202         GL_LockArrays(0, 0);
3203 }
3204
3205 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)
3206 {
3207         texturelayer_t *layer;
3208         layer = t->currentlayers + t->currentnumlayers++;
3209         layer->type = type;
3210         layer->depthmask = depthmask;
3211         layer->blendfunc1 = blendfunc1;
3212         layer->blendfunc2 = blendfunc2;
3213         layer->texture = texture;
3214         layer->texmatrix = *matrix;
3215         layer->color[0] = r * r_view.colorscale;
3216         layer->color[1] = g * r_view.colorscale;
3217         layer->color[2] = b * r_view.colorscale;
3218         layer->color[3] = a;
3219 }
3220
3221 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
3222 {
3223         double index, f;
3224         index = parms[2] + r_refdef.time * parms[3];
3225         index -= floor(index);
3226         switch (func)
3227         {
3228         default:
3229         case Q3WAVEFUNC_NONE:
3230         case Q3WAVEFUNC_NOISE:
3231         case Q3WAVEFUNC_COUNT:
3232                 f = 0;
3233                 break;
3234         case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
3235         case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
3236         case Q3WAVEFUNC_SAWTOOTH: f = index;break;
3237         case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
3238         case Q3WAVEFUNC_TRIANGLE:
3239                 index *= 4;
3240                 f = index - floor(index);
3241                 if (index < 1)
3242                         f = f;
3243                 else if (index < 2)
3244                         f = 1 - f;
3245                 else if (index < 3)
3246                         f = -f;
3247                 else
3248                         f = -(1 - f);
3249                 break;
3250         }
3251         return (float)(parms[0] + parms[1] * f);
3252 }
3253
3254 void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t)
3255 {
3256         int i;
3257         model_t *model = ent->model;
3258         float f;
3259         float tcmat[12];
3260         q3shaderinfo_layer_tcmod_t *tcmod;
3261
3262         // switch to an alternate material if this is a q1bsp animated material
3263         {
3264                 texture_t *texture = t;
3265                 int s = ent->skinnum;
3266                 if ((unsigned int)s >= (unsigned int)model->numskins)
3267                         s = 0;
3268                 if (model->skinscenes)
3269                 {
3270                         if (model->skinscenes[s].framecount > 1)
3271                                 s = model->skinscenes[s].firstframe + (unsigned int) (r_refdef.time * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
3272                         else
3273                                 s = model->skinscenes[s].firstframe;
3274                 }
3275                 if (s > 0)
3276                         t = t + s * model->num_surfaces;
3277                 if (t->animated)
3278                 {
3279                         // use an alternate animation if the entity's frame is not 0,
3280                         // and only if the texture has an alternate animation
3281                         if (ent->frame2 != 0 && t->anim_total[1])
3282                                 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(r_refdef.time * 5.0f) % t->anim_total[1]) : 0];
3283                         else
3284                                 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(r_refdef.time * 5.0f) % t->anim_total[0]) : 0];
3285                 }
3286                 texture->currentframe = t;
3287         }
3288
3289         // update currentskinframe to be a qw skin or animation frame
3290         if ((i = ent->entitynumber - 1) >= 0 && i < cl.maxclients)
3291         {
3292                 if (strcmp(r_qwskincache[i], cl.scores[i].qw_skin))
3293                 {
3294                         strlcpy(r_qwskincache[i], cl.scores[i].qw_skin, sizeof(r_qwskincache[i]));
3295                         Con_DPrintf("loading skins/%s\n", r_qwskincache[i]);
3296                         r_qwskincache_skinframe[i] = R_SkinFrame_LoadExternal(va("skins/%s", r_qwskincache[i]), TEXF_PRECACHE | (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP, developer.integer > 0);
3297                 }
3298                 t->currentskinframe = r_qwskincache_skinframe[i];
3299                 if (t->currentskinframe == NULL)
3300                         t->currentskinframe = t->skinframes[(int)(t->skinframerate * (cl.time - ent->frame2time)) % t->numskinframes];
3301         }
3302         else if (t->numskinframes >= 2)
3303                 t->currentskinframe = t->skinframes[(int)(t->skinframerate * (cl.time - ent->frame2time)) % t->numskinframes];
3304         if (t->backgroundnumskinframes >= 2)
3305                 t->backgroundcurrentskinframe = t->backgroundskinframes[(int)(t->backgroundskinframerate * (cl.time - ent->frame2time)) % t->backgroundnumskinframes];
3306
3307         t->currentmaterialflags = t->basematerialflags;
3308         t->currentalpha = ent->alpha;
3309         if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_novis.integer))
3310                 t->currentalpha *= r_wateralpha.value;
3311         if (!(ent->flags & RENDER_LIGHT))
3312                 t->currentmaterialflags |= MATERIALFLAG_FULLBRIGHT;
3313         if (ent->effects & EF_ADDITIVE)
3314                 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
3315         else if (t->currentalpha < 1)
3316                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
3317         if (ent->effects & EF_DOUBLESIDED)
3318                 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
3319         if (ent->effects & EF_NODEPTHTEST)
3320                 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
3321         if (ent->flags & RENDER_VIEWMODEL)
3322                 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
3323         if (t->backgroundnumskinframes && !(t->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED))
3324                 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
3325
3326         for (i = 0, tcmod = t->tcmods;i < Q3MAXTCMODS && (tcmod->tcmod || i < 1);i++, tcmod++)
3327         {
3328                 matrix4x4_t matrix;
3329                 switch(tcmod->tcmod)
3330                 {
3331                 case Q3TCMOD_COUNT:
3332                 case Q3TCMOD_NONE:
3333                         if (t->currentmaterialflags & MATERIALFLAG_WATER && r_waterscroll.value != 0)
3334                                 matrix = r_waterscrollmatrix;
3335                         else
3336                                 matrix = identitymatrix;
3337                         break;
3338                 case Q3TCMOD_ENTITYTRANSLATE:
3339                         // this is used in Q3 to allow the gamecode to control texcoord
3340                         // scrolling on the entity, which is not supported in darkplaces yet.
3341                         Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
3342                         break;
3343                 case Q3TCMOD_ROTATE:
3344                         Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
3345                         Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * r_refdef.time, 0, 0, 1);
3346                         Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
3347                         break;
3348                 case Q3TCMOD_SCALE:
3349                         Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
3350                         break;
3351                 case Q3TCMOD_SCROLL:
3352                         Matrix4x4_CreateTranslate(&matrix, tcmod->parms[0] * r_refdef.time, tcmod->parms[1] * r_refdef.time, 0);
3353                         break;
3354                 case Q3TCMOD_STRETCH:
3355                         f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
3356                         Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
3357                         break;
3358                 case Q3TCMOD_TRANSFORM:
3359                         VectorSet(tcmat +  0, tcmod->parms[0], tcmod->parms[1], 0);
3360                         VectorSet(tcmat +  3, tcmod->parms[2], tcmod->parms[3], 0);
3361                         VectorSet(tcmat +  6, 0                   , 0                , 1);
3362                         VectorSet(tcmat +  9, tcmod->parms[4], tcmod->parms[5], 0);
3363                         Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
3364                         break;
3365                 case Q3TCMOD_TURBULENT:
3366                         // this is handled in the RSurf_PrepareVertices function
3367                         matrix = identitymatrix;
3368                         break;
3369                 }
3370                 // either replace or concatenate the transformation
3371                 if (i < 1)
3372                         t->currenttexmatrix = matrix;
3373                 else
3374                 {
3375                         matrix4x4_t temp = t->currenttexmatrix;
3376                         Matrix4x4_Concat(&t->currenttexmatrix, &matrix, &temp);
3377                 }
3378         }
3379
3380         t->colormapping = VectorLength2(ent->colormap_pantscolor) + VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f);
3381         t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
3382         t->glosstexture = r_texture_white;
3383         t->backgroundbasetexture = t->backgroundnumskinframes ? ((!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base) : r_texture_white;
3384         t->backgroundglosstexture = r_texture_white;
3385         t->specularpower = r_shadow_glossexponent.value;
3386         // TODO: store reference values for these in the texture?
3387         t->specularscale = 0;
3388         if (r_shadow_gloss.integer > 0)
3389         {
3390                 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
3391                 {
3392                         if (r_shadow_glossintensity.value > 0)
3393                         {
3394                                 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_black;
3395                                 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_black;
3396                                 t->specularscale = r_shadow_glossintensity.value;
3397                         }
3398                 }
3399                 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
3400                         t->specularscale = r_shadow_gloss2intensity.value;
3401         }
3402
3403         t->currentpolygonfactor = r_refdef.polygonfactor;
3404         t->currentpolygonoffset = r_refdef.polygonoffset;
3405         // submodels are biased to avoid z-fighting with world surfaces that they
3406         // may be exactly overlapping (avoids z-fighting artifacts on certain
3407         // doors and things in Quake maps)
3408         if (ent->model->brush.submodel)
3409         {
3410                 t->currentpolygonfactor = r_refdef.polygonfactor + r_polygonoffset_submodel_factor.value;
3411                 t->currentpolygonoffset = r_refdef.polygonoffset + r_polygonoffset_submodel_offset.value;
3412         }
3413
3414         VectorClear(t->dlightcolor);
3415         t->currentnumlayers = 0;
3416         if (!(t->currentmaterialflags & MATERIALFLAG_NODRAW))
3417         {
3418                 if (!(t->currentmaterialflags & MATERIALFLAG_SKY))
3419                 {
3420                         int blendfunc1, blendfunc2, depthmask;
3421                         if (t->currentmaterialflags & MATERIALFLAG_ADD)
3422                         {
3423                                 blendfunc1 = GL_SRC_ALPHA;
3424                                 blendfunc2 = GL_ONE;
3425                         }
3426                         else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
3427                         {
3428                                 blendfunc1 = GL_SRC_ALPHA;
3429                                 blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
3430                         }
3431                         else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
3432                         {
3433                                 blendfunc1 = t->customblendfunc[0];
3434                                 blendfunc2 = t->customblendfunc[1];
3435                         }
3436                         else
3437                         {
3438                                 blendfunc1 = GL_ONE;
3439                                 blendfunc2 = GL_ZERO;
3440                         }
3441                         depthmask = !(t->currentmaterialflags & MATERIALFLAG_BLENDED);
3442                         if (t->currentmaterialflags & (MATERIALFLAG_WATER | MATERIALFLAG_WALL))
3443                         {
3444                                 rtexture_t *currentbasetexture;
3445                                 int layerflags = 0;
3446                                 if (r_refdef.fogenabled && (t->currentmaterialflags & MATERIALFLAG_BLENDED))
3447                                         layerflags |= TEXTURELAYERFLAG_FOGDARKEN;
3448                                 currentbasetexture = (VectorLength2(ent->colormap_pantscolor) + VectorLength2(ent->colormap_shirtcolor) < (1.0f / 1048576.0f) && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
3449                                 if (t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
3450                                 {
3451                                         // fullbright is not affected by r_refdef.lightmapintensity
3452                                         R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_TEXTURE, currentbasetexture, &t->currenttexmatrix, ent->colormod[0], ent->colormod[1], ent->colormod[2], t->currentalpha);
3453                                         if (VectorLength2(ent->colormap_pantscolor) >= (1.0f / 1048576.0f) && t->currentskinframe->pants)
3454                                                 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);
3455                                         if (VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->currentskinframe->shirt)
3456                                                 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);
3457                                 }
3458                                 else
3459                                 {
3460                                         float colorscale;
3461                                         // set the color tint used for lights affecting this surface
3462                                         VectorSet(t->dlightcolor, ent->colormod[0] * t->currentalpha, ent->colormod[1] * t->currentalpha, ent->colormod[2] * t->currentalpha);
3463                                         colorscale = 2;
3464                                         // q3bsp has no lightmap updates, so the lightstylevalue that
3465                                         // would normally be baked into the lightmap must be
3466                                         // applied to the color
3467                                         if (ent->model->type == mod_brushq3)
3468                                                 colorscale *= r_refdef.lightstylevalue[0] * (1.0f / 256.0f);
3469                                         colorscale *= r_refdef.lightmapintensity;
3470                                         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);
3471                                         if (r_ambient.value >= (1.0f/64.0f))
3472                                                 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);
3473                                         if (VectorLength2(ent->colormap_pantscolor) >= (1.0f / 1048576.0f) && t->currentskinframe->pants)
3474                                         {
3475                                                 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);
3476                                                 if (r_ambient.value >= (1.0f/64.0f))
3477                                                         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);
3478                                         }
3479                                         if (VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->currentskinframe->shirt)
3480                                         {
3481                                                 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);
3482                                                 if (r_ambient.value >= (1.0f/64.0f))
3483                                                         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);
3484                                         }
3485                                 }
3486                                 if (t->currentskinframe->glow != NULL)
3487                                         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);
3488                                 if (r_refdef.fogenabled && !(t->currentmaterialflags & MATERIALFLAG_ADD))
3489                                 {
3490                                         // if this is opaque use alpha blend which will darken the earlier
3491                                         // passes cheaply.
3492                                         //
3493                                         // if this is an alpha blended material, all the earlier passes
3494                                         // were darkened by fog already, so we only need to add the fog
3495                                         // color ontop through the fog mask texture
3496                                         //
3497                                         // if this is an additive blended material, all the earlier passes
3498                                         // were darkened by fog already, and we should not add fog color
3499                                         // (because the background was not darkened, there is no fog color
3500                                         // that was lost behind it).
3501                                         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);
3502                                 }
3503                         }
3504                 }
3505         }
3506 }
3507
3508 void R_UpdateAllTextureInfo(entity_render_t *ent)
3509 {
3510         int i;
3511         if (ent->model)
3512                 for (i = 0;i < ent->model->num_texturesperskin;i++)
3513                         R_UpdateTextureInfo(ent, ent->model->data_textures + i);
3514 }
3515
3516 rsurfacestate_t rsurface;
3517
3518 void R_Mesh_ResizeArrays(int newvertices)
3519 {
3520         float *base;
3521         if (rsurface.array_size >= newvertices)
3522                 return;
3523         if (rsurface.array_modelvertex3f)
3524                 Mem_Free(rsurface.array_modelvertex3f);
3525         rsurface.array_size = (newvertices + 1023) & ~1023;
3526         base = (float *)Mem_Alloc(r_main_mempool, rsurface.array_size * sizeof(float[33]));
3527         rsurface.array_modelvertex3f     = base + rsurface.array_size * 0;
3528         rsurface.array_modelsvector3f    = base + rsurface.array_size * 3;
3529         rsurface.array_modeltvector3f    = base + rsurface.array_size * 6;
3530         rsurface.array_modelnormal3f     = base + rsurface.array_size * 9;
3531         rsurface.array_deformedvertex3f  = base + rsurface.array_size * 12;
3532         rsurface.array_deformedsvector3f = base + rsurface.array_size * 15;
3533         rsurface.array_deformedtvector3f = base + rsurface.array_size * 18;
3534         rsurface.array_deformednormal3f  = base + rsurface.array_size * 21;
3535         rsurface.array_texcoord3f        = base + rsurface.array_size * 24;
3536         rsurface.array_color4f           = base + rsurface.array_size * 27;
3537         rsurface.array_generatedtexcoordtexture2f = base + rsurface.array_size * 31;
3538 }
3539
3540 void RSurf_CleanUp(void)
3541 {
3542         CHECKGLERROR
3543         if (rsurface.mode == RSURFMODE_GLSL)
3544         {
3545                 qglUseProgramObjectARB(0);CHECKGLERROR
3546         }
3547         GL_AlphaTest(false);
3548         rsurface.mode = RSURFMODE_NONE;
3549         rsurface.uselightmaptexture = false;
3550         rsurface.texture = NULL;
3551 }
3552
3553 void RSurf_ActiveWorldEntity(void)
3554 {
3555         model_t *model = r_refdef.worldmodel;
3556         RSurf_CleanUp();
3557         if (rsurface.array_size < model->surfmesh.num_vertices)
3558                 R_Mesh_ResizeArrays(model->surfmesh.num_vertices);
3559         rsurface.matrix = identitymatrix;
3560         rsurface.inversematrix = identitymatrix;
3561         R_Mesh_Matrix(&identitymatrix);
3562         VectorCopy(r_view.origin, rsurface.modelorg);
3563         VectorSet(rsurface.modellight_ambient, 0, 0, 0);
3564         VectorSet(rsurface.modellight_diffuse, 0, 0, 0);
3565         VectorSet(rsurface.modellight_lightdir, 0, 0, 1);
3566         VectorSet(rsurface.colormap_pantscolor, 0, 0, 0);
3567         VectorSet(rsurface.colormap_shirtcolor, 0, 0, 0);
3568         rsurface.frameblend[0].frame = 0;
3569         rsurface.frameblend[0].lerp = 1;
3570         rsurface.frameblend[1].frame = 0;
3571         rsurface.frameblend[1].lerp = 0;
3572         rsurface.frameblend[2].frame = 0;
3573         rsurface.frameblend[2].lerp = 0;
3574         rsurface.frameblend[3].frame = 0;
3575         rsurface.frameblend[3].lerp = 0;
3576         rsurface.modelvertex3f  = model->surfmesh.data_vertex3f;
3577         rsurface.modelvertex3f_bufferobject = model->surfmesh.vbo;
3578         rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f;
3579         rsurface.modelsvector3f = model->surfmesh.data_svector3f;
3580         rsurface.modelsvector3f_bufferobject = model->surfmesh.vbo;
3581         rsurface.modelsvector3f_bufferoffset = model->surfmesh.vbooffset_svector3f;
3582         rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
3583         rsurface.modeltvector3f_bufferobject = model->surfmesh.vbo;
3584         rsurface.modeltvector3f_bufferoffset = model->surfmesh.vbooffset_tvector3f;
3585         rsurface.modelnormal3f  = model->surfmesh.data_normal3f;
3586         rsurface.modelnormal3f_bufferobject = model->surfmesh.vbo;
3587         rsurface.modelnormal3f_bufferoffset = model->surfmesh.vbooffset_normal3f;
3588         rsurface.modellightmapcolor4f  = model->surfmesh.data_lightmapcolor4f;
3589         rsurface.modellightmapcolor4f_bufferobject = model->surfmesh.vbo;
3590         rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.vbooffset_lightmapcolor4f;
3591         rsurface.modeltexcoordtexture2f  = model->surfmesh.data_texcoordtexture2f;
3592         rsurface.modeltexcoordtexture2f_bufferobject = model->surfmesh.vbo;
3593         rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.vbooffset_texcoordtexture2f;
3594         rsurface.modeltexcoordlightmap2f  = model->surfmesh.data_texcoordlightmap2f;
3595         rsurface.modeltexcoordlightmap2f_bufferobject = model->surfmesh.vbo;
3596         rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f;
3597         rsurface.modelelement3i = model->surfmesh.data_element3i;
3598         rsurface.modelelement3i_bufferobject = model->surfmesh.ebo;
3599         rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
3600         rsurface.modelnum_vertices = model->surfmesh.num_vertices;
3601         rsurface.modelnum_triangles = model->surfmesh.num_triangles;
3602         rsurface.modelsurfaces = model->data_surfaces;
3603         rsurface.generatedvertex = false;
3604         rsurface.vertex3f  = rsurface.modelvertex3f;
3605         rsurface.vertex3f_bufferobject = rsurface.modelvertex3f_bufferobject;
3606         rsurface.vertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
3607         rsurface.svector3f = rsurface.modelsvector3f;
3608         rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject;
3609         rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
3610         rsurface.tvector3f = rsurface.modeltvector3f;
3611         rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject;
3612         rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
3613         rsurface.normal3f  = rsurface.modelnormal3f;
3614         rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject;
3615         rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
3616         rsurface.texcoordtexture2f = rsurface.modeltexcoordtexture2f;
3617 }
3618
3619 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
3620 {
3621         model_t *model = ent->model;
3622         RSurf_CleanUp();
3623         if (rsurface.array_size < model->surfmesh.num_vertices)
3624                 R_Mesh_ResizeArrays(model->surfmesh.num_vertices);
3625         rsurface.matrix = ent->matrix;
3626         rsurface.inversematrix = ent->inversematrix;
3627         R_Mesh_Matrix(&rsurface.matrix);
3628         Matrix4x4_Transform(&rsurface.inversematrix, r_view.origin, rsurface.modelorg);
3629         VectorCopy(ent->modellight_ambient, rsurface.modellight_ambient);
3630         VectorCopy(ent->modellight_diffuse, rsurface.modellight_diffuse);
3631         VectorCopy(ent->modellight_lightdir, rsurface.modellight_lightdir);
3632         VectorCopy(ent->colormap_pantscolor, rsurface.colormap_pantscolor);
3633         VectorCopy(ent->colormap_shirtcolor, rsurface.colormap_shirtcolor);
3634         rsurface.frameblend[0] = ent->frameblend[0];
3635         rsurface.frameblend[1] = ent->frameblend[1];
3636         rsurface.frameblend[2] = ent->frameblend[2];
3637         rsurface.frameblend[3] = ent->frameblend[3];
3638         if (model->surfmesh.isanimated && (rsurface.frameblend[0].lerp != 1 || rsurface.frameblend[0].frame != 0))
3639         {
3640                 if (wanttangents)
3641                 {
3642                         rsurface.modelvertex3f = rsurface.array_modelvertex3f;
3643                         rsurface.modelsvector3f = rsurface.array_modelsvector3f;
3644                         rsurface.modeltvector3f = rsurface.array_modeltvector3f;
3645                         rsurface.modelnormal3f = rsurface.array_modelnormal3f;
3646                         Mod_Alias_GetMesh_Vertices(model, rsurface.frameblend, rsurface.array_modelvertex3f, rsurface.array_modelnormal3f, rsurface.array_modelsvector3f, rsurface.array_modeltvector3f);
3647                 }
3648                 else if (wantnormals)
3649                 {
3650                         rsurface.modelvertex3f = rsurface.array_modelvertex3f;
3651                         rsurface.modelsvector3f = NULL;
3652                         rsurface.modeltvector3f = NULL;
3653                         rsurface.modelnormal3f = rsurface.array_modelnormal3f;
3654                         Mod_Alias_GetMesh_Vertices(model, rsurface.frameblend, rsurface.array_modelvertex3f, rsurface.array_modelnormal3f, NULL, NULL);
3655                 }
3656                 else
3657                 {
3658                         rsurface.modelvertex3f = rsurface.array_modelvertex3f;
3659                         rsurface.modelsvector3f = NULL;
3660                         rsurface.modeltvector3f = NULL;
3661                         rsurface.modelnormal3f = NULL;
3662                         Mod_Alias_GetMesh_Vertices(model, rsurface.frameblend, rsurface.array_modelvertex3f, NULL, NULL, NULL);
3663                 }
3664                 rsurface.modelvertex3f_bufferobject = 0;
3665                 rsurface.modelvertex3f_bufferoffset = 0;
3666                 rsurface.modelsvector3f_bufferobject = 0;
3667                 rsurface.modelsvector3f_bufferoffset = 0;
3668                 rsurface.modeltvector3f_bufferobject = 0;
3669                 rsurface.modeltvector3f_bufferoffset = 0;
3670                 rsurface.modelnormal3f_bufferobject = 0;
3671                 rsurface.modelnormal3f_bufferoffset = 0;
3672                 rsurface.generatedvertex = true;
3673         }
3674         else
3675         {
3676                 rsurface.modelvertex3f  = model->surfmesh.data_vertex3f;
3677                 rsurface.modelvertex3f_bufferobject = model->surfmesh.vbo;
3678                 rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f;
3679                 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
3680                 rsurface.modelsvector3f_bufferobject = model->surfmesh.vbo;
3681                 rsurface.modelsvector3f_bufferoffset = model->surfmesh.vbooffset_svector3f;
3682                 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
3683                 rsurface.modeltvector3f_bufferobject = model->surfmesh.vbo;
3684                 rsurface.modeltvector3f_bufferoffset = model->surfmesh.vbooffset_tvector3f;
3685                 rsurface.modelnormal3f  = model->surfmesh.data_normal3f;
3686                 rsurface.modelnormal3f_bufferobject = model->surfmesh.vbo;
3687                 rsurface.modelnormal3f_bufferoffset = model->surfmesh.vbooffset_normal3f;
3688                 rsurface.generatedvertex = false;
3689         }
3690         rsurface.modellightmapcolor4f  = model->surfmesh.data_lightmapcolor4f;
3691         rsurface.modellightmapcolor4f_bufferobject = model->surfmesh.vbo;
3692         rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.vbooffset_lightmapcolor4f;
3693         rsurface.modeltexcoordtexture2f  = model->surfmesh.data_texcoordtexture2f;
3694         rsurface.modeltexcoordtexture2f_bufferobject = model->surfmesh.vbo;
3695         rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.vbooffset_texcoordtexture2f;
3696         rsurface.modeltexcoordlightmap2f  = model->surfmesh.data_texcoordlightmap2f;
3697         rsurface.modeltexcoordlightmap2f_bufferobject = model->surfmesh.vbo;
3698         rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f;
3699         rsurface.modelelement3i = model->surfmesh.data_element3i;
3700         rsurface.modelelement3i_bufferobject = model->surfmesh.ebo;
3701         rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
3702         rsurface.modelnum_vertices = model->surfmesh.num_vertices;
3703         rsurface.modelnum_triangles = model->surfmesh.num_triangles;
3704         rsurface.modelsurfaces = model->data_surfaces;
3705         rsurface.vertex3f  = rsurface.modelvertex3f;
3706         rsurface.vertex3f_bufferobject = rsurface.modelvertex3f_bufferobject;
3707         rsurface.vertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
3708         rsurface.svector3f = rsurface.modelsvector3f;
3709         rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject;
3710         rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
3711         rsurface.tvector3f = rsurface.modeltvector3f;
3712         rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject;
3713         rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
3714         rsurface.normal3f  = rsurface.modelnormal3f;
3715         rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject;
3716         rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
3717         rsurface.texcoordtexture2f = rsurface.modeltexcoordtexture2f;
3718 }
3719
3720 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
3721 void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generatetangents, int texturenumsurfaces, msurface_t **texturesurfacelist)
3722 {
3723         int deformindex;
3724         int texturesurfaceindex;
3725         int i, j;
3726         float amplitude;
3727         float animpos;
3728         float scale;
3729         const float *v1, *in_tc;
3730         float *out_tc;
3731         float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
3732         float waveparms[4];
3733         q3shaderinfo_deform_t *deform;
3734         // 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
3735         if (rsurface.generatedvertex)
3736         {
3737                 if (rsurface.texture->tcgen.tcgen == Q3TCGEN_ENVIRONMENT)
3738                         generatenormals = true;
3739                 for (i = 0;i < Q3MAXDEFORMS;i++)
3740                 {
3741                         if (rsurface.texture->deforms[i].deform == Q3DEFORM_AUTOSPRITE)
3742                         {
3743                                 generatetangents = true;
3744                                 generatenormals = true;
3745                         }
3746                         if (rsurface.texture->deforms[i].deform != Q3DEFORM_NONE)
3747                                 generatenormals = true;
3748                 }
3749                 if (generatenormals && !rsurface.modelnormal3f)
3750                 {
3751                         rsurface.normal3f = rsurface.modelnormal3f = rsurface.array_modelnormal3f;
3752                         rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject = 0;
3753                         rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset = 0;
3754                         Mod_BuildNormals(0, rsurface.modelnum_vertices, rsurface.modelnum_triangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.array_modelnormal3f, r_smoothnormals_areaweighting.integer);
3755                 }
3756                 if (generatetangents && !rsurface.modelsvector3f)
3757                 {
3758                         rsurface.svector3f = rsurface.modelsvector3f = rsurface.array_modelsvector3f;
3759                         rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject = 0;
3760                         rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset = 0;
3761                         rsurface.tvector3f = rsurface.modeltvector3f = rsurface.array_modeltvector3f;
3762                         rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject = 0;
3763                         rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset = 0;
3764                         Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnum_vertices, rsurface.modelnum_triangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.array_modelsvector3f, rsurface.array_modeltvector3f, r_smoothnormals_areaweighting.integer);
3765                 }
3766         }
3767         rsurface.vertex3f  = rsurface.modelvertex3f;
3768         rsurface.vertex3f_bufferobject = rsurface.modelvertex3f_bufferobject;
3769         rsurface.vertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
3770         rsurface.svector3f = rsurface.modelsvector3f;
3771         rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject;
3772         rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
3773         rsurface.tvector3f = rsurface.modeltvector3f;
3774         rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject;
3775         rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
3776         rsurface.normal3f  = rsurface.modelnormal3f;
3777         rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject;
3778         rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
3779         // if vertices are deformed (sprite flares and things in maps, possibly
3780         // water waves, bulges and other deformations), generate them into
3781         // rsurface.deform* arrays from whatever the rsurface.* arrays point to
3782         // (may be static model data or generated data for an animated model, or
3783         //  the previous deform pass)
3784         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform;deformindex++, deform++)
3785         {
3786                 switch (deform->deform)
3787                 {
3788                 default:
3789                 case Q3DEFORM_PROJECTIONSHADOW:
3790                 case Q3DEFORM_TEXT0:
3791                 case Q3DEFORM_TEXT1:
3792                 case Q3DEFORM_TEXT2:
3793                 case Q3DEFORM_TEXT3:
3794                 case Q3DEFORM_TEXT4:
3795                 case Q3DEFORM_TEXT5:
3796                 case Q3DEFORM_TEXT6:
3797                 case Q3DEFORM_TEXT7:
3798                 case Q3DEFORM_NONE:
3799                         break;
3800                 case Q3DEFORM_AUTOSPRITE:
3801                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.forward, newforward);
3802                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.right, newright);
3803                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.up, newup);
3804                         VectorNormalize(newforward);
3805                         VectorNormalize(newright);
3806                         VectorNormalize(newup);
3807                         // make deformed versions of only the model vertices used by the specified surfaces
3808                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
3809                         {
3810                                 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
3811                                 // a single autosprite surface can contain multiple sprites...
3812                                 for (j = 0;j < surface->num_vertices - 3;j += 4)
3813                                 {
3814                                         VectorClear(center);
3815                                         for (i = 0;i < 4;i++)
3816                                                 VectorAdd(center, (rsurface.vertex3f + 3 * surface->num_firstvertex) + (j+i) * 3, center);
3817                                         VectorScale(center, 0.25f, center);
3818                                         VectorCopy((rsurface.normal3f  + 3 * surface->num_firstvertex) + j*3, forward);
3819                                         VectorCopy((rsurface.svector3f + 3 * surface->num_firstvertex) + j*3, right);
3820                                         VectorCopy((rsurface.tvector3f + 3 * surface->num_firstvertex) + j*3, up);
3821                                         for (i = 0;i < 4;i++)
3822                                         {
3823                                                 VectorSubtract((rsurface.vertex3f + 3 * surface->num_firstvertex) + (j+i)*3, center, v);
3824                                                 VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.array_deformedvertex3f + (surface->num_firstvertex+i+j) * 3);
3825                                         }
3826                                 }
3827                                 Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformednormal3f, r_smoothnormals_areaweighting.integer);
3828                                 Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modeltexcoordtexture2f, rsurface.array_deformednormal3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformedsvector3f, rsurface.array_deformedtvector3f, r_smoothnormals_areaweighting.integer);
3829                         }
3830                         rsurface.vertex3f = rsurface.array_deformedvertex3f;
3831                         rsurface.vertex3f_bufferobject = 0;
3832                         rsurface.vertex3f_bufferoffset = 0;
3833                         rsurface.svector3f = rsurface.array_deformedsvector3f;
3834                         rsurface.svector3f_bufferobject = 0;
3835                         rsurface.svector3f_bufferoffset = 0;
3836                         rsurface.tvector3f = rsurface.array_deformedtvector3f;
3837                         rsurface.tvector3f_bufferobject = 0;
3838                         rsurface.tvector3f_bufferoffset = 0;
3839                         rsurface.normal3f = rsurface.array_deformednormal3f;
3840                         rsurface.normal3f_bufferobject = 0;
3841                         rsurface.normal3f_bufferoffset = 0;
3842                         break;
3843                 case Q3DEFORM_AUTOSPRITE2:
3844                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.forward, newforward);
3845                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.right, newright);
3846                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.up, newup);
3847                         VectorNormalize(newforward);
3848                         VectorNormalize(newright);
3849                         VectorNormalize(newup);
3850                         // make deformed versions of only the model vertices used by the specified surfaces
3851                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
3852                         {
3853                                 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
3854                                 const float *v1, *v2;
3855                                 vec3_t start, end;
3856                                 float f, l;
3857                                 struct
3858                                 {
3859                                         float length2;
3860                                         const float *v1;
3861                                         const float *v2;
3862                                 }
3863                                 shortest[2];
3864                                 memset(shortest, 0, sizeof(shortest));
3865                                 // a single autosprite surface can contain multiple sprites...
3866                                 for (j = 0;j < surface->num_vertices - 3;j += 4)
3867                                 {
3868                                         VectorClear(center);
3869                                         for (i = 0;i < 4;i++)
3870                                                 VectorAdd(center, (rsurface.vertex3f + 3 * surface->num_firstvertex) + (j+i) * 3, center);
3871                                         VectorScale(center, 0.25f, center);
3872                                         // find the two shortest edges, then use them to define the
3873                                         // axis vectors for rotating around the central axis
3874                                         for (i = 0;i < 6;i++)
3875                                         {
3876                                                 v1 = rsurface.vertex3f + 3 * (surface->num_firstvertex + quadedges[i][0]);
3877                                                 v2 = rsurface.vertex3f + 3 * (surface->num_firstvertex + quadedges[i][1]);
3878 #if 0
3879                                                 Debug_PolygonBegin(NULL, 0, false, 0);
3880                                                 Debug_PolygonVertex(v1[0], v1[1], v1[2], 0, 0, 1, 0, 0, 1);
3881                                                 Debug_PolygonVertex((v1[0] + v2[0]) * 0.5f + rsurface.normal3f[3 * (surface->num_firstvertex + j)+0] * 4, (v1[1] + v2[1]) * 0.5f + rsurface.normal3f[3 * (surface->num_firstvertex + j)+1], (v1[2] + v2[2]) * 0.5f + rsurface.normal3f[3 * (surface->num_firstvertex + j)+2], 0, 0, 1, 1, 0, 1);
3882                                                 Debug_PolygonVertex(v2[0], v2[1], v2[2], 0, 0, 1, 0, 0, 1);
3883                                                 Debug_PolygonEnd();
3884 #endif
3885                                                 l = VectorDistance2(v1, v2);
3886                                                 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
3887                                                 if (v1[2] != v2[2])
3888                                                         l += (1.0f / 1024.0f);
3889                                                 if (shortest[0].length2 > l || i == 0)
3890                                                 {
3891                                                         shortest[1] = shortest[0];
3892                                                         shortest[0].length2 = l;
3893                                                         shortest[0].v1 = v1;
3894                                                         shortest[0].v2 = v2;
3895                                                 }
3896                                                 else if (shortest[1].length2 > l || i == 1)
3897                                                 {
3898                                                         shortest[1].length2 = l;
3899                                                         shortest[1].v1 = v1;
3900                                                         shortest[1].v2 = v2;
3901                                                 }
3902                                         }
3903                                         VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
3904                                         VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
3905 #if 0
3906                                         Debug_PolygonBegin(NULL, 0, false, 0);
3907                                         Debug_PolygonVertex(start[0], start[1], start[2], 0, 0, 1, 1, 0, 1);
3908                                         Debug_PolygonVertex(center[0] + rsurface.normal3f[3 * (surface->num_firstvertex + j)+0] * 4, center[1] + rsurface.normal3f[3 * (surface->num_firstvertex + j)+1] * 4, center[2] + rsurface.normal3f[3 * (surface->num_firstvertex + j)+2] * 4, 0, 0, 0, 1, 0, 1);
3909                                         Debug_PolygonVertex(end[0], end[1], end[2], 0, 0, 0, 1, 1, 1);
3910                                         Debug_PolygonEnd();
3911 #endif
3912                                         // this calculates the right vector from the shortest edge
3913                                         // and the up vector from the edge midpoints
3914                                         VectorSubtract(shortest[0].v1, shortest[0].v2, right);
3915                                         VectorNormalize(right);
3916                                         VectorSubtract(end, start, up);
3917                                         VectorNormalize(up);
3918                                         // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
3919                                         //VectorSubtract(rsurface.modelorg, center, forward);
3920                                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.forward, forward);
3921                                         VectorNegate(forward, forward);
3922                                         VectorReflect(forward, 0, up, forward);
3923                                         VectorNormalize(forward);
3924                                         CrossProduct(up, forward, newright);
3925                                         VectorNormalize(newright);
3926 #if 0
3927                                         Debug_PolygonBegin(NULL, 0, false, 0);
3928                                         Debug_PolygonVertex(center[0] + rsurface.normal3f[3 * (surface->num_firstvertex + j)+0] * 8, center[1] + rsurface.normal3f[3 * (surface->num_firstvertex + j)+1] * 8, center[2] + rsurface.normal3f[3 * (surface->num_firstvertex + j)+2] * 8, 0, 0, 1, 0, 0, 1);
3929                                         Debug_PolygonVertex(center[0] + right[0] * 8, center[1] + right[1] * 8, center[2] + right[2] * 8, 0, 0, 0, 1, 0, 1);
3930                                         Debug_PolygonVertex(center[0] + up   [0] * 8, center[1] + up   [1] * 8, center[2] + up   [2] * 8, 0, 0, 0, 0, 1, 1);
3931                                         Debug_PolygonEnd();
3932 #endif
3933 #if 0
3934                                         Debug_PolygonBegin(NULL, 0, false, 0);
3935                                         Debug_PolygonVertex(center[0] + forward [0] * 8, center[1] + forward [1] * 8, center[2] + forward [2] * 8, 0, 0, 1, 0, 0, 1);
3936                                         Debug_PolygonVertex(center[0] + newright[0] * 8, center[1] + newright[1] * 8, center[2] + newright[2] * 8, 0, 0, 0, 1, 0, 1);
3937                                         Debug_PolygonVertex(center[0] + up      [0] * 8, center[1] + up      [1] * 8, center[2] + up      [2] * 8, 0, 0, 0, 0, 1, 1);
3938                                         Debug_PolygonEnd();
3939 #endif
3940                                         // rotate the quad around the up axis vector, this is made
3941                                         // especially easy by the fact we know the quad is flat,
3942                                         // so we only have to subtract the center position and
3943                                         // measure distance along the right vector, and then
3944                                         // multiply that by the newright vector and add back the
3945                                         // center position
3946                                         // we also need to subtract the old position to undo the
3947                                         // displacement from the center, which we do with a
3948                                         // DotProduct, the subtraction/addition of center is also
3949                                         // optimized into DotProducts here
3950                                         l = DotProduct(right, center);
3951                                         for (i = 0;i < 4;i++)
3952                                         {
3953                                                 v1 = rsurface.vertex3f + 3 * (surface->num_firstvertex + j + i);
3954                                                 f = DotProduct(right, v1) - l;
3955                                                 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.array_deformedvertex3f + (surface->num_firstvertex+i+j) * 3);
3956                                         }
3957                                 }
3958                                 Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformednormal3f, r_smoothnormals_areaweighting.integer);
3959                                 Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modeltexcoordtexture2f, rsurface.array_deformednormal3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformedsvector3f, rsurface.array_deformedtvector3f, r_smoothnormals_areaweighting.integer);
3960                         }
3961                         rsurface.vertex3f = rsurface.array_deformedvertex3f;
3962                         rsurface.vertex3f_bufferobject = 0;
3963                         rsurface.vertex3f_bufferoffset = 0;
3964                         rsurface.svector3f = rsurface.array_deformedsvector3f;
3965                         rsurface.svector3f_bufferobject = 0;
3966                         rsurface.svector3f_bufferoffset = 0;
3967                         rsurface.tvector3f = rsurface.array_deformedtvector3f;
3968                         rsurface.tvector3f_bufferobject = 0;
3969                         rsurface.tvector3f_bufferoffset = 0;
3970                         rsurface.normal3f = rsurface.array_deformednormal3f;
3971                         rsurface.normal3f_bufferobject = 0;
3972                         rsurface.normal3f_bufferoffset = 0;
3973                         break;
3974                 case Q3DEFORM_NORMAL:
3975                         // deform the normals to make reflections wavey
3976                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
3977                         {
3978                                 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
3979                                 for (j = 0;j < surface->num_vertices;j++)
3980                                 {
3981                                         float vertex[3];
3982                                         float *normal = (rsurface.array_deformednormal3f  + 3 * surface->num_firstvertex) + j*3;
3983                                         VectorScale((rsurface.vertex3f  + 3 * surface->num_firstvertex) + j*3, 0.98f, vertex);
3984                                         VectorCopy((rsurface.normal3f  + 3 * surface->num_firstvertex) + j*3, normal);
3985                                         normal[0] += deform->parms[0] * noise4f(      vertex[0], vertex[1], vertex[2], r_refdef.time * deform->parms[1]);
3986                                         normal[1] += deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], r_refdef.time * deform->parms[1]);
3987                                         normal[2] += deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], r_refdef.time * deform->parms[1]);
3988                                         VectorNormalize(normal);
3989                                 }
3990                                 Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modeltexcoordtexture2f, rsurface.array_deformednormal3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformedsvector3f, rsurface.array_deformedtvector3f, r_smoothnormals_areaweighting.integer);
3991                         }
3992                         rsurface.svector3f = rsurface.array_deformedsvector3f;
3993                         rsurface.svector3f_bufferobject = 0;
3994                         rsurface.svector3f_bufferoffset = 0;
3995                         rsurface.tvector3f = rsurface.array_deformedtvector3f;
3996                         rsurface.tvector3f_bufferobject = 0;
3997                         rsurface.tvector3f_bufferoffset = 0;
3998                         rsurface.normal3f = rsurface.array_deformednormal3f;
3999                         rsurface.normal3f_bufferobject = 0;
4000                         rsurface.normal3f_bufferoffset = 0;
4001                         break;
4002                 case Q3DEFORM_WAVE:
4003                         // deform vertex array to make wavey water and flags and such
4004                         waveparms[0] = deform->waveparms[0];
4005                         waveparms[1] = deform->waveparms[1];
4006                         waveparms[2] = deform->waveparms[2];
4007                         waveparms[3] = deform->waveparms[3];
4008                         // this is how a divisor of vertex influence on deformation
4009                         animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
4010                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
4011                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4012                         {
4013                                 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4014                                 for (j = 0;j < surface->num_vertices;j++)
4015                                 {
4016                                         float *vertex = (rsurface.array_deformedvertex3f  + 3 * surface->num_firstvertex) + j*3;
4017                                         VectorCopy((rsurface.vertex3f  + 3 * surface->num_firstvertex) + j*3, vertex);
4018                                         // if the wavefunc depends on time, evaluate it per-vertex
4019                                         if (waveparms[3])
4020                                         {
4021                                                 waveparms[2] = deform->waveparms[2] + (vertex[0] + vertex[1] + vertex[2]) * animpos;
4022                                                 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
4023                                         }
4024                                         VectorMA(vertex, scale, (rsurface.normal3f  + 3 * surface->num_firstvertex) + j*3, vertex);
4025                                 }
4026                         }
4027                         rsurface.vertex3f = rsurface.array_deformedvertex3f;
4028                         rsurface.vertex3f_bufferobject = 0;
4029                         rsurface.vertex3f_bufferoffset = 0;
4030                         break;
4031                 case Q3DEFORM_BULGE:
4032                         // deform vertex array to make the surface have moving bulges
4033                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4034                         {
4035                                 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4036                                 for (j = 0;j < surface->num_vertices;j++)
4037                                 {
4038                                         scale = sin((rsurface.modeltexcoordtexture2f[2 * (surface->num_firstvertex + j)] * deform->parms[0] + r_refdef.time * deform->parms[2])) * deform->parms[1];
4039                                         VectorMA(rsurface.vertex3f + 3 * (surface->num_firstvertex + j), scale, rsurface.normal3f + 3 * (surface->num_firstvertex + j), rsurface.array_deformedvertex3f + 3 * (surface->num_firstvertex + j));
4040                                 }
4041                         }
4042                         rsurface.vertex3f = rsurface.array_deformedvertex3f;
4043                         rsurface.vertex3f_bufferobject = 0;
4044                         rsurface.vertex3f_bufferoffset = 0;
4045                         break;
4046                 case Q3DEFORM_MOVE:
4047                         // deform vertex array
4048                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
4049                         VectorScale(deform->parms, scale, waveparms);
4050                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4051                         {
4052                                 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4053                                 for (j = 0;j < surface->num_vertices;j++)
4054                                         VectorAdd(rsurface.vertex3f + 3 * (surface->num_firstvertex + j), waveparms, rsurface.array_deformedvertex3f + 3 * (surface->num_firstvertex + j));
4055                         }
4056                         rsurface.vertex3f = rsurface.array_deformedvertex3f;
4057                         rsurface.vertex3f_bufferobject = 0;
4058                         rsurface.vertex3f_bufferoffset = 0;
4059                         break;
4060                 }
4061         }
4062         // generate texcoords based on the chosen texcoord source
4063         switch(rsurface.texture->tcgen.tcgen)
4064         {
4065         default:
4066         case Q3TCGEN_TEXTURE:
4067                 rsurface.texcoordtexture2f               = rsurface.modeltexcoordtexture2f;
4068                 rsurface.texcoordtexture2f_bufferobject  = rsurface.modeltexcoordtexture2f_bufferobject;
4069                 rsurface.texcoordtexture2f_bufferoffset  = rsurface.modeltexcoordtexture2f_bufferoffset;
4070                 break;
4071         case Q3TCGEN_LIGHTMAP:
4072                 rsurface.texcoordtexture2f               = rsurface.modeltexcoordlightmap2f;
4073                 rsurface.texcoordtexture2f_bufferobject  = rsurface.modeltexcoordlightmap2f_bufferobject;
4074                 rsurface.texcoordtexture2f_bufferoffset  = rsurface.modeltexcoordlightmap2f_bufferoffset;
4075                 break;
4076         case Q3TCGEN_VECTOR:
4077                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4078                 {
4079                         const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4080                         for (j = 0, v1 = rsurface.modelvertex3f + 3 * surface->num_firstvertex, out_tc = rsurface.array_generatedtexcoordtexture2f + 2 * surface->num_firstvertex;j < surface->num_vertices;j++, v1 += 3, out_tc += 2)
4081                         {
4082                                 out_tc[0] = DotProduct(v1, rsurface.texture->tcgen.parms);
4083                                 out_tc[1] = DotProduct(v1, rsurface.texture->tcgen.parms + 3);
4084                         }
4085                 }
4086                 rsurface.texcoordtexture2f               = rsurface.array_generatedtexcoordtexture2f;
4087                 rsurface.texcoordtexture2f_bufferobject  = 0;
4088                 rsurface.texcoordtexture2f_bufferoffset  = 0;
4089                 break;
4090         case Q3TCGEN_ENVIRONMENT:
4091                 // make environment reflections using a spheremap
4092                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4093                 {
4094                         const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4095                         const float *vertex = rsurface.modelvertex3f + 3 * surface->num_firstvertex;
4096                         const float *normal = rsurface.modelnormal3f + 3 * surface->num_firstvertex;
4097                         float *out_tc = rsurface.array_generatedtexcoordtexture2f + 2 * surface->num_firstvertex;
4098                         for (j = 0;j < surface->num_vertices;j++, vertex += 3, normal += 3, out_tc += 2)
4099                         {
4100                                 float l, d, eyedir[3];
4101                                 VectorSubtract(rsurface.modelorg, vertex, eyedir);
4102                                 l = 0.5f / VectorLength(eyedir);
4103                                 d = DotProduct(normal, eyedir)*2;
4104                                 out_tc[0] = 0.5f + (normal[1]*d - eyedir[1])*l;
4105                                 out_tc[1] = 0.5f - (normal[2]*d - eyedir[2])*l;
4106                         }
4107                 }
4108                 rsurface.texcoordtexture2f               = rsurface.array_generatedtexcoordtexture2f;
4109                 rsurface.texcoordtexture2f_bufferobject  = 0;
4110                 rsurface.texcoordtexture2f_bufferoffset  = 0;
4111                 break;
4112         }
4113         // the only tcmod that needs software vertex processing is turbulent, so
4114         // check for it here and apply the changes if needed
4115         // and we only support that as the first one
4116         // (handling a mixture of turbulent and other tcmods would be problematic
4117         //  without punting it entirely to a software path)
4118         if (rsurface.texture->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
4119         {
4120                 amplitude = rsurface.texture->tcmods[0].parms[1];
4121                 animpos = rsurface.texture->tcmods[0].parms[2] + r_refdef.time * rsurface.texture->tcmods[0].parms[3];
4122                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4123                 {
4124                         const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4125                         for (j = 0, v1 = rsurface.modelvertex3f + 3 * surface->num_firstvertex, in_tc = rsurface.texcoordtexture2f + 2 * surface->num_firstvertex, out_tc = rsurface.array_generatedtexcoordtexture2f + 2 * surface->num_firstvertex;j < surface->num_vertices;j++, v1 += 3, in_tc += 2, out_tc += 2)
4126                         {
4127                                 out_tc[0] = in_tc[0] + amplitude * sin(((v1[0] + v1[2]) * 1.0 / 1024.0f + animpos) * M_PI * 2);
4128                                 out_tc[1] = in_tc[1] + amplitude * sin(((v1[1]        ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
4129                         }
4130                 }
4131                 rsurface.texcoordtexture2f               = rsurface.array_generatedtexcoordtexture2f;
4132                 rsurface.texcoordtexture2f_bufferobject  = 0;
4133                 rsurface.texcoordtexture2f_bufferoffset  = 0;
4134         }
4135         rsurface.texcoordlightmap2f              = rsurface.modeltexcoordlightmap2f;
4136         rsurface.texcoordlightmap2f_bufferobject = rsurface.modeltexcoordlightmap2f_bufferobject;
4137         rsurface.texcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
4138         R_Mesh_VertexPointer(rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
4139 }
4140
4141 void RSurf_DrawBatch_Simple(int texturenumsurfaces, msurface_t **texturesurfacelist)
4142 {
4143         int i, j;
4144         const msurface_t *surface = texturesurfacelist[0];
4145         const msurface_t *surface2;
4146         int firstvertex;
4147         int endvertex;
4148         int numvertices;
4149         int numtriangles;
4150         // TODO: lock all array ranges before render, rather than on each surface
4151         if (texturenumsurfaces == 1)
4152         {
4153                 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
4154                 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface.modelelement3i + 3 * surface->num_firsttriangle), rsurface.modelelement3i_bufferobject, (sizeof(int[3]) * surface->num_firsttriangle));
4155         }
4156         else if (r_batchmode.integer == 2)
4157         {
4158                 #define MAXBATCHTRIANGLES 4096
4159                 int batchtriangles = 0;
4160                 int batchelements[MAXBATCHTRIANGLES*3];
4161                 for (i = 0;i < texturenumsurfaces;i = j)
4162                 {
4163                         surface = texturesurfacelist[i];
4164                         j = i + 1;
4165                         if (surface->num_triangles > MAXBATCHTRIANGLES)
4166                         {
4167                                 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface.modelelement3i + 3 * surface->num_firsttriangle), rsurface.modelelement3i_bufferobject, (sizeof(int[3]) * surface->num_firsttriangle));
4168                                 continue;
4169                         }
4170                         memcpy(batchelements, rsurface.modelelement3i + 3 * surface->num_firsttriangle, surface->num_triangles * sizeof(int[3]));
4171                         batchtriangles = surface->num_triangles;
4172                         firstvertex = surface->num_firstvertex;
4173                         endvertex = surface->num_firstvertex + surface->num_vertices;
4174                         for (;j < texturenumsurfaces;j++)
4175                         {
4176                                 surface2 = texturesurfacelist[j];
4177                                 if (batchtriangles + surface2->num_triangles > MAXBATCHTRIANGLES)
4178                                         break;
4179                                 memcpy(batchelements + batchtriangles * 3, rsurface.modelelement3i + 3 * surface2->num_firsttriangle, surface2->num_triangles * sizeof(int[3]));
4180                                 batchtriangles += surface2->num_triangles;
4181                                 firstvertex = min(firstvertex, surface2->num_firstvertex);
4182                                 endvertex = max(endvertex, surface2->num_firstvertex + surface2->num_vertices);
4183                         }
4184                         surface2 = texturesurfacelist[j-1];
4185                         numvertices = endvertex - firstvertex;
4186                         R_Mesh_Draw(firstvertex, numvertices, batchtriangles, batchelements, 0, 0);
4187                 }
4188         }
4189         else if (r_batchmode.integer == 1)
4190         {
4191                 for (i = 0;i < texturenumsurfaces;i = j)
4192                 {
4193                         surface = texturesurfacelist[i];
4194                         for (j = i + 1, surface2 = surface + 1;j < texturenumsurfaces;j++, surface2++)
4195                                 if (texturesurfacelist[j] != surface2)
4196                                         break;
4197                         surface2 = texturesurfacelist[j-1];
4198                         numvertices = surface2->num_firstvertex + surface2->num_vertices - surface->num_firstvertex;
4199                         numtriangles = surface2->num_firsttriangle + surface2->num_triangles - surface->num_firsttriangle;
4200                         GL_LockArrays(surface->num_firstvertex, numvertices);
4201                         R_Mesh_Draw(surface->num_firstvertex, numvertices, numtriangles, (rsurface.modelelement3i + 3 * surface->num_firsttriangle), rsurface.modelelement3i_bufferobject, (sizeof(int[3]) * surface->num_firsttriangle));
4202                 }
4203         }
4204         else
4205         {
4206                 for (i = 0;i < texturenumsurfaces;i++)
4207                 {
4208                         surface = texturesurfacelist[i];
4209                         GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
4210                         R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface.modelelement3i + 3 * surface->num_firsttriangle), rsurface.modelelement3i_bufferobject, (sizeof(int[3]) * surface->num_firsttriangle));
4211                 }
4212         }
4213 }
4214
4215 static void RSurf_DrawBatch_WithLightmapSwitching(int texturenumsurfaces, msurface_t **texturesurfacelist, int lightmaptexunit, int deluxemaptexunit)
4216 {
4217         int i;
4218         int j;
4219         const msurface_t *surface = texturesurfacelist[0];
4220         const msurface_t *surface2;
4221         int firstvertex;
4222         int endvertex;
4223         int numvertices;
4224         int numtriangles;
4225         // TODO: lock all array ranges before render, rather than on each surface
4226         if (texturenumsurfaces == 1)
4227         {
4228                 R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
4229                 if (deluxemaptexunit >= 0)
4230                         R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
4231                 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
4232                 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface.modelelement3i + 3 * surface->num_firsttriangle), rsurface.modelelement3i_bufferobject, (sizeof(int[3]) * surface->num_firsttriangle));
4233         }
4234         else if (r_batchmode.integer == 2)
4235         {
4236                 #define MAXBATCHTRIANGLES 4096
4237                 int batchtriangles = 0;
4238                 int batchelements[MAXBATCHTRIANGLES*3];
4239                 for (i = 0;i < texturenumsurfaces;i = j)
4240                 {
4241                         surface = texturesurfacelist[i];
4242                         R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
4243                         if (deluxemaptexunit >= 0)
4244                                 R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
4245                         j = i + 1;
4246                         if (surface->num_triangles > MAXBATCHTRIANGLES)
4247                         {
4248                                 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface.modelelement3i + 3 * surface->num_firsttriangle), rsurface.modelelement3i_bufferobject, (sizeof(int[3]) * surface->num_firsttriangle));
4249                                 continue;
4250                         }
4251                         memcpy(batchelements, rsurface.modelelement3i + 3 * surface->num_firsttriangle, surface->num_triangles * sizeof(int[3]));
4252                         batchtriangles = surface->num_triangles;
4253                         firstvertex = surface->num_firstvertex;
4254                         endvertex = surface->num_firstvertex + surface->num_vertices;
4255                         for (;j < texturenumsurfaces;j++)
4256                         {
4257                                 surface2 = texturesurfacelist[j];
4258                                 if (surface2->lightmaptexture != surface->lightmaptexture || batchtriangles + surface2->num_triangles > MAXBATCHTRIANGLES)
4259                                         break;
4260                                 memcpy(batchelements + batchtriangles * 3, rsurface.modelelement3i + 3 * surface2->num_firsttriangle, surface2->num_triangles * sizeof(int[3]));
4261                                 batchtriangles += surface2->num_triangles;
4262                                 firstvertex = min(firstvertex, surface2->num_firstvertex);
4263                                 endvertex = max(endvertex, surface2->num_firstvertex + surface2->num_vertices);
4264                         }
4265                         surface2 = texturesurfacelist[j-1];
4266                         numvertices = endvertex - firstvertex;
4267                         R_Mesh_Draw(firstvertex, numvertices, batchtriangles, batchelements, 0, 0);
4268                 }
4269         }
4270         else if (r_batchmode.integer == 1)
4271         {
4272 #if 0
4273                 Con_Printf("%s batch sizes ignoring lightmap:", rsurface.texture->name);
4274                 for (i = 0;i < texturenumsurfaces;i = j)
4275                 {
4276                         surface = texturesurfacelist[i];
4277                         for (j = i + 1, surface2 = surface + 1;j < texturenumsurfaces;j++, surface2++)
4278                                 if (texturesurfacelist[j] != surface2)
4279                                         break;
4280                         Con_Printf(" %i", j - i);
4281                 }
4282                 Con_Printf("\n");
4283                 Con_Printf("%s batch sizes honoring lightmap:", rsurface.texture->name);
4284 #endif
4285                 for (i = 0;i < texturenumsurfaces;i = j)
4286                 {
4287                         surface = texturesurfacelist[i];
4288                         R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
4289                         if (deluxemaptexunit >= 0)
4290                                 R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
4291                         for (j = i + 1, surface2 = surface + 1;j < texturenumsurfaces;j++, surface2++)
4292                                 if (texturesurfacelist[j] != surface2 || texturesurfacelist[j]->lightmaptexture != surface->lightmaptexture)
4293                                         break;
4294 #if 0
4295                         Con_Printf(" %i", j - i);
4296 #endif
4297                         surface2 = texturesurfacelist[j-1];
4298                         numvertices = surface2->num_firstvertex + surface2->num_vertices - surface->num_firstvertex;
4299                         numtriangles = surface2->num_firsttriangle + surface2->num_triangles - surface->num_firsttriangle;
4300                         GL_LockArrays(surface->num_firstvertex, numvertices);
4301                         R_Mesh_Draw(surface->num_firstvertex, numvertices, numtriangles, (rsurface.modelelement3i + 3 * surface->num_firsttriangle), rsurface.modelelement3i_bufferobject, (sizeof(int[3]) * surface->num_firsttriangle));
4302                 }
4303 #if 0
4304                 Con_Printf("\n");
4305 #endif
4306         }
4307         else
4308         {
4309                 for (i = 0;i < texturenumsurfaces;i++)
4310                 {
4311                         surface = texturesurfacelist[i];
4312                         R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
4313                         if (deluxemaptexunit >= 0)
4314                                 R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
4315                         GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
4316                         R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface.modelelement3i + 3 * surface->num_firsttriangle), rsurface.modelelement3i_bufferobject, (sizeof(int[3]) * surface->num_firsttriangle));
4317                 }
4318         }
4319 }
4320
4321 static void RSurf_DrawBatch_ShowSurfaces(int texturenumsurfaces, msurface_t **texturesurfacelist)
4322 {
4323         int j;
4324         int texturesurfaceindex;
4325         if (r_showsurfaces.integer == 2)
4326         {
4327                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4328                 {
4329                         const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4330                         for (j = 0;j < surface->num_triangles;j++)
4331                         {
4332                                 float f = ((j + surface->num_firsttriangle) & 31) * (1.0f / 31.0f) * r_view.colorscale;
4333                                 GL_Color(f, f, f, 1);
4334                                 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, 1, (rsurface.modelelement3i + 3 * (j + surface->num_firsttriangle)), rsurface.modelelement3i_bufferobject, (sizeof(int[3]) * (j + surface->num_firsttriangle)));
4335                         }
4336                 }
4337         }
4338         else
4339         {
4340                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4341                 {
4342                         const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4343                         int k = (int)(((size_t)surface) / sizeof(msurface_t));
4344                         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);
4345                         GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
4346                         R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface.modelelement3i + 3 * surface->num_firsttriangle), rsurface.modelelement3i_bufferobject, (sizeof(int[3]) * surface->num_firsttriangle));
4347                 }
4348         }
4349 }
4350
4351 static void RSurf_DrawBatch_GL11_ApplyFog(int texturenumsurfaces, msurface_t **texturesurfacelist)
4352 {
4353         int texturesurfaceindex;
4354         int i;
4355         float f;
4356         float *v, *c, *c2;
4357         if (rsurface.lightmapcolor4f)
4358         {
4359                 // generate color arrays for the surfaces in this list
4360                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4361                 {
4362                         const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4363                         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)
4364                         {
4365                                 f = FogPoint_Model(v);
4366                                 c2[0] = c[0] * f;
4367                                 c2[1] = c[1] * f;
4368                                 c2[2] = c[2] * f;
4369                                 c2[3] = c[3];
4370                         }
4371                 }
4372         }
4373         else
4374         {
4375                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4376                 {
4377                         const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4378                         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)
4379                         {
4380                                 f = FogPoint_Model(v);
4381                                 c2[0] = f;
4382                                 c2[1] = f;
4383                                 c2[2] = f;
4384                                 c2[3] = 1;
4385                         }
4386                 }
4387         }
4388         rsurface.lightmapcolor4f = rsurface.array_color4f;
4389         rsurface.lightmapcolor4f_bufferobject = 0;
4390         rsurface.lightmapcolor4f_bufferoffset = 0;
4391 }
4392
4393 static void RSurf_DrawBatch_GL11_ApplyColor(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a)
4394 {
4395         int texturesurfaceindex;
4396         int i;
4397         float *c, *c2;
4398         if (!rsurface.lightmapcolor4f)
4399                 return;
4400         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4401         {
4402                 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4403                 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)
4404                 {
4405                         c2[0] = c[0] * r;
4406                         c2[1] = c[1] * g;
4407                         c2[2] = c[2] * b;
4408                         c2[3] = c[3] * a;
4409                 }
4410         }
4411         rsurface.lightmapcolor4f = rsurface.array_color4f;
4412         rsurface.lightmapcolor4f_bufferobject = 0;
4413         rsurface.lightmapcolor4f_bufferoffset = 0;
4414 }
4415
4416 static void RSurf_DrawBatch_GL11_Lightmap(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
4417 {
4418         // TODO: optimize
4419         rsurface.lightmapcolor4f = NULL;
4420         rsurface.lightmapcolor4f_bufferobject = 0;
4421         rsurface.lightmapcolor4f_bufferoffset = 0;
4422         if (applyfog)   RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
4423         if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
4424         R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
4425         GL_Color(r, g, b, a);
4426         RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist, 0, -1);
4427 }
4428
4429 static void RSurf_DrawBatch_GL11_Unlit(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
4430 {
4431         // TODO: optimize applyfog && applycolor case
4432         // just apply fog if necessary, and tint the fog color array if necessary
4433         rsurface.lightmapcolor4f = NULL;
4434         rsurface.lightmapcolor4f_bufferobject = 0;
4435         rsurface.lightmapcolor4f_bufferoffset = 0;
4436         if (applyfog)   RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
4437         if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
4438         R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
4439         GL_Color(r, g, b, a);
4440         RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
4441 }
4442
4443 static void RSurf_DrawBatch_GL11_VertexColor(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
4444 {
4445         int texturesurfaceindex;
4446         int i;
4447         float *c;
4448         // TODO: optimize
4449         if (texturesurfacelist[0]->lightmapinfo && texturesurfacelist[0]->lightmapinfo->stainsamples)
4450         {
4451                 // generate color arrays for the surfaces in this list
4452                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4453                 {
4454                         const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4455                         for (i = 0, c = rsurface.array_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
4456                         {
4457                                 if (surface->lightmapinfo->samples)
4458                                 {
4459                                         const unsigned char *lm = surface->lightmapinfo->samples + (rsurface.modellightmapoffsets + surface->num_firstvertex)[i];
4460                                         float scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[0]] * (1.0f / 32768.0f);
4461                                         VectorScale(lm, scale, c);
4462                                         if (surface->lightmapinfo->styles[1] != 255)
4463                                         {
4464                                                 int size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
4465                                                 lm += size3;
4466                                                 scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[1]] * (1.0f / 32768.0f);
4467                                                 VectorMA(c, scale, lm, c);
4468                                                 if (surface->lightmapinfo->styles[2] != 255)
4469                                                 {
4470                                                         lm += size3;
4471                                                         scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[2]] * (1.0f / 32768.0f);
4472                                                         VectorMA(c, scale, lm, c);
4473                                                         if (surface->lightmapinfo->styles[3] != 255)
4474                                                         {
4475                                                                 lm += size3;
4476                                                                 scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[3]] * (1.0f / 32768.0f);
4477                                                                 VectorMA(c, scale, lm, c);
4478                                                         }
4479                                                 }
4480                                         }
4481                                 }
4482                                 else
4483                                         VectorClear(c);
4484                                 c[3] = 1;
4485                         }
4486                 }
4487                 rsurface.lightmapcolor4f = rsurface.array_color4f;
4488                 rsurface.lightmapcolor4f_bufferobject = 0;
4489                 rsurface.lightmapcolor4f_bufferoffset = 0;
4490         }
4491         else
4492         {
4493                 rsurface.lightmapcolor4f = rsurface.modellightmapcolor4f;
4494                 rsurface.lightmapcolor4f_bufferobject = rsurface.modellightmapcolor4f_bufferobject;
4495                 rsurface.lightmapcolor4f_bufferoffset = rsurface.modellightmapcolor4f_bufferoffset;
4496         }
4497         if (applyfog)   RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
4498         if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
4499         R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
4500         GL_Color(r, g, b, a);
4501         RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
4502 }
4503
4504 static void RSurf_DrawBatch_GL11_VertexShade(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
4505 {
4506         int texturesurfaceindex;
4507         int i;
4508         float f;
4509         float *v, *c, *c2;
4510         vec3_t ambientcolor;
4511         vec3_t diffusecolor;
4512         vec3_t lightdir;
4513         // TODO: optimize
4514         // model lighting
4515         VectorCopy(rsurface.modellight_lightdir, lightdir);
4516         ambientcolor[0] = rsurface.modellight_ambient[0] * r * 0.5f;
4517         ambientcolor[1] = rsurface.modellight_ambient[1] * g * 0.5f;
4518         ambientcolor[2] = rsurface.modellight_ambient[2] * b * 0.5f;
4519         diffusecolor[0] = rsurface.modellight_diffuse[0] * r * 0.5f;
4520         diffusecolor[1] = rsurface.modellight_diffuse[1] * g * 0.5f;
4521         diffusecolor[2] = rsurface.modellight_diffuse[2] * b * 0.5f;
4522         if (VectorLength2(diffusecolor) > 0)
4523         {
4524                 // generate color arrays for the surfaces in this list
4525                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4526                 {
4527                         const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4528                         int numverts = surface->num_vertices;
4529                         v = rsurface.vertex3f + 3 * surface->num_firstvertex;
4530                         c2 = rsurface.normal3f + 3 * surface->num_firstvertex;
4531                         c = rsurface.array_color4f + 4 * surface->num_firstvertex;
4532                         // q3-style directional shading
4533                         for (i = 0;i < numverts;i++, v += 3, c2 += 3, c += 4)
4534                         {
4535                                 if ((f = DotProduct(c2, lightdir)) > 0)
4536                                         VectorMA(ambientcolor, f, diffusecolor, c);
4537                                 else
4538                                         VectorCopy(ambientcolor, c);
4539                                 c[3] = a;
4540                         }
4541                 }
4542                 r = 1;
4543                 g = 1;
4544                 b = 1;
4545                 a = 1;
4546                 applycolor = false;
4547                 rsurface.lightmapcolor4f = rsurface.array_color4f;
4548                 rsurface.lightmapcolor4f_bufferobject = 0;
4549                 rsurface.lightmapcolor4f_bufferoffset = 0;
4550         }
4551         else
4552         {
4553                 r = ambientcolor[0];
4554                 g = ambientcolor[1];
4555                 b = ambientcolor[2];
4556                 rsurface.lightmapcolor4f = NULL;
4557                 rsurface.lightmapcolor4f_bufferobject = 0;
4558                 rsurface.lightmapcolor4f_bufferoffset = 0;
4559         }
4560         if (applyfog)   RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
4561         if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
4562         R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
4563         GL_Color(r, g, b, a);
4564         RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
4565 }
4566
4567 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, msurface_t **texturesurfacelist)
4568 {
4569         GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
4570         GL_PolygonOffset(rsurface.texture->currentpolygonfactor, rsurface.texture->currentpolygonoffset);
4571         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
4572         GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
4573         if (rsurface.mode != RSURFMODE_SHOWSURFACES)
4574         {
4575                 rsurface.mode = RSURFMODE_SHOWSURFACES;
4576                 GL_DepthMask(true);
4577                 GL_BlendFunc(GL_ONE, GL_ZERO);
4578                 R_Mesh_ColorPointer(NULL, 0, 0);
4579                 R_Mesh_ResetTextureState();
4580         }
4581         RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
4582         RSurf_DrawBatch_ShowSurfaces(texturenumsurfaces, texturesurfacelist);
4583 }
4584
4585 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, msurface_t **texturesurfacelist)
4586 {
4587         // transparent sky would be ridiculous
4588         if ((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED))
4589                 return;
4590         if (rsurface.mode != RSURFMODE_SKY)
4591         {
4592                 if (rsurface.mode == RSURFMODE_GLSL)
4593                 {
4594                         qglUseProgramObjectARB(0);CHECKGLERROR
4595                 }
4596                 rsurface.mode = RSURFMODE_SKY;
4597         }
4598         if (skyrendernow)
4599         {
4600                 skyrendernow = false;
4601                 R_Sky();
4602                 // restore entity matrix
4603                 R_Mesh_Matrix(&rsurface.matrix);
4604         }
4605         GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
4606         GL_PolygonOffset(rsurface.texture->currentpolygonfactor, rsurface.texture->currentpolygonoffset);
4607         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
4608         GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
4609         GL_DepthMask(true);
4610         // LordHavoc: HalfLife maps have freaky skypolys so don't use
4611         // skymasking on them, and Quake3 never did sky masking (unlike
4612         // software Quake and software Quake2), so disable the sky masking
4613         // in Quake3 maps as it causes problems with q3map2 sky tricks,
4614         // and skymasking also looks very bad when noclipping outside the
4615         // level, so don't use it then either.
4616         if (r_refdef.worldmodel && r_refdef.worldmodel->type == mod_brushq1 && r_q1bsp_skymasking.integer && !r_viewcache.world_novis)
4617         {
4618                 GL_Color(r_refdef.fogcolor[0] * r_view.colorscale, r_refdef.fogcolor[1] * r_view.colorscale, r_refdef.fogcolor[2] * r_view.colorscale, 1);
4619                 R_Mesh_ColorPointer(NULL, 0, 0);
4620                 R_Mesh_ResetTextureState();
4621                 if (skyrendermasked)
4622                 {
4623                         // depth-only (masking)
4624                         GL_ColorMask(0,0,0,0);
4625                         // just to make sure that braindead drivers don't draw
4626                         // anything despite that colormask...
4627                         GL_BlendFunc(GL_ZERO, GL_ONE);
4628                 }
4629                 else
4630                 {
4631                         // fog sky
4632                         GL_BlendFunc(GL_ONE, GL_ZERO);
4633                 }
4634                 RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
4635                 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
4636                 if (skyrendermasked)
4637                         GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
4638         }
4639 }
4640
4641 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, msurface_t **texturesurfacelist)
4642 {
4643         if (rsurface.mode != RSURFMODE_GLSL)
4644         {
4645                 rsurface.mode = RSURFMODE_GLSL;
4646                 R_Mesh_ResetTextureState();
4647         }
4648
4649         R_SetupSurfaceShader(vec3_origin, rsurface.lightmode == 2, 1, 1, rsurface.texture->specularscale);
4650         if (!r_glsl_permutation)
4651                 return;
4652
4653         if (rsurface.lightmode == 2)
4654                 RSurf_PrepareVerticesForBatch(true, r_glsl_permutation->loc_Texture_Normal >= 0, texturenumsurfaces, texturesurfacelist);
4655         else
4656                 RSurf_PrepareVerticesForBatch(r_glsl_permutation->loc_Texture_Normal >= 0, r_glsl_permutation->loc_Texture_Normal >= 0, texturenumsurfaces, texturesurfacelist);
4657         R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
4658         R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
4659         R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
4660         R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
4661         R_Mesh_TexCoordPointer(4, 2, rsurface.modeltexcoordlightmap2f, rsurface.modeltexcoordlightmap2f_bufferobject, rsurface.modeltexcoordlightmap2f_bufferoffset);
4662
4663         GL_Color(rsurface.texture->currentlayers[0].color[0], rsurface.texture->currentlayers[0].color[1], rsurface.texture->currentlayers[0].color[2], rsurface.texture->currentlayers[0].color[3]);
4664         if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
4665         {
4666                 R_Mesh_TexBind(7, R_GetTexture(r_texture_white));
4667                 if (r_glsl_permutation->loc_Texture_Deluxemap >= 0)
4668                         R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
4669                 R_Mesh_ColorPointer(NULL, 0, 0);
4670         }
4671         else if (rsurface.uselightmaptexture)
4672         {
4673                 R_Mesh_TexBind(7, R_GetTexture(texturesurfacelist[0]->lightmaptexture));
4674                 if (r_glsl_permutation->loc_Texture_Deluxemap >= 0)
4675                         R_Mesh_TexBind(8, R_GetTexture(texturesurfacelist[0]->deluxemaptexture));
4676                 R_Mesh_ColorPointer(NULL, 0, 0);
4677         }
4678         else
4679         {
4680                 R_Mesh_TexBind(7, R_GetTexture(r_texture_white));
4681                 if (r_glsl_permutation->loc_Texture_Deluxemap >= 0)
4682                         R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
4683                 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
4684         }
4685
4686         if (rsurface.uselightmaptexture && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT))
4687                 RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist, 7, r_glsl_permutation->loc_Texture_Deluxemap >= 0 ? 8 : -1);
4688         else
4689                 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
4690         if (rsurface.texture->backgroundnumskinframes && !(rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED))
4691         {
4692         }
4693 }
4694
4695 static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, msurface_t **texturesurfacelist)
4696 {
4697         // OpenGL 1.3 path - anything not completely ancient
4698         int texturesurfaceindex;
4699         qboolean applycolor;
4700         qboolean applyfog;
4701         rmeshstate_t m;
4702         int layerindex;
4703         const texturelayer_t *layer;
4704         if (rsurface.mode != RSURFMODE_MULTIPASS)
4705                 rsurface.mode = RSURFMODE_MULTIPASS;
4706         RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist);
4707         for (layerindex = 0, layer = rsurface.texture->currentlayers;layerindex < rsurface.texture->currentnumlayers;layerindex++, layer++)
4708         {
4709                 vec4_t layercolor;
4710                 int layertexrgbscale;
4711                 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
4712                 {
4713                         if (layerindex == 0)
4714                                 GL_AlphaTest(true);
4715                         else
4716                         {
4717                                 GL_AlphaTest(false);
4718                                 qglDepthFunc(GL_EQUAL);CHECKGLERROR
4719                         }
4720                 }
4721                 GL_DepthMask(layer->depthmask);
4722                 GL_BlendFunc(layer->blendfunc1, layer->blendfunc2);
4723                 if ((layer->color[0] > 2 || layer->color[1] > 2 || layer->color[2] > 2) && (gl_combine.integer || layer->depthmask))
4724                 {
4725                         layertexrgbscale = 4;
4726                         VectorScale(layer->color, 0.25f, layercolor);
4727                 }
4728                 else if ((layer->color[0] > 1 || layer->color[1] > 1 || layer->color[2] > 1) && (gl_combine.integer || layer->depthmask))
4729                 {
4730                         layertexrgbscale = 2;
4731                         VectorScale(layer->color, 0.5f, layercolor);
4732                 }
4733                 else
4734                 {
4735                         layertexrgbscale = 1;
4736                         VectorScale(layer->color, 1.0f, layercolor);
4737                 }
4738                 layercolor[3] = layer->color[3];
4739                 applycolor = layercolor[0] != 1 || layercolor[1] != 1 || layercolor[2] != 1 || layercolor[3] != 1;
4740                 R_Mesh_ColorPointer(NULL, 0, 0);
4741                 applyfog = (layer->flags & TEXTURELAYERFLAG_FOGDARKEN) != 0;
4742                 switch (layer->type)
4743                 {
4744                 case TEXTURELAYERTYPE_LITTEXTURE:
4745                         memset(&m, 0, sizeof(m));
4746                         m.tex[0] = R_GetTexture(r_texture_white);
4747                         m.pointer_texcoord[0] = rsurface.modeltexcoordlightmap2f;
4748                         m.pointer_texcoord_bufferobject[0] = rsurface.modeltexcoordlightmap2f_bufferobject;
4749                         m.pointer_texcoord_bufferoffset[0] = rsurface.modeltexcoordlightmap2f_bufferoffset;
4750                         m.tex[1] = R_GetTexture(layer->texture);
4751                         m.texmatrix[1] = layer->texmatrix;
4752                         m.texrgbscale[1] = layertexrgbscale;
4753                         m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
4754                         m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
4755                         m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
4756                         R_Mesh_TextureState(&m);
4757                         if (rsurface.lightmode == 2)
4758                                 RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
4759                         else if (rsurface.uselightmaptexture)
4760                                 RSurf_DrawBatch_GL11_Lightmap(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
4761                         else
4762                                 RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
4763                         break;
4764                 case TEXTURELAYERTYPE_TEXTURE:
4765                         memset(&m, 0, sizeof(m));
4766                         m.tex[0] = R_GetTexture(layer->texture);
4767                         m.texmatrix[0] = layer->texmatrix;
4768                         m.texrgbscale[0] = layertexrgbscale;
4769                         m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
4770                         m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
4771                         m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
4772                         R_Mesh_TextureState(&m);
4773                         RSurf_DrawBatch_GL11_Unlit(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
4774                         break;
4775                 case TEXTURELAYERTYPE_FOG:
4776                         memset(&m, 0, sizeof(m));
4777                         m.texrgbscale[0] = layertexrgbscale;
4778                         if (layer->texture)
4779                         {
4780                                 m.tex[0] = R_GetTexture(layer->texture);
4781                                 m.texmatrix[0] = layer->texmatrix;
4782                                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
4783                                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
4784                                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
4785                         }
4786                         R_Mesh_TextureState(&m);
4787                         // generate a color array for the fog pass
4788                         R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
4789                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4790                         {
4791                                 int i;
4792                                 float f, *v, *c;
4793                                 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4794                                 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)
4795                                 {
4796                                         f = 1 - FogPoint_Model(v);
4797                                         c[0] = layercolor[0];
4798                                         c[1] = layercolor[1];
4799                                         c[2] = layercolor[2];
4800                                         c[3] = f * layercolor[3];
4801                                 }
4802                         }
4803                         RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
4804                         break;
4805                 default:
4806                         Con_Printf("R_DrawTextureSurfaceList: unknown layer type %i\n", layer->type);
4807                 }
4808                 GL_LockArrays(0, 0);
4809         }
4810         CHECKGLERROR
4811         if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
4812         {
4813                 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
4814                 GL_AlphaTest(false);
4815         }
4816 }
4817
4818 static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, msurface_t **texturesurfacelist)
4819 {
4820         // OpenGL 1.1 - crusty old voodoo path
4821         int texturesurfaceindex;
4822         qboolean applyfog;
4823         rmeshstate_t m;
4824         int layerindex;
4825         const texturelayer_t *layer;
4826         if (rsurface.mode != RSURFMODE_MULTIPASS)
4827                 rsurface.mode = RSURFMODE_MULTIPASS;
4828         RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist);
4829         for (layerindex = 0, layer = rsurface.texture->currentlayers;layerindex < rsurface.texture->currentnumlayers;layerindex++, layer++)
4830         {
4831                 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
4832                 {
4833                         if (layerindex == 0)
4834                                 GL_AlphaTest(true);
4835                         else
4836                         {
4837                                 GL_AlphaTest(false);
4838                                 qglDepthFunc(GL_EQUAL);CHECKGLERROR
4839                         }
4840                 }
4841                 GL_DepthMask(layer->depthmask);
4842                 GL_BlendFunc(layer->blendfunc1, layer->blendfunc2);
4843                 R_Mesh_ColorPointer(NULL, 0, 0);
4844                 applyfog = (layer->flags & TEXTURELAYERFLAG_FOGDARKEN) != 0;
4845                 switch (layer->type)
4846                 {
4847                 case TEXTURELAYERTYPE_LITTEXTURE:
4848                         if (layer->blendfunc1 == GL_ONE && layer->blendfunc2 == GL_ZERO)
4849                         {
4850                                 // two-pass lit texture with 2x rgbscale
4851                                 // first the lightmap pass
4852                                 memset(&m, 0, sizeof(m));
4853                                 m.tex[0] = R_GetTexture(r_texture_white);
4854                                 m.pointer_texcoord[0] = rsurface.modeltexcoordlightmap2f;
4855                                 m.pointer_texcoord_bufferobject[0] = rsurface.modeltexcoordlightmap2f_bufferobject;
4856                                 m.pointer_texcoord_bufferoffset[0] = rsurface.modeltexcoordlightmap2f_bufferoffset;
4857                                 R_Mesh_TextureState(&m);
4858                                 if (rsurface.lightmode == 2)
4859                                         RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
4860                                 else if (rsurface.uselightmaptexture)
4861                                         RSurf_DrawBatch_GL11_Lightmap(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
4862                                 else
4863                                         RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
4864                                 GL_LockArrays(0, 0);
4865                                 // then apply the texture to it
4866                                 GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
4867                                 memset(&m, 0, sizeof(m));
4868                                 m.tex[0] = R_GetTexture(layer->texture);
4869                                 m.texmatrix[0] = layer->texmatrix;
4870                                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
4871                                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
4872                                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
4873                                 R_Mesh_TextureState(&m);
4874                                 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);
4875                         }
4876                         else
4877                         {
4878                                 // single pass vertex-lighting-only texture with 1x rgbscale and transparency support
4879                                 memset(&m, 0, sizeof(m));
4880                                 m.tex[0] = R_GetTexture(layer->texture);
4881                                 m.texmatrix[0] = layer->texmatrix;
4882                                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
4883                                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
4884                                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
4885                                 R_Mesh_TextureState(&m);
4886                                 if (rsurface.lightmode == 2)
4887                                         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);
4888                                 else
4889                                         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);
4890                         }
4891                         break;
4892                 case TEXTURELAYERTYPE_TEXTURE:
4893                         // singletexture unlit texture with transparency support
4894                         memset(&m, 0, sizeof(m));
4895                         m.tex[0] = R_GetTexture(layer->texture);
4896                         m.texmatrix[0] = layer->texmatrix;
4897                         m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
4898                         m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
4899                         m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
4900                         R_Mesh_TextureState(&m);
4901                         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);
4902                         break;
4903                 case TEXTURELAYERTYPE_FOG:
4904                         // singletexture fogging
4905                         R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
4906                         if (layer->texture)
4907                         {
4908                                 memset(&m, 0, sizeof(m));
4909                                 m.tex[0] = R_GetTexture(layer->texture);
4910                                 m.texmatrix[0] = layer->texmatrix;
4911                                 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
4912                                 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
4913                                 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
4914                                 R_Mesh_TextureState(&m);
4915                         }
4916                         else
4917                                 R_Mesh_ResetTextureState();
4918                         // generate a color array for the fog pass
4919                         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4920                         {
4921                                 int i;
4922                                 float f, *v, *c;
4923                                 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4924                                 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)
4925                                 {
4926                                         f = 1 - FogPoint_Model(v);
4927                                         c[0] = layer->color[0];
4928                                         c[1] = layer->color[1];
4929                                         c[2] = layer->color[2];
4930                                         c[3] = f * layer->color[3];
4931                                 }
4932                         }
4933                         RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
4934                         break;
4935                 default:
4936                         Con_Printf("R_DrawTextureSurfaceList: unknown layer type %i\n", layer->type);
4937                 }
4938                 GL_LockArrays(0, 0);
4939         }
4940         CHECKGLERROR
4941         if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
4942         {
4943                 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
4944                 GL_AlphaTest(false);
4945         }
4946 }
4947
4948 static void R_DrawTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly)
4949 {
4950         if (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW)
4951                 return;
4952         rsurface.rtlight = NULL;
4953         CHECKGLERROR
4954         if (depthonly)
4955         {
4956                 if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
4957                         return;
4958                 if (rsurface.mode != RSURFMODE_MULTIPASS)
4959                         rsurface.mode = RSURFMODE_MULTIPASS;
4960                 if (r_depthfirst.integer == 3)
4961                 {
4962                         int i = (int)(texturesurfacelist[0] - rsurface.modelsurfaces);
4963                         GL_Color(((i >> 6) & 7) / 7.0f, ((i >> 3) & 7) / 7.0f, (i & 7) / 7.0f,1);
4964                 }
4965                 else
4966                 {
4967                         GL_ColorMask(0,0,0,0);
4968                         GL_Color(1,1,1,1);
4969                 }
4970                 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
4971                 GL_PolygonOffset(rsurface.texture->currentpolygonfactor, rsurface.texture->currentpolygonoffset);
4972                 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
4973                 GL_DepthTest(true);
4974                 GL_BlendFunc(GL_ONE, GL_ZERO);
4975                 GL_DepthMask(true);
4976                 GL_AlphaTest(false);
4977                 R_Mesh_ColorPointer(NULL, 0, 0);
4978                 R_Mesh_ResetTextureState();
4979                 RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
4980                 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
4981                 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
4982                 r_refdef.stats.entities_surfaces += texturenumsurfaces;
4983         }
4984         else if (r_depthfirst.integer == 3)
4985                 return;
4986         else if (r_showsurfaces.integer)
4987         {
4988                 if (rsurface.mode != RSURFMODE_MULTIPASS)
4989                         rsurface.mode = RSURFMODE_MULTIPASS;
4990                 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
4991                 GL_PolygonOffset(rsurface.texture->currentpolygonfactor, rsurface.texture->currentpolygonoffset);
4992                 GL_DepthTest(true);
4993                 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
4994                 GL_BlendFunc(GL_ONE, GL_ZERO);
4995                 GL_DepthMask(writedepth);
4996                 GL_Color(1,1,1,1);
4997                 GL_AlphaTest(false);
4998                 R_Mesh_ColorPointer(NULL, 0, 0);
4999                 R_Mesh_ResetTextureState();
5000                 RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
5001                 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist);
5002                 r_refdef.stats.entities_surfaces += texturenumsurfaces;
5003         }
5004         else if (gl_lightmaps.integer)
5005         {
5006                 rmeshstate_t m;
5007                 if (rsurface.mode != RSURFMODE_MULTIPASS)
5008                         rsurface.mode = RSURFMODE_MULTIPASS;
5009                 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
5010                 GL_DepthTest(true);
5011                 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
5012                 GL_BlendFunc(GL_ONE, GL_ZERO);
5013                 GL_DepthMask(writedepth);
5014                 GL_Color(1,1,1,1);
5015                 GL_AlphaTest(false);
5016                 R_Mesh_ColorPointer(NULL, 0, 0);
5017                 memset(&m, 0, sizeof(m));
5018                 m.tex[0] = R_GetTexture(r_texture_white);
5019                 m.pointer_texcoord[0] = rsurface.modeltexcoordlightmap2f;
5020                 m.pointer_texcoord_bufferobject[0] = rsurface.modeltexcoordlightmap2f_bufferobject;
5021                 m.pointer_texcoord_bufferoffset[0] = rsurface.modeltexcoordlightmap2f_bufferoffset;
5022                 R_Mesh_TextureState(&m);
5023                 RSurf_PrepareVerticesForBatch(rsurface.lightmode == 2, false, texturenumsurfaces, texturesurfacelist);
5024                 if (rsurface.lightmode == 2)
5025                         RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
5026                 else if (rsurface.uselightmaptexture)
5027                         RSurf_DrawBatch_GL11_Lightmap(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
5028                 else
5029                         RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
5030                 r_refdef.stats.entities_surfaces += texturenumsurfaces;
5031         }
5032         else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY)
5033         {
5034                 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
5035                 r_refdef.stats.entities_surfaces += texturenumsurfaces;
5036         }
5037         else if (rsurface.texture->currentnumlayers)
5038         {
5039                 // write depth for anything we skipped on the depth-only pass earlier
5040                 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
5041                         writedepth = true;
5042                 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
5043                 GL_PolygonOffset(rsurface.texture->currentpolygonfactor, rsurface.texture->currentpolygonoffset);
5044                 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
5045                 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
5046                 GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
5047                 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
5048                 GL_AlphaTest((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
5049                 // use lightmode 0 (fullbright or lightmap) or 2 (model lighting)
5050                 rsurface.lightmode = ((rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || rsurface.modeltexcoordlightmap2f != NULL) ? 0 : 2;
5051                 if (r_glsl.integer && gl_support_fragment_shader)
5052                         R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist);
5053                 else if (gl_combine.integer && r_textureunits.integer >= 2)
5054                         R_DrawTextureSurfaceList_GL13(texturenumsurfaces, texturesurfacelist);
5055                 else
5056                         R_DrawTextureSurfaceList_GL11(texturenumsurfaces, texturesurfacelist);
5057                 r_refdef.stats.entities_surfaces += texturenumsurfaces;
5058         }
5059         CHECKGLERROR
5060         GL_LockArrays(0, 0);
5061 }
5062
5063 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5064 {
5065         int i, j;
5066         int texturenumsurfaces, endsurface;
5067         texture_t *texture;
5068         msurface_t *surface;
5069         msurface_t *texturesurfacelist[1024];
5070
5071         // if the model is static it doesn't matter what value we give for
5072         // wantnormals and wanttangents, so this logic uses only rules applicable
5073         // to a model, knowing that they are meaningless otherwise
5074         if (ent == r_refdef.worldentity)
5075                 RSurf_ActiveWorldEntity();
5076         else if ((ent->effects & EF_FULLBRIGHT) || r_showsurfaces.integer || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f))
5077                 RSurf_ActiveModelEntity(ent, false, false);
5078         else
5079                 RSurf_ActiveModelEntity(ent, true, r_glsl.integer && gl_support_fragment_shader);
5080
5081         for (i = 0;i < numsurfaces;i = j)
5082         {
5083                 j = i + 1;
5084                 surface = rsurface.modelsurfaces + surfacelist[i];
5085                 texture = surface->texture;
5086                 R_UpdateTextureInfo(ent, texture);
5087                 rsurface.texture = texture->currentframe;
5088                 rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
5089                 // scan ahead until we find a different texture
5090                 endsurface = min(i + 1024, numsurfaces);
5091                 texturenumsurfaces = 0;
5092                 texturesurfacelist[texturenumsurfaces++] = surface;
5093                 for (;j < endsurface;j++)
5094                 {
5095                         surface = rsurface.modelsurfaces + surfacelist[j];
5096                         if (texture != surface->texture || rsurface.uselightmaptexture != (surface->lightmaptexture != NULL))
5097                                 break;
5098                         texturesurfacelist[texturenumsurfaces++] = surface;
5099                 }
5100                 // render the range of surfaces
5101                 R_DrawTextureSurfaceList(texturenumsurfaces, texturesurfacelist, true, false);
5102         }
5103
5104         RSurf_CleanUp();
5105 }
5106
5107 void R_QueueSurfaceList(entity_render_t *ent, int numsurfaces, msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly)
5108 {
5109         int i, j;
5110         vec3_t tempcenter, center;
5111         texture_t *texture;
5112         // break the surface list down into batches by texture and use of lightmapping
5113         for (i = 0;i < numsurfaces;i = j)
5114         {
5115                 j = i + 1;
5116                 // texture is the base texture pointer, rsurface.texture is the
5117                 // current frame/skin the texture is directing us to use (for example
5118                 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
5119                 // use skin 1 instead)
5120                 texture = surfacelist[i]->texture;
5121                 rsurface.texture = texture->currentframe;
5122                 rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
5123                 if (!(rsurface.texture->currentmaterialflags & flagsmask))
5124                 {
5125                         // if this texture is not the kind we want, skip ahead to the next one
5126                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
5127                                 ;
5128                         continue;
5129                 }
5130                 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
5131                 {
5132                         // transparent surfaces get pushed off into the transparent queue
5133                         const msurface_t *surface = surfacelist[i];
5134                         if (depthonly)
5135                                 continue;
5136                         tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
5137                         tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
5138                         tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
5139                         Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
5140                         R_MeshQueue_AddTransparent(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_view.origin : center, R_DrawSurface_TransparentCallback, ent, surface - rsurface.modelsurfaces, rsurface.rtlight);
5141                 }
5142                 else
5143                 {
5144                         // simply scan ahead until we find a different texture or lightmap state
5145                         for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.uselightmaptexture == (surfacelist[j]->lightmaptexture != NULL);j++)
5146                                 ;
5147                         // render the range of surfaces
5148                         R_DrawTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly);
5149                 }
5150         }
5151 }
5152
5153 float locboxvertex3f[6*4*3] =
5154 {
5155         1,0,1, 1,0,0, 1,1,0, 1,1,1,
5156         0,1,1, 0,1,0, 0,0,0, 0,0,1,
5157         1,1,1, 1,1,0, 0,1,0, 0,1,1,
5158         0,0,1, 0,0,0, 1,0,0, 1,0,1,
5159         0,0,1, 1,0,1, 1,1,1, 0,1,1,
5160         1,0,0, 0,0,0, 0,1,0, 1,1,0
5161 };
5162
5163 int locboxelement3i[6*2*3] =
5164 {
5165          0, 1, 2, 0, 2, 3,
5166          4, 5, 6, 4, 6, 7,
5167          8, 9,10, 8,10,11,
5168         12,13,14, 12,14,15,
5169         16,17,18, 16,18,19,
5170         20,21,22, 20,22,23
5171 };
5172
5173 void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5174 {
5175         int i, j;
5176         cl_locnode_t *loc = (cl_locnode_t *)ent;
5177         vec3_t mins, size;
5178         float vertex3f[6*4*3];
5179         CHECKGLERROR
5180         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5181         GL_DepthMask(false);
5182         GL_DepthRange(0, 1);
5183         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
5184         GL_DepthTest(true);
5185         GL_CullFace(GL_NONE);
5186         R_Mesh_Matrix(&identitymatrix);
5187
5188         R_Mesh_VertexPointer(vertex3f, 0, 0);
5189         R_Mesh_ColorPointer(NULL, 0, 0);
5190         R_Mesh_ResetTextureState();
5191
5192         i = surfacelist[0];
5193         GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_view.colorscale,
5194                          ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_view.colorscale,
5195                          ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_view.colorscale,
5196                         surfacelist[0] < 0 ? 0.5f : 0.125f);
5197
5198         if (VectorCompare(loc->mins, loc->maxs))
5199         {
5200                 VectorSet(size, 2, 2, 2);
5201                 VectorMA(loc->mins, -0.5f, size, mins);
5202         }
5203         else
5204         {
5205                 VectorCopy(loc->mins, mins);
5206                 VectorSubtract(loc->maxs, loc->mins, size);
5207         }
5208
5209         for (i = 0;i < 6*4*3;)
5210                 for (j = 0;j < 3;j++, i++)
5211                         vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
5212
5213         R_Mesh_Draw(0, 6*4, 6*2, locboxelement3i, 0, 0);
5214 }
5215
5216 void R_DrawLocs(void)
5217 {
5218         int index;
5219         cl_locnode_t *loc, *nearestloc;
5220         vec3_t center;
5221         nearestloc = CL_Locs_FindNearest(cl.movement_origin);
5222         for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
5223         {
5224                 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
5225                 R_MeshQueue_AddTransparent(center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
5226         }
5227 }
5228
5229 void R_DrawCollisionBrushes(entity_render_t *ent)
5230 {
5231         int i;
5232         q3mbrush_t *brush;
5233         msurface_t *surface;
5234         model_t *model = ent->model;
5235         if (!model->brush.num_brushes)
5236                 return;
5237         CHECKGLERROR
5238         R_Mesh_ColorPointer(NULL, 0, 0);
5239         R_Mesh_ResetTextureState();
5240         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
5241         GL_DepthMask(false);
5242         GL_DepthRange(0, 1);
5243         GL_DepthTest(!r_showdisabledepthtest.integer);
5244         GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
5245         for (i = 0, brush = model->brush.data_brushes + model->firstmodelbrush;i < model->nummodelbrushes;i++, brush++)
5246                 if (brush->colbrushf && brush->colbrushf->numtriangles)
5247                         R_DrawCollisionBrush(brush->colbrushf);
5248         for (i = 0, surface = model->data_surfaces + model->firstmodelsurface;i < model->nummodelsurfaces;i++, surface++)
5249                 if (surface->num_collisiontriangles)
5250                         R_DrawCollisionSurface(ent, surface);
5251         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
5252 }
5253
5254 void R_DrawTrianglesAndNormals(entity_render_t *ent, qboolean drawtris, qboolean drawnormals, int flagsmask)
5255 {
5256         int i, j, k, l;
5257         const int *elements;
5258         msurface_t *surface;
5259         model_t *model = ent->model;
5260         vec3_t v;
5261         CHECKGLERROR
5262         GL_DepthRange(0, 1);
5263         GL_DepthTest(!r_showdisabledepthtest.integer);
5264         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
5265         GL_DepthMask(true);
5266         GL_BlendFunc(GL_ONE, GL_ZERO);
5267         R_Mesh_ColorPointer(NULL, 0, 0);
5268         R_Mesh_ResetTextureState();
5269         for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
5270         {
5271                 if (ent == r_refdef.worldentity && !r_viewcache.world_surfacevisible[j])
5272                         continue;
5273                 rsurface.texture = surface->texture->currentframe;
5274                 if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
5275                 {
5276                         RSurf_PrepareVerticesForBatch(true, true, 1, &surface);
5277                         if (drawtris)
5278                         {
5279                                 if (!rsurface.texture->currentlayers->depthmask)
5280                                         GL_Color(r_showtris.value * r_view.colorscale, 0, 0, 1);
5281                                 else if (ent == r_refdef.worldentity)
5282                                         GL_Color(r_showtris.value * r_view.colorscale, r_showtris.value * r_view.colorscale, r_showtris.value * r_view.colorscale, 1);
5283                                 else
5284                                         GL_Color(0, r_showtris.value * r_view.colorscale, 0, 1);
5285                                 elements = (ent->model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);
5286                                 CHECKGLERROR
5287                                 qglBegin(GL_LINES);
5288                                 for (k = 0;k < surface->num_triangles;k++, elements += 3)
5289                                 {
5290 #define GLVERTEXELEMENT(n) qglVertex3f(rsurface.vertex3f[elements[n]*3+0], rsurface.vertex3f[elements[n]*3+1], rsurface.vertex3f[elements[n]*3+2])
5291                                         GLVERTEXELEMENT(0);GLVERTEXELEMENT(1);
5292                                         GLVERTEXELEMENT(1);GLVERTEXELEMENT(2);
5293                                         GLVERTEXELEMENT(2);GLVERTEXELEMENT(0);
5294                                 }
5295                                 qglEnd();
5296                                 CHECKGLERROR
5297                         }
5298                         if (drawnormals)
5299                         {
5300                                 GL_Color(r_shownormals.value * r_view.colorscale, 0, 0, 1);
5301                                 qglBegin(GL_LINES);
5302                                 for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
5303                                 {
5304                                         VectorCopy(rsurface.vertex3f + l * 3, v);
5305                                         qglVertex3f(v[0], v[1], v[2]);
5306                                         VectorMA(v, 8, rsurface.svector3f + l * 3, v);
5307                                         qglVertex3f(v[0], v[1], v[2]);
5308                                 }
5309                                 qglEnd();
5310                                 CHECKGLERROR
5311                                 GL_Color(0, 0, r_shownormals.value * r_view.colorscale, 1);
5312                                 qglBegin(GL_LINES);
5313                                 for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
5314                                 {
5315                                         VectorCopy(rsurface.vertex3f + l * 3, v);
5316                                         qglVertex3f(v[0], v[1], v[2]);
5317                                         VectorMA(v, 8, rsurface.tvector3f + l * 3, v);
5318                                         qglVertex3f(v[0], v[1], v[2]);
5319                                 }
5320                                 qglEnd();
5321                                 CHECKGLERROR
5322                                 GL_Color(0, r_shownormals.value * r_view.colorscale, 0, 1);
5323                                 qglBegin(GL_LINES);
5324                                 for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
5325                                 {
5326                                         VectorCopy(rsurface.vertex3f + l * 3, v);
5327                                         qglVertex3f(v[0], v[1], v[2]);
5328                                         VectorMA(v, 8, rsurface.normal3f + l * 3, v);
5329                                         qglVertex3f(v[0], v[1], v[2]);
5330                                 }
5331                                 qglEnd();
5332                                 CHECKGLERROR
5333                         }
5334                 }
5335         }
5336         rsurface.texture = NULL;
5337 }
5338
5339 extern void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface);
5340 void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean depthonly)
5341 {
5342         int i, j, endj, f, flagsmask;
5343         int counttriangles = 0;
5344         msurface_t *surface, **surfacechain;
5345         texture_t *t;
5346         model_t *model = r_refdef.worldmodel;
5347         const int maxsurfacelist = 1024;
5348         int numsurfacelist = 0;
5349         msurface_t *surfacelist[1024];
5350         if (model == NULL)
5351                 return;
5352
5353         RSurf_ActiveWorldEntity();
5354
5355         // update light styles
5356         if (!skysurfaces && !depthonly && model->brushq1.light_styleupdatechains)
5357         {
5358                 for (i = 0;i < model->brushq1.light_styles;i++)
5359                 {
5360                         if (model->brushq1.light_stylevalue[i] != r_refdef.lightstylevalue[model->brushq1.light_style[i]])
5361                         {
5362                                 model->brushq1.light_stylevalue[i] = r_refdef.lightstylevalue[model->brushq1.light_style[i]];
5363                                 if ((surfacechain = model->brushq1.light_styleupdatechains[i]))
5364                                         for (;(surface = *surfacechain);surfacechain++)
5365                                                 surface->cached_dlight = true;
5366                         }
5367                 }
5368         }
5369
5370         R_UpdateAllTextureInfo(r_refdef.worldentity);
5371         flagsmask = skysurfaces ? MATERIALFLAG_SKY : (MATERIALFLAG_WATER | MATERIALFLAG_WALL);
5372         f = 0;
5373         t = NULL;
5374         rsurface.uselightmaptexture = false;
5375         rsurface.texture = NULL;
5376         numsurfacelist = 0;
5377         j = model->firstmodelsurface;
5378         endj = j + model->nummodelsurfaces;
5379         while (j < endj)
5380         {
5381                 // quickly skip over non-visible surfaces
5382                 for (;j < endj && !r_viewcache.world_surfacevisible[j];j++)
5383                         ;
5384                 // quickly iterate over visible surfaces
5385                 for (;j < endj && r_viewcache.world_surfacevisible[j];j++)
5386                 {
5387                         // process this surface
5388                         surface = model->data_surfaces + j;
5389                         // if this surface fits the criteria, add it to the list
5390                         if (surface->num_triangles)
5391                         {
5392                                 // if lightmap parameters changed, rebuild lightmap texture
5393                                 if (surface->cached_dlight)
5394                                         R_BuildLightMap(r_refdef.worldentity, surface);
5395                                 // add face to draw list
5396                                 surfacelist[numsurfacelist++] = surface;
5397                                 counttriangles += surface->num_triangles;
5398                                 if (numsurfacelist >= maxsurfacelist)
5399                                 {
5400                                         R_QueueSurfaceList(r_refdef.worldentity, numsurfacelist, surfacelist, flagsmask, writedepth, depthonly);
5401                                         numsurfacelist = 0;
5402                                 }
5403                         }
5404                 }
5405         }
5406         if (numsurfacelist)
5407                 R_QueueSurfaceList(r_refdef.worldentity, numsurfacelist, surfacelist, flagsmask, writedepth, depthonly);
5408         r_refdef.stats.entities_triangles += counttriangles;
5409         RSurf_CleanUp();
5410
5411         if (r_showcollisionbrushes.integer && !skysurfaces && !depthonly)
5412                 R_DrawCollisionBrushes(r_refdef.worldentity);
5413
5414         if ((r_showtris.integer || r_shownormals.integer) && !depthonly)
5415                 R_DrawTrianglesAndNormals(r_refdef.worldentity, r_showtris.integer, r_shownormals.integer, flagsmask);
5416 }
5417
5418 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly)
5419 {
5420         int i, f, flagsmask;
5421         int counttriangles = 0;
5422         msurface_t *surface, *endsurface, **surfacechain;
5423         texture_t *t;
5424         model_t *model = ent->model;
5425         const int maxsurfacelist = 1024;
5426         int numsurfacelist = 0;
5427         msurface_t *surfacelist[1024];
5428         if (model == NULL)
5429                 return;
5430
5431         // if the model is static it doesn't matter what value we give for
5432         // wantnormals and wanttangents, so this logic uses only rules applicable
5433         // to a model, knowing that they are meaningless otherwise
5434         if (ent == r_refdef.worldentity)
5435                 RSurf_ActiveWorldEntity();
5436         else if ((ent->effects & EF_FULLBRIGHT) || r_showsurfaces.integer || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f))
5437                 RSurf_ActiveModelEntity(ent, false, false);
5438         else
5439                 RSurf_ActiveModelEntity(ent, true, r_glsl.integer && gl_support_fragment_shader && !depthonly);
5440
5441         // update light styles
5442         if (!skysurfaces && !depthonly && model->brushq1.light_styleupdatechains)
5443         {
5444                 for (i = 0;i < model->brushq1.light_styles;i++)
5445                 {
5446                         if (model->brushq1.light_stylevalue[i] != r_refdef.lightstylevalue[model->brushq1.light_style[i]])
5447                         {
5448                                 model->brushq1.light_stylevalue[i] = r_refdef.lightstylevalue[model->brushq1.light_style[i]];
5449                                 if ((surfacechain = model->brushq1.light_styleupdatechains[i]))
5450                                         for (;(surface = *surfacechain);surfacechain++)
5451                                                 surface->cached_dlight = true;
5452                         }
5453                 }
5454         }
5455
5456         R_UpdateAllTextureInfo(ent);
5457         flagsmask = skysurfaces ? MATERIALFLAG_SKY : (MATERIALFLAG_WATER | MATERIALFLAG_WALL);
5458         f = 0;
5459         t = NULL;
5460         rsurface.uselightmaptexture = false;
5461         rsurface.texture = NULL;
5462         numsurfacelist = 0;
5463         surface = model->data_surfaces + model->firstmodelsurface;
5464         endsurface = surface + model->nummodelsurfaces;
5465         for (;surface < endsurface;surface++)
5466         {
5467                 // if this surface fits the criteria, add it to the list
5468                 if (surface->num_triangles)
5469                 {
5470                         // if lightmap parameters changed, rebuild lightmap texture
5471                         if (surface->cached_dlight)
5472                                 R_BuildLightMap(ent, surface);
5473                         // add face to draw list
5474                         surfacelist[numsurfacelist++] = surface;
5475                         counttriangles += surface->num_triangles;
5476                         if (numsurfacelist >= maxsurfacelist)
5477                         {
5478                                 R_QueueSurfaceList(ent, numsurfacelist, surfacelist, flagsmask, writedepth, depthonly);
5479                                 numsurfacelist = 0;
5480                         }
5481                 }
5482         }
5483         if (numsurfacelist)
5484                 R_QueueSurfaceList(ent, numsurfacelist, surfacelist, flagsmask, writedepth, depthonly);
5485         r_refdef.stats.entities_triangles += counttriangles;
5486         RSurf_CleanUp();
5487
5488         if (r_showcollisionbrushes.integer && !skysurfaces && !depthonly)
5489                 R_DrawCollisionBrushes(ent);
5490
5491         if ((r_showtris.integer || r_shownormals.integer) && !depthonly)
5492                 R_DrawTrianglesAndNormals(ent, r_showtris.integer, r_shownormals.integer, flagsmask);
5493 }