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