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