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