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