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