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