5cd9e3a42ee2b65858b0cbeb9f7add18e6ff1ec2
[xonotic/darkplaces.git] / gl_rmain.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // r_main.c
21
22 #include "quakedef.h"
23 #include "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
36 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"};
37 cvar_t r_nearclip = {0, "r_nearclip", "1", "distance from camera of nearclip plane" };
38 cvar_t r_showbboxes = {0, "r_showbboxes", "0", "shows bounding boxes of server entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
39 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)"};
40 cvar_t r_showtris = {0, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"};
41 cvar_t r_shownormals = {0, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"};
42 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"};
43 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"};
44 cvar_t r_showcollisionbrushes = {0, "r_showcollisionbrushes", "0", "draws collision brushes in quake3 maps (mode 1), mode 2 disables rendering of world (trippy!)"};
45 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"};
46 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"};
47 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"};
48 cvar_t r_drawportals = {0, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"};
49 cvar_t r_drawentities = {0, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"};
50 cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1", "draw your weapon model"};
51 cvar_t r_cullentities_trace = {0, "r_cullentities_trace", "1", "probabistically cull invisible entities"};
52 cvar_t r_cullentities_trace_samples = {0, "r_cullentities_trace_samples", "2", "number of samples to test for entity culling"};
53 cvar_t r_cullentities_trace_enlarge = {0, "r_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
54 cvar_t r_cullentities_trace_delay = {0, "r_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
55 cvar_t r_speeds = {0, "r_speeds","0", "displays rendering statistics and per-subsystem timings"};
56 cvar_t r_fullbright = {0, "r_fullbright","0", "makes map very bright and renders faster"};
57 cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1", "opacity of water polygons"};
58 cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1", "enables dynamic lights (rocket glow and such)"};
59 cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1", "enables glowing pixels in quake textures (changes need r_restart to take effect)"};
60 cvar_t r_shadows = {CVAR_SAVE, "r_shadows", "0", "casts fake stencil shadows from models onto the world (rtlights are unaffected by this)"};
61 cvar_t r_shadows_throwdistance = {CVAR_SAVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"};
62 cvar_t r_q1bsp_skymasking = {0, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
63 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"};
64 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"};
65 cvar_t r_fog_exp2 = {0, "r_fog_exp2", "0", "uses GL_EXP2 fog (as in Nehahra) rather than realistic GL_EXP fog"};
66
67 cvar_t gl_fogenable = {0, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"};
68 cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"};
69 cvar_t gl_fogred = {0, "gl_fogred","0.3", "nehahra fog color red value (for Nehahra compatibility only)"};
70 cvar_t gl_foggreen = {0, "gl_foggreen","0.3", "nehahra fog color green value (for Nehahra compatibility only)"};
71 cvar_t gl_fogblue = {0, "gl_fogblue","0.3", "nehahra fog color blue value (for Nehahra compatibility only)"};
72 cvar_t gl_fogstart = {0, "gl_fogstart", "0", "nehahra fog start distance (for Nehahra compatibility only)"};
73 cvar_t gl_fogend = {0, "gl_fogend","0", "nehahra fog end distance (for Nehahra compatibility only)"};
74 cvar_t gl_skyclip = {0, "gl_skyclip", "4608", "nehahra farclip distance - the real fog end (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_contrastboost = {CVAR_SAVE, "r_glsl_contrastboost", "1", "by how much to multiply the contrast in dark areas (1 is no change)"};
80 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)"};
81 cvar_t r_glsl_offsetmapping = {CVAR_SAVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
82 cvar_t r_glsl_offsetmapping_reliefmapping = {CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
83 cvar_t r_glsl_offsetmapping_scale = {CVAR_SAVE, "r_glsl_offsetmapping_scale", "0.04", "how deep the offset mapping effect is"};
84 cvar_t r_glsl_postprocess = {CVAR_SAVE, "r_glsl_postprocess", "0", "use a GLSL postprocessing shader"};
85 cvar_t r_glsl_postprocess_uservec1 = {CVAR_SAVE, "r_glsl_postprocess_uservec1", "0 0 0 0", "a 4-component vector to pass as uservec1 to the postprocessing shader (only useful if default.glsl has been customized)"};
86 cvar_t r_glsl_postprocess_uservec2 = {CVAR_SAVE, "r_glsl_postprocess_uservec2", "0 0 0 0", "a 4-component vector to pass as uservec2 to the postprocessing shader (only useful if default.glsl has been customized)"};
87 cvar_t r_glsl_postprocess_uservec3 = {CVAR_SAVE, "r_glsl_postprocess_uservec3", "0 0 0 0", "a 4-component vector to pass as uservec3 to the postprocessing shader (only useful if default.glsl has been customized)"};
88 cvar_t r_glsl_postprocess_uservec4 = {CVAR_SAVE, "r_glsl_postprocess_uservec4", "0 0 0 0", "a 4-component vector to pass as uservec4 to the postprocessing shader (only useful if default.glsl has been customized)"};
89 cvar_t r_glsl_usegeneric = {CVAR_SAVE, "r_glsl_usegeneric", "1", "use shaders for rendering simple geometry (rather than conventional fixed-function rendering for this purpose)"};
90
91 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)"};
92 cvar_t r_water_clippingplanebias = {CVAR_SAVE, "r_water_clippingplanebias", "1", "a rather technical setting which avoids black pixels around water edges"};
93 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"};
94 cvar_t r_water_refractdistort = {CVAR_SAVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
95 cvar_t r_water_reflectdistort = {CVAR_SAVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"};
96
97 cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "1", "enables animation smoothing on sprites (requires r_lerpmodels 1)"};
98 cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
99 cvar_t r_lerplightstyles = {CVAR_SAVE, "r_lerplightstyles", "0", "enable animation smoothing on flickering lights"};
100 cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
101
102 cvar_t r_bloom = {CVAR_SAVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"};
103 cvar_t r_bloom_colorscale = {CVAR_SAVE, "r_bloom_colorscale", "1", "how bright the glow is"};
104 cvar_t r_bloom_brighten = {CVAR_SAVE, "r_bloom_brighten", "2", "how bright the glow is, after subtract/power"};
105 cvar_t r_bloom_blur = {CVAR_SAVE, "r_bloom_blur", "4", "how large the glow is"};
106 cvar_t r_bloom_resolution = {CVAR_SAVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"};
107 cvar_t r_bloom_colorexponent = {CVAR_SAVE, "r_bloom_colorexponent", "1", "how exagerated the glow is"};
108 cvar_t r_bloom_colorsubtract = {CVAR_SAVE, "r_bloom_colorsubtract", "0.125", "reduces bloom colors by a certain amount"};
109
110 cvar_t r_hdr = {CVAR_SAVE, "r_hdr", "0", "enables High Dynamic Range bloom effect (higher quality version of r_bloom)"};
111 cvar_t r_hdr_scenebrightness = {CVAR_SAVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
112 cvar_t r_hdr_glowintensity = {CVAR_SAVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
113 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)"};
114
115 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"};
116
117 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"};
118
119 cvar_t gl_lightmaps = {0, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers)"};
120
121 cvar_t r_test = {0, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
122 cvar_t r_batchmode = {0, "r_batchmode", "1", "selects method of rendering multiple surfaces with one driver call (values are 0, 1, 2, etc...)"};
123 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"};
124 cvar_t r_track_sprites_flags = {CVAR_SAVE, "r_track_sprites_flags", "1", "1: Rotate sprites accodringly, 2: Make it a continuous rotation"};
125 cvar_t r_track_sprites_scalew = {CVAR_SAVE, "r_track_sprites_scalew", "1", "width scaling of tracked sprites"};
126 cvar_t r_track_sprites_scaleh = {CVAR_SAVE, "r_track_sprites_scaleh", "1", "height scaling of tracked sprites"};
127
128 extern cvar_t v_glslgamma;
129
130 extern qboolean v_flipped_state;
131
132 static struct r_bloomstate_s
133 {
134         qboolean enabled;
135         qboolean hdr;
136
137         int bloomwidth, bloomheight;
138
139         int screentexturewidth, screentextureheight;
140         rtexture_t *texture_screen;
141
142         int bloomtexturewidth, bloomtextureheight;
143         rtexture_t *texture_bloom;
144
145         // arrays for rendering the screen passes
146         float screentexcoord2f[8];
147         float bloomtexcoord2f[8];
148         float offsettexcoord2f[8];
149 }
150 r_bloomstate;
151
152 typedef struct r_waterstate_waterplane_s
153 {
154         rtexture_t *texture_refraction;
155         rtexture_t *texture_reflection;
156         mplane_t plane;
157         int materialflags; // combined flags of all water surfaces on this plane
158         unsigned char pvsbits[(32768+7)>>3]; // FIXME: buffer overflow on huge maps
159         qboolean pvsvalid;
160 }
161 r_waterstate_waterplane_t;
162
163 #define MAX_WATERPLANES 16
164
165 static struct r_waterstate_s
166 {
167         qboolean enabled;
168
169         qboolean renderingscene; // true while rendering a refraction or reflection texture, disables water surfaces
170
171         int waterwidth, waterheight;
172         int texturewidth, textureheight;
173
174         int maxwaterplanes; // same as MAX_WATERPLANES
175         int numwaterplanes;
176         r_waterstate_waterplane_t waterplanes[MAX_WATERPLANES];
177
178         float screenscale[2];
179         float screencenter[2];
180 }
181 r_waterstate;
182
183 // shadow volume bsp struct with automatically growing nodes buffer
184 svbsp_t r_svbsp;
185
186 rtexture_t *r_texture_blanknormalmap;
187 rtexture_t *r_texture_white;
188 rtexture_t *r_texture_grey128;
189 rtexture_t *r_texture_black;
190 rtexture_t *r_texture_notexture;
191 rtexture_t *r_texture_whitecube;
192 rtexture_t *r_texture_normalizationcube;
193 rtexture_t *r_texture_fogattenuation;
194 rtexture_t *r_texture_gammaramps;
195 unsigned int r_texture_gammaramps_serial;
196 //rtexture_t *r_texture_fogintensity;
197
198 char r_qwskincache[MAX_SCOREBOARD][MAX_QPATH];
199 skinframe_t *r_qwskincache_skinframe[MAX_SCOREBOARD];
200
201 // vertex coordinates for a quad that covers the screen exactly
202 const static float r_screenvertex3f[12] =
203 {
204         0, 0, 0,
205         1, 0, 0,
206         1, 1, 0,
207         0, 1, 0
208 };
209
210 extern void R_DrawModelShadows(void);
211
212 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
213 {
214         int i;
215         for (i = 0;i < verts;i++)
216         {
217                 out[0] = in[0] * r;
218                 out[1] = in[1] * g;
219                 out[2] = in[2] * b;
220                 out[3] = in[3];
221                 in += 4;
222                 out += 4;
223         }
224 }
225
226 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
227 {
228         int i;
229         for (i = 0;i < verts;i++)
230         {
231                 out[0] = r;
232                 out[1] = g;
233                 out[2] = b;
234                 out[3] = a;
235                 out += 4;
236         }
237 }
238
239 // FIXME: move this to client?
240 void FOG_clear(void)
241 {
242         if (gamemode == GAME_NEHAHRA)
243         {
244                 Cvar_Set("gl_fogenable", "0");
245                 Cvar_Set("gl_fogdensity", "0.2");
246                 Cvar_Set("gl_fogred", "0.3");
247                 Cvar_Set("gl_foggreen", "0.3");
248                 Cvar_Set("gl_fogblue", "0.3");
249         }
250         r_refdef.fog_density = 0;
251         r_refdef.fog_red = 0;
252         r_refdef.fog_green = 0;
253         r_refdef.fog_blue = 0;
254         r_refdef.fog_alpha = 1;
255         r_refdef.fog_start = 0;
256         r_refdef.fog_end = 0;
257 }
258
259 float FogForDistance(vec_t dist)
260 {
261         unsigned int fogmasktableindex = (unsigned int)(dist * r_refdef.fogmasktabledistmultiplier);
262         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
263 }
264
265 float FogPoint_World(const vec3_t p)
266 {
267         return FogForDistance(VectorDistance((p), r_refdef.view.origin));
268 }
269
270 float FogPoint_Model(const vec3_t p)
271 {
272         return FogForDistance(VectorDistance((p), rsurface.modelorg));
273 }
274
275 static void R_BuildBlankTextures(void)
276 {
277         unsigned char data[4];
278         data[2] = 128; // normal X
279         data[1] = 128; // normal Y
280         data[0] = 255; // normal Z
281         data[3] = 128; // height
282         r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_PERSISTENT, NULL);
283         data[0] = 255;
284         data[1] = 255;
285         data[2] = 255;
286         data[3] = 255;
287         r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_PERSISTENT, NULL);
288         data[0] = 128;
289         data[1] = 128;
290         data[2] = 128;
291         data[3] = 255;
292         r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_PERSISTENT, NULL);
293         data[0] = 0;
294         data[1] = 0;
295         data[2] = 0;
296         data[3] = 255;
297         r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_PERSISTENT, NULL);
298 }
299
300 static void R_BuildNoTexture(void)
301 {
302         int x, y;
303         unsigned char pix[16][16][4];
304         // this makes a light grey/dark grey checkerboard texture
305         for (y = 0;y < 16;y++)
306         {
307                 for (x = 0;x < 16;x++)
308                 {
309                         if ((y < 8) ^ (x < 8))
310                         {
311                                 pix[y][x][0] = 128;
312                                 pix[y][x][1] = 128;
313                                 pix[y][x][2] = 128;
314                                 pix[y][x][3] = 255;
315                         }
316                         else
317                         {
318                                 pix[y][x][0] = 64;
319                                 pix[y][x][1] = 64;
320                                 pix[y][x][2] = 64;
321                                 pix[y][x][3] = 255;
322                         }
323                 }
324         }
325         r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_PERSISTENT, NULL);
326 }
327
328 static void R_BuildWhiteCube(void)
329 {
330         unsigned char data[6*1*1*4];
331         memset(data, 255, sizeof(data));
332         r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_PERSISTENT, NULL);
333 }
334
335 static void R_BuildNormalizationCube(void)
336 {
337         int x, y, side;
338         vec3_t v;
339         vec_t s, t, intensity;
340 #define NORMSIZE 64
341         unsigned char data[6][NORMSIZE][NORMSIZE][4];
342         for (side = 0;side < 6;side++)
343         {
344                 for (y = 0;y < NORMSIZE;y++)
345                 {
346                         for (x = 0;x < NORMSIZE;x++)
347                         {
348                                 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
349                                 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
350                                 switch(side)
351                                 {
352                                 default:
353                                 case 0:
354                                         v[0] = 1;
355                                         v[1] = -t;
356                                         v[2] = -s;
357                                         break;
358                                 case 1:
359                                         v[0] = -1;
360                                         v[1] = -t;
361                                         v[2] = s;
362                                         break;
363                                 case 2:
364                                         v[0] = s;
365                                         v[1] = 1;
366                                         v[2] = t;
367                                         break;
368                                 case 3:
369                                         v[0] = s;
370                                         v[1] = -1;
371                                         v[2] = -t;
372                                         break;
373                                 case 4:
374                                         v[0] = s;
375                                         v[1] = -t;
376                                         v[2] = 1;
377                                         break;
378                                 case 5:
379                                         v[0] = -s;
380                                         v[1] = -t;
381                                         v[2] = -1;
382                                         break;
383                                 }
384                                 intensity = 127.0f / sqrt(DotProduct(v, v));
385                                 data[side][y][x][2] = (unsigned char)(128.0f + intensity * v[0]);
386                                 data[side][y][x][1] = (unsigned char)(128.0f + intensity * v[1]);
387                                 data[side][y][x][0] = (unsigned char)(128.0f + intensity * v[2]);
388                                 data[side][y][x][3] = 255;
389                         }
390                 }
391         }
392         r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, &data[0][0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_PERSISTENT, NULL);
393 }
394
395 static void R_BuildFogTexture(void)
396 {
397         int x, b;
398 #define FOGWIDTH 256
399         unsigned char data1[FOGWIDTH][4];
400         //unsigned char data2[FOGWIDTH][4];
401         double d, r, alpha;
402
403         r_refdef.fogmasktable_start = r_refdef.fog_start;
404         r_refdef.fogmasktable_alpha = r_refdef.fog_alpha;
405         r_refdef.fogmasktable_range = r_refdef.fogrange;
406         r_refdef.fogmasktable_density = r_refdef.fog_density;
407
408         r = r_refdef.fogmasktable_range / FOGMASKTABLEWIDTH;
409         for (x = 0;x < FOGMASKTABLEWIDTH;x++)
410         {
411                 d = (x * r - r_refdef.fogmasktable_start);
412                 if(developer.integer >= 100)
413                         Con_Printf("%f ", d);
414                 d = max(0, d);
415                 if (r_fog_exp2.integer)
416                         alpha = exp(-r_refdef.fogmasktable_density * r_refdef.fogmasktable_density * 0.0001 * d * d);
417                 else
418                         alpha = exp(-r_refdef.fogmasktable_density * 0.004 * d);
419                 if(developer.integer >= 100)
420                         Con_Printf(" : %f ", alpha);
421                 alpha = 1 - (1 - alpha) * r_refdef.fogmasktable_alpha;
422                 if(developer.integer >= 100)
423                         Con_Printf(" = %f\n", alpha);
424                 r_refdef.fogmasktable[x] = bound(0, alpha, 1);
425         }
426
427         for (x = 0;x < FOGWIDTH;x++)
428         {
429                 b = (int)(r_refdef.fogmasktable[x * (FOGMASKTABLEWIDTH - 1) / (FOGWIDTH - 1)] * 255);
430                 data1[x][0] = b;
431                 data1[x][1] = b;
432                 data1[x][2] = b;
433                 data1[x][3] = 255;
434                 //data2[x][0] = 255 - b;
435                 //data2[x][1] = 255 - b;
436                 //data2[x][2] = 255 - b;
437                 //data2[x][3] = 255;
438         }
439         if (r_texture_fogattenuation)
440         {
441                 R_UpdateTexture(r_texture_fogattenuation, &data1[0][0], 0, 0, FOGWIDTH, 1);
442                 //R_UpdateTexture(r_texture_fogattenuation, &data2[0][0], 0, 0, FOGWIDTH, 1);
443         }
444         else
445         {
446                 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);
447                 //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
448         }
449 }
450
451 static const char *builtinshaderstring =
452 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
453 "// written by Forest 'LordHavoc' Hale\n"
454 "\n"
455 "// common definitions between vertex shader and fragment shader:\n"
456 "\n"
457 "//#ifdef __GLSL_CG_DATA_TYPES\n"
458 "//# define myhalf half\n"
459 "//# define myhalf2 half2\n"
460 "//# define myhalf3 half3\n"
461 "//# define myhalf4 half4\n"
462 "//#else\n"
463 "# define myhalf float\n"
464 "# define myhalf2 vec2\n"
465 "# define myhalf3 vec3\n"
466 "# define myhalf4 vec4\n"
467 "//#endif\n"
468 "\n"
469 "#ifdef MODE_DEPTH_OR_SHADOW\n"
470 "\n"
471 "# ifdef VERTEX_SHADER\n"
472 "void main(void)\n"
473 "{\n"
474 "       gl_Position = ftransform();\n"
475 "}\n"
476 "# endif\n"
477 "\n"
478 "#else\n"
479 "\n"
480 "#ifdef MODE_POSTPROCESS\n"
481 "# ifdef VERTEX_SHADER\n"
482 "void main(void)\n"
483 "{\n"
484 "       gl_FrontColor = gl_Color;\n"
485 "       gl_Position = ftransform();\n"
486 "       gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;\n"
487 "#ifdef USEGLOW\n"
488 "       gl_TexCoord[1] = gl_TextureMatrix[1] * gl_MultiTexCoord1;\n"
489 "#endif\n"
490 "}\n"
491 "# endif\n"
492 "# ifdef FRAGMENT_SHADER\n"
493 "\n"
494 "uniform sampler2D Texture_First;\n"
495 "#ifdef USEGLOW\n"
496 "uniform sampler2D Texture_Second;\n"
497 "#endif\n"
498 "#ifdef USEGAMMARAMPS\n"
499 "uniform sampler2D Texture_Attenuation;\n"
500 "#endif\n"
501 "#ifdef USEVERTEXTEXTUREBLEND\n"
502 "uniform vec4 TintColor;\n"
503 "#endif\n"
504 "#ifdef USECOLORMOD\n"
505 "uniform vec3 Gamma;\n"
506 "#endif\n"
507 "//uncomment these if you want to use them:\n"
508 "// uniform vec4 UserVec1;\n"
509 "// uniform vec4 UserVec2;\n"
510 "// uniform vec4 UserVec3;\n"
511 "// uniform vec4 UserVec4;\n"
512 "// uniform float ClientTime;\n"
513 "void main(void)\n"
514 "{\n"
515 "       gl_FragColor = texture2D(Texture_First, gl_TexCoord[0].xy);\n"
516 "#ifdef USEGLOW\n"
517 "       gl_FragColor += texture2D(Texture_Second, gl_TexCoord[1].xy);\n"
518 "#endif\n"
519 "#ifdef USEVERTEXTEXTUREBLEND\n"
520 "       gl_FragColor = mix(TintColor, gl_FragColor, TintColor.a);\n"
521 "#endif\n"
522 "\n"
523 "#ifdef USEPOSTPROCESSING\n"
524 "// add your own postprocessing here or make your own ifdef for it\n"
525 "#endif\n"
526 "\n"
527 "#ifdef USEGAMMARAMPS\n"
528 "       gl_FragColor.r = texture2D(Texture_Attenuation, vec2(gl_FragColor.r, 0)).r;\n"
529 "       gl_FragColor.g = texture2D(Texture_Attenuation, vec2(gl_FragColor.g, 0)).g;\n"
530 "       gl_FragColor.b = texture2D(Texture_Attenuation, vec2(gl_FragColor.b, 0)).b;\n"
531 "#endif\n"
532 "}\n"
533 "# endif\n"
534 "\n"
535 "\n"
536 "#else\n"
537 "#ifdef MODE_GENERIC\n"
538 "# ifdef VERTEX_SHADER\n"
539 "void main(void)\n"
540 "{\n"
541 "       gl_FrontColor = gl_Color;\n"
542 "#  ifdef USEDIFFUSE\n"
543 "       gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;\n"
544 "#  endif\n"
545 "#  ifdef USESPECULAR\n"
546 "       gl_TexCoord[1] = gl_TextureMatrix[1] * gl_MultiTexCoord1;\n"
547 "#  endif\n"
548 "       gl_Position = ftransform();\n"
549 "}\n"
550 "# endif\n"
551 "# ifdef FRAGMENT_SHADER\n"
552 "\n"
553 "#  ifdef USEDIFFUSE\n"
554 "uniform sampler2D Texture_First;\n"
555 "#  endif\n"
556 "#  ifdef USESPECULAR\n"
557 "uniform sampler2D Texture_Second;\n"
558 "#  endif\n"
559 "\n"
560 "void main(void)\n"
561 "{\n"
562 "       gl_FragColor = gl_Color;\n"
563 "#  ifdef USEDIFFUSE\n"
564 "       gl_FragColor *= texture2D(Texture_First, gl_TexCoord[0].xy);\n"
565 "#  endif\n"
566 "\n"
567 "#  ifdef USESPECULAR\n"
568 "       vec4 tex2 = texture2D(Texture_Second, gl_TexCoord[1].xy);\n"
569 "#  endif\n"
570 "#  ifdef USECOLORMAPPING\n"
571 "       gl_FragColor *= tex2;\n"
572 "#  endif\n"
573 "#  ifdef USEGLOW\n"
574 "       gl_FragColor += tex2;\n"
575 "#  endif\n"
576 "#  ifdef USEVERTEXTEXTUREBLEND\n"
577 "       gl_FragColor = mix(tex2, gl_FragColor, tex2.a);\n"
578 "#  endif\n"
579 "}\n"
580 "# endif\n"
581 "\n"
582 "#else // !MODE_GENERIC\n"
583 "\n"
584 "varying vec2 TexCoord;\n"
585 "varying vec2 TexCoordLightmap;\n"
586 "\n"
587 "#ifdef MODE_LIGHTSOURCE\n"
588 "varying vec3 CubeVector;\n"
589 "#endif\n"
590 "\n"
591 "#ifdef MODE_LIGHTSOURCE\n"
592 "varying vec3 LightVector;\n"
593 "#endif\n"
594 "#ifdef MODE_LIGHTDIRECTION\n"
595 "varying vec3 LightVector;\n"
596 "#endif\n"
597 "\n"
598 "varying vec3 EyeVector;\n"
599 "#ifdef USEFOG\n"
600 "varying vec3 EyeVectorModelSpace;\n"
601 "#endif\n"
602 "\n"
603 "varying vec3 VectorS; // direction of S texcoord (sometimes crudely called tangent)\n"
604 "varying vec3 VectorT; // direction of T texcoord (sometimes crudely called binormal)\n"
605 "varying vec3 VectorR; // direction of R texcoord (surface normal)\n"
606 "\n"
607 "#ifdef MODE_WATER\n"
608 "varying vec4 ModelViewProjectionPosition;\n"
609 "#ifdef MODE_REFRACTION\n"
610 "varying vec4 ModelViewProjectionPosition;\n"
611 "#else\n"
612 "# ifdef USEREFLECTION\n"
613 "varying vec4 ModelViewProjectionPosition;\n"
614 "# endif\n"
615 "#endif\n"
616 "#endif\n"
617 "\n"
618 "\n"
619 "\n"
620 "\n"
621 "\n"
622 "// vertex shader specific:\n"
623 "#ifdef VERTEX_SHADER\n"
624 "\n"
625 "uniform vec3 LightPosition;\n"
626 "uniform vec3 EyePosition;\n"
627 "uniform vec3 LightDir;\n"
628 "\n"
629 "// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3), this would require sending a 4 component texcoord1 with W as 1 or -1 according to which side the texcoord2 should be on\n"
630 "\n"
631 "void main(void)\n"
632 "{\n"
633 "       gl_FrontColor = gl_Color;\n"
634 "       // copy the surface texcoord\n"
635 "       TexCoord = vec2(gl_TextureMatrix[0] * gl_MultiTexCoord0);\n"
636 "#ifndef MODE_LIGHTSOURCE\n"
637 "# ifndef MODE_LIGHTDIRECTION\n"
638 "       TexCoordLightmap = vec2(gl_MultiTexCoord4);\n"
639 "# endif\n"
640 "#endif\n"
641 "\n"
642 "#ifdef MODE_LIGHTSOURCE\n"
643 "       // transform vertex position into light attenuation/cubemap space\n"
644 "       // (-1 to +1 across the light box)\n"
645 "       CubeVector = vec3(gl_TextureMatrix[3] * gl_Vertex);\n"
646 "\n"
647 "       // transform unnormalized light direction into tangent space\n"
648 "       // (we use unnormalized to ensure that it interpolates correctly and then\n"
649 "       //  normalize it per pixel)\n"
650 "       vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n"
651 "       LightVector.x = dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
652 "       LightVector.y = dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
653 "       LightVector.z = dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n"
654 "#endif\n"
655 "\n"
656 "#ifdef MODE_LIGHTDIRECTION\n"
657 "       LightVector.x = dot(LightDir, gl_MultiTexCoord1.xyz);\n"
658 "       LightVector.y = dot(LightDir, gl_MultiTexCoord2.xyz);\n"
659 "       LightVector.z = dot(LightDir, gl_MultiTexCoord3.xyz);\n"
660 "#endif\n"
661 "\n"
662 "       // transform unnormalized eye direction into tangent space\n"
663 "#ifndef USEFOG\n"
664 "       vec3 EyeVectorModelSpace;\n"
665 "#endif\n"
666 "       EyeVectorModelSpace = EyePosition - gl_Vertex.xyz;\n"
667 "       EyeVector.x = dot(EyeVectorModelSpace, gl_MultiTexCoord1.xyz);\n"
668 "       EyeVector.y = dot(EyeVectorModelSpace, gl_MultiTexCoord2.xyz);\n"
669 "       EyeVector.z = dot(EyeVectorModelSpace, gl_MultiTexCoord3.xyz);\n"
670 "\n"
671 "#ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
672 "       VectorS = gl_MultiTexCoord1.xyz;\n"
673 "       VectorT = gl_MultiTexCoord2.xyz;\n"
674 "       VectorR = gl_MultiTexCoord3.xyz;\n"
675 "#endif\n"
676 "\n"
677 "//#if defined(MODE_WATER) || defined(MODE_REFRACTION) || defined(USEREFLECTION)\n"
678 "//     ModelViewProjectionPosition = gl_Vertex * gl_ModelViewProjectionMatrix;\n"
679 "//     //ModelViewProjectionPosition_svector = (gl_Vertex + vec4(gl_MultiTexCoord1.xyz, 0)) * gl_ModelViewProjectionMatrix - ModelViewProjectionPosition;\n"
680 "//     //ModelViewProjectionPosition_tvector = (gl_Vertex + vec4(gl_MultiTexCoord2.xyz, 0)) * gl_ModelViewProjectionMatrix - ModelViewProjectionPosition;\n"
681 "//#endif\n"
682 "\n"
683 "// transform vertex to camera space, using ftransform to match non-VS\n"
684 "       // rendering\n"
685 "       gl_Position = ftransform();\n"
686 "\n"
687 "#ifdef MODE_WATER\n"
688 "       ModelViewProjectionPosition = gl_Position;\n"
689 "#endif\n"
690 "#ifdef MODE_REFRACTION\n"
691 "       ModelViewProjectionPosition = gl_Position;\n"
692 "#endif\n"
693 "#ifdef USEREFLECTION\n"
694 "       ModelViewProjectionPosition = gl_Position;\n"
695 "#endif\n"
696 "}\n"
697 "\n"
698 "#endif // VERTEX_SHADER\n"
699 "\n"
700 "\n"
701 "\n"
702 "\n"
703 "// fragment shader specific:\n"
704 "#ifdef FRAGMENT_SHADER\n"
705 "\n"
706 "// 13 textures, we can only use up to 16 on DX9-class hardware\n"
707 "uniform sampler2D Texture_Normal;\n"
708 "uniform sampler2D Texture_Color;\n"
709 "uniform sampler2D Texture_Gloss;\n"
710 "uniform sampler2D Texture_Glow;\n"
711 "uniform sampler2D Texture_SecondaryNormal;\n"
712 "uniform sampler2D Texture_SecondaryColor;\n"
713 "uniform sampler2D Texture_SecondaryGloss;\n"
714 "uniform sampler2D Texture_SecondaryGlow;\n"
715 "uniform sampler2D Texture_Pants;\n"
716 "uniform sampler2D Texture_Shirt;\n"
717 "uniform sampler2D Texture_FogMask;\n"
718 "uniform sampler2D Texture_Lightmap;\n"
719 "uniform sampler2D Texture_Deluxemap;\n"
720 "uniform sampler2D Texture_Refraction;\n"
721 "uniform sampler2D Texture_Reflection;\n"
722 "uniform sampler2D Texture_Attenuation;\n"
723 "uniform samplerCube Texture_Cube;\n"
724 "\n"
725 "uniform myhalf3 LightColor;\n"
726 "uniform myhalf3 AmbientColor;\n"
727 "uniform myhalf3 DiffuseColor;\n"
728 "uniform myhalf3 SpecularColor;\n"
729 "uniform myhalf3 Color_Pants;\n"
730 "uniform myhalf3 Color_Shirt;\n"
731 "uniform myhalf3 FogColor;\n"
732 "\n"
733 "uniform myhalf4 TintColor;\n"
734 "\n"
735 "\n"
736 "//#ifdef MODE_WATER\n"
737 "uniform vec4 DistortScaleRefractReflect;\n"
738 "uniform vec4 ScreenScaleRefractReflect;\n"
739 "uniform vec4 ScreenCenterRefractReflect;\n"
740 "uniform myhalf4 RefractColor;\n"
741 "uniform myhalf4 ReflectColor;\n"
742 "uniform myhalf ReflectFactor;\n"
743 "uniform myhalf ReflectOffset;\n"
744 "//#else\n"
745 "//# ifdef MODE_REFRACTION\n"
746 "//uniform vec4 DistortScaleRefractReflect;\n"
747 "//uniform vec4 ScreenScaleRefractReflect;\n"
748 "//uniform vec4 ScreenCenterRefractReflect;\n"
749 "//uniform myhalf4 RefractColor;\n"
750 "//#  ifdef USEREFLECTION\n"
751 "//uniform myhalf4 ReflectColor;\n"
752 "//#  endif\n"
753 "//# else\n"
754 "//#  ifdef USEREFLECTION\n"
755 "//uniform vec4 DistortScaleRefractReflect;\n"
756 "//uniform vec4 ScreenScaleRefractReflect;\n"
757 "//uniform vec4 ScreenCenterRefractReflect;\n"
758 "//uniform myhalf4 ReflectColor;\n"
759 "//#  endif\n"
760 "//# endif\n"
761 "//#endif\n"
762 "\n"
763 "uniform myhalf GlowScale;\n"
764 "uniform myhalf SceneBrightness;\n"
765 "#ifdef USECONTRASTBOOST\n"
766 "uniform myhalf ContrastBoostCoeff;\n"
767 "#endif\n"
768 "\n"
769 "uniform float OffsetMapping_Scale;\n"
770 "uniform float OffsetMapping_Bias;\n"
771 "uniform float FogRangeRecip;\n"
772 "\n"
773 "uniform myhalf AmbientScale;\n"
774 "uniform myhalf DiffuseScale;\n"
775 "uniform myhalf SpecularScale;\n"
776 "uniform myhalf SpecularPower;\n"
777 "\n"
778 "#ifdef USEOFFSETMAPPING\n"
779 "vec2 OffsetMapping(vec2 TexCoord)\n"
780 "{\n"
781 "#ifdef USEOFFSETMAPPING_RELIEFMAPPING\n"
782 "       // 14 sample relief mapping: linear search and then binary search\n"
783 "       // this basically steps forward a small amount repeatedly until it finds\n"
784 "       // itself inside solid, then jitters forward and back using decreasing\n"
785 "       // amounts to find the impact\n"
786 "       //vec3 OffsetVector = vec3(EyeVector.xy * ((1.0 / EyeVector.z) * OffsetMapping_Scale) * vec2(-1, 1), -1);\n"
787 "       //vec3 OffsetVector = vec3(normalize(EyeVector.xy) * OffsetMapping_Scale * vec2(-1, 1), -1);\n"
788 "       vec3 OffsetVector = vec3(normalize(EyeVector).xy * OffsetMapping_Scale * vec2(-1, 1), -1);\n"
789 "       vec3 RT = vec3(TexCoord, 1);\n"
790 "       OffsetVector *= 0.1;\n"
791 "       RT += OffsetVector *  step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
792 "       RT += OffsetVector *  step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
793 "       RT += OffsetVector *  step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
794 "       RT += OffsetVector *  step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
795 "       RT += OffsetVector *  step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
796 "       RT += OffsetVector *  step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
797 "       RT += OffsetVector *  step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
798 "       RT += OffsetVector *  step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
799 "       RT += OffsetVector *  step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
800 "       RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z)          - 0.5);\n"
801 "       RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) * 0.5    - 0.25);\n"
802 "       RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) * 0.25   - 0.125);\n"
803 "       RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) * 0.125  - 0.0625);\n"
804 "       RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) * 0.0625 - 0.03125);\n"
805 "       return RT.xy;\n"
806 "#else\n"
807 "       // 3 sample offset mapping (only 3 samples because of ATI Radeon 9500-9800/X300 limits)\n"
808 "       // this basically moves forward the full distance, and then backs up based\n"
809 "       // on height of samples\n"
810 "       //vec2 OffsetVector = vec2(EyeVector.xy * ((1.0 / EyeVector.z) * OffsetMapping_Scale) * vec2(-1, 1));\n"
811 "       //vec2 OffsetVector = vec2(normalize(EyeVector.xy) * OffsetMapping_Scale * vec2(-1, 1));\n"
812 "       vec2 OffsetVector = vec2(normalize(EyeVector).xy * OffsetMapping_Scale * vec2(-1, 1));\n"
813 "       TexCoord += OffsetVector;\n"
814 "       OffsetVector *= 0.333;\n"
815 "       TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
816 "       TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
817 "       TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
818 "       return TexCoord;\n"
819 "#endif\n"
820 "}\n"
821 "#endif // USEOFFSETMAPPING\n"
822 "\n"
823 "#ifdef MODE_WATER\n"
824 "\n"
825 "// water pass\n"
826 "void main(void)\n"
827 "{\n"
828 "#ifdef USEOFFSETMAPPING\n"
829 "       // apply offsetmapping\n"
830 "       vec2 TexCoordOffset = OffsetMapping(TexCoord);\n"
831 "#define TexCoord TexCoordOffset\n"
832 "#endif\n"
833 "\n"
834 "       vec4 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect * (1.0 / ModelViewProjectionPosition.w);\n"
835 "       //vec4 ScreenTexCoord = (ModelViewProjectionPosition.xyxy + normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
836 "       vec4 ScreenTexCoord = ModelViewProjectionPosition.xyxy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect + vec2(normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5))).xyxy * DistortScaleRefractReflect;\n"
837 "       float Fresnel = pow(min(1.0, 1.0 - float(normalize(EyeVector).z)), 2.0) * ReflectFactor + ReflectOffset;\n"
838 "       gl_FragColor = mix(texture2D(Texture_Refraction, ScreenTexCoord.xy) * RefractColor, texture2D(Texture_Reflection, ScreenTexCoord.zw) * ReflectColor, Fresnel);\n"
839 "}\n"
840 "\n"
841 "#else // !MODE_WATER\n"
842 "#ifdef MODE_REFRACTION\n"
843 "\n"
844 "// refraction pass\n"
845 "void main(void)\n"
846 "{\n"
847 "#ifdef USEOFFSETMAPPING\n"
848 "       // apply offsetmapping\n"
849 "       vec2 TexCoordOffset = OffsetMapping(TexCoord);\n"
850 "#define TexCoord TexCoordOffset\n"
851 "#endif\n"
852 "\n"
853 "       vec2 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect.xy * (1.0 / ModelViewProjectionPosition.w);\n"
854 "       //vec2 ScreenTexCoord = (ModelViewProjectionPosition.xy + normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5)).xy * DistortScaleRefractReflect.xy * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy;\n"
855 "       vec2 ScreenTexCoord = ModelViewProjectionPosition.xy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy + vec2(normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5))).xy * DistortScaleRefractReflect.xy;\n"
856 "       gl_FragColor = texture2D(Texture_Refraction, ScreenTexCoord) * RefractColor;\n"
857 "}\n"
858 "\n"
859 "#else // !MODE_REFRACTION\n"
860 "void main(void)\n"
861 "{\n"
862 "#ifdef USEOFFSETMAPPING\n"
863 "       // apply offsetmapping\n"
864 "       vec2 TexCoordOffset = OffsetMapping(TexCoord);\n"
865 "#define TexCoord TexCoordOffset\n"
866 "#endif\n"
867 "\n"
868 "       // combine the diffuse textures (base, pants, shirt)\n"
869 "       myhalf4 color = myhalf4(texture2D(Texture_Color, TexCoord));\n"
870 "#ifdef USECOLORMAPPING\n"
871 "       color.rgb += myhalf3(texture2D(Texture_Pants, TexCoord)) * Color_Pants + myhalf3(texture2D(Texture_Shirt, TexCoord)) * Color_Shirt;\n"
872 "#endif\n"
873 "#ifdef USEVERTEXTEXTUREBLEND\n"
874 "       myhalf terrainblend = clamp(myhalf(gl_Color.a) * color.a * 2.0 - 0.5, myhalf(0.0), myhalf(1.0));\n"
875 "       //myhalf terrainblend = min(myhalf(gl_Color.a) * color.a * 2.0, myhalf(1.0));\n"
876 "       //myhalf terrainblend = myhalf(gl_Color.a) * color.a > 0.5;\n"
877 "       color = mix(myhalf4(texture2D(Texture_SecondaryColor, TexCoord)), color, terrainblend);\n"
878 "       //color = mix(myhalf4(1, 0, 0, 1), color, terrainblend);\n"
879 "#endif\n"
880 "\n"
881 "#ifdef USEDIFFUSE\n"
882 "       // get the surface normal and the gloss color\n"
883 "# ifdef USEVERTEXTEXTUREBLEND\n"
884 "       myhalf3 surfacenormal = normalize(mix(myhalf3(texture2D(Texture_SecondaryNormal, TexCoord)), myhalf3(texture2D(Texture_Normal, TexCoord)), terrainblend) - myhalf3(0.5, 0.5, 0.5));\n"
885 "#  ifdef USESPECULAR\n"
886 "       myhalf3 glosscolor = mix(myhalf3(texture2D(Texture_SecondaryGloss, TexCoord)), myhalf3(texture2D(Texture_Gloss, TexCoord)), terrainblend);\n"
887 "#  endif\n"
888 "# else\n"
889 "       myhalf3 surfacenormal = normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5));\n"
890 "#  ifdef USESPECULAR\n"
891 "       myhalf3 glosscolor = myhalf3(texture2D(Texture_Gloss, TexCoord));\n"
892 "#  endif\n"
893 "# endif\n"
894 "#endif\n"
895 "\n"
896 "\n"
897 "\n"
898 "#ifdef MODE_LIGHTSOURCE\n"
899 "       // light source\n"
900 "\n"
901 "       // calculate surface normal, light normal, and specular normal\n"
902 "       // compute color intensity for the two textures (colormap and glossmap)\n"
903 "       // scale by light color and attenuation as efficiently as possible\n"
904 "       // (do as much scalar math as possible rather than vector math)\n"
905 "# ifdef USEDIFFUSE\n"
906 "       // get the light normal\n"
907 "       myhalf3 diffusenormal = myhalf3(normalize(LightVector));\n"
908 "# endif\n"
909 "# ifdef USESPECULAR\n"
910 "       myhalf3 specularnormal = normalize(diffusenormal + myhalf3(normalize(EyeVector)));\n"
911 "\n"
912 "       // calculate directional shading\n"
913 "       color.rgb = 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)) * glosscolor);\n"
914 "# else\n"
915 "#  ifdef USEDIFFUSE\n"
916 "       // calculate directional shading\n"
917 "       color.rgb = color.rgb * (myhalf(texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0))) * (AmbientScale + DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0))));\n"
918 "#  else\n"
919 "       // calculate directionless shading\n"
920 "       color.rgb = color.rgb * myhalf(texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0)));\n"
921 "#  endif\n"
922 "# endif\n"
923 "\n"
924 "# ifdef USECUBEFILTER\n"
925 "       // apply light cubemap filter\n"
926 "       //color.rgb *= normalize(CubeVector) * 0.5 + 0.5;//vec3(textureCube(Texture_Cube, CubeVector));\n"
927 "       color.rgb *= myhalf3(textureCube(Texture_Cube, CubeVector));\n"
928 "# endif\n"
929 "#endif // MODE_LIGHTSOURCE\n"
930 "\n"
931 "\n"
932 "\n"
933 "\n"
934 "#ifdef MODE_LIGHTDIRECTION\n"
935 "       // directional model lighting\n"
936 "# ifdef USEDIFFUSE\n"
937 "       // get the light normal\n"
938 "       myhalf3 diffusenormal = myhalf3(LightVector);\n"
939 "# endif\n"
940 "# ifdef USESPECULAR\n"
941 "       // calculate directional shading\n"
942 "       color.rgb *= AmbientColor + DiffuseColor * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0));\n"
943 "       myhalf3 specularnormal = normalize(diffusenormal + myhalf3(normalize(EyeVector)));\n"
944 "       color.rgb += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularColor * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
945 "# else\n"
946 "#  ifdef USEDIFFUSE\n"
947 "\n"
948 "       // calculate directional shading\n"
949 "       color.rgb *= AmbientColor + DiffuseColor * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0));\n"
950 "#  else\n"
951 "       color.rgb *= AmbientColor;\n"
952 "#  endif\n"
953 "# endif\n"
954 "#endif // MODE_LIGHTDIRECTION\n"
955 "\n"
956 "\n"
957 "\n"
958 "\n"
959 "#ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
960 "       // deluxemap lightmapping using light vectors in modelspace (evil q3map2)\n"
961 "\n"
962 "       // get the light normal\n"
963 "       myhalf3 diffusenormal_modelspace = myhalf3(texture2D(Texture_Deluxemap, TexCoordLightmap)) - myhalf3(0.5);\n"
964 "       myhalf3 diffusenormal = normalize(myhalf3(dot(diffusenormal_modelspace, myhalf3(VectorS)), dot(diffusenormal_modelspace, myhalf3(VectorT)), dot(diffusenormal_modelspace, myhalf3(VectorR))));\n"
965 "       // calculate directional shading\n"
966 "       myhalf3 tempcolor = color.rgb * (DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0)));\n"
967 "# ifdef USESPECULAR\n"
968 "       myhalf3 specularnormal = myhalf3(normalize(diffusenormal + myhalf3(normalize(EyeVector))));\n"
969 "       tempcolor += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
970 "# endif\n"
971 "\n"
972 "       // apply lightmap color\n"
973 "       color.rgb = color.rgb * AmbientScale + tempcolor * myhalf3(texture2D(Texture_Lightmap, TexCoordLightmap));\n"
974 "#endif // MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
975 "\n"
976 "\n"
977 "\n"
978 "\n"
979 "#ifdef MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n"
980 "       // deluxemap lightmapping using light vectors in tangentspace (hmap2 -light)\n"
981 "\n"
982 "       // get the light normal\n"
983 "       myhalf3 diffusenormal = normalize(myhalf3(texture2D(Texture_Deluxemap, TexCoordLightmap)) - myhalf3(0.5));\n"
984 "       // calculate directional shading\n"
985 "       myhalf3 tempcolor = color.rgb * (DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0)));\n"
986 "# ifdef USESPECULAR\n"
987 "       myhalf3 specularnormal = myhalf3(normalize(diffusenormal + myhalf3(normalize(EyeVector))));\n"
988 "       tempcolor += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
989 "# endif\n"
990 "\n"
991 "       // apply lightmap color\n"
992 "       color.rgb = color.rgb * AmbientScale + tempcolor * myhalf3(texture2D(Texture_Lightmap, TexCoordLightmap));\n"
993 "#endif // MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n"
994 "\n"
995 "\n"
996 "\n"
997 "\n"
998 "#ifdef MODE_LIGHTMAP\n"
999 "       // apply lightmap color\n"
1000 "       color.rgb = color.rgb * myhalf3(texture2D(Texture_Lightmap, TexCoordLightmap)) * DiffuseScale + color.rgb * AmbientScale;\n"
1001 "#endif // MODE_LIGHTMAP\n"
1002 "\n"
1003 "\n"
1004 "\n"
1005 "\n"
1006 "#ifdef MODE_VERTEXCOLOR\n"
1007 "       // apply lightmap color\n"
1008 "       color.rgb = color.rgb * myhalf3(gl_Color.rgb) * DiffuseScale + color.rgb * AmbientScale;\n"
1009 "#endif // MODE_VERTEXCOLOR\n"
1010 "\n"
1011 "\n"
1012 "\n"
1013 "\n"
1014 "#ifdef MODE_FLATCOLOR\n"
1015 "#endif // MODE_FLATCOLOR\n"
1016 "\n"
1017 "\n"
1018 "\n"
1019 "\n"
1020 "\n"
1021 "\n"
1022 "\n"
1023 "       color *= TintColor;\n"
1024 "\n"
1025 "#ifdef USEGLOW\n"
1026 "       color.rgb += myhalf3(texture2D(Texture_Glow, TexCoord)) * GlowScale;\n"
1027 "#endif\n"
1028 "\n"
1029 "#ifdef USECONTRASTBOOST\n"
1030 "       color.rgb = color.rgb / (ContrastBoostCoeff * color.rgb + myhalf3(1, 1, 1));\n"
1031 "#endif\n"
1032 "\n"
1033 "       color.rgb *= SceneBrightness;\n"
1034 "\n"
1035 "       // apply fog after Contrastboost/SceneBrightness because its color is already modified appropriately\n"
1036 "#ifdef USEFOG\n"
1037 "       color.rgb = mix(FogColor, color.rgb, myhalf(texture2D(Texture_FogMask, myhalf2(length(EyeVectorModelSpace)*FogRangeRecip, 0.0))));\n"
1038 "#endif\n"
1039 "\n"
1040 "       // reflection must come last because it already contains exactly the correct fog (the reflection render preserves camera distance from the plane, it only flips the side) and ContrastBoost/SceneBrightness\n"
1041 "#ifdef USEREFLECTION\n"
1042 "       vec4 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect * (1.0 / ModelViewProjectionPosition.w);\n"
1043 "       //vec4 ScreenTexCoord = (ModelViewProjectionPosition.xyxy + normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
1044 "       vec4 ScreenTexCoord = ModelViewProjectionPosition.xyxy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect + vec3(normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5))).xyxy * DistortScaleRefractReflect;\n"
1045 "       color.rgb = mix(color.rgb, myhalf3(texture2D(Texture_Reflection, ScreenTexCoord.zw)) * ReflectColor.rgb, ReflectColor.a);\n"
1046 "#endif\n"
1047 "\n"
1048 "       gl_FragColor = vec4(color);\n"
1049 "}\n"
1050 "#endif // !MODE_REFRACTION\n"
1051 "#endif // !MODE_WATER\n"
1052 "\n"
1053 "#endif // FRAGMENT_SHADER\n"
1054 "\n"
1055 "#endif // !MODE_GENERIC\n"
1056 "#endif // !MODE_POSTPROCESS\n"
1057 "#endif // !MODE_DEPTH_OR_SHADOW\n"
1058 ;
1059
1060 typedef struct shaderpermutationinfo_s
1061 {
1062         const char *pretext;
1063         const char *name;
1064 }
1065 shaderpermutationinfo_t;
1066
1067 typedef struct shadermodeinfo_s
1068 {
1069         const char *vertexfilename;
1070         const char *geometryfilename;
1071         const char *fragmentfilename;
1072         const char *pretext;
1073         const char *name;
1074 }
1075 shadermodeinfo_t;
1076
1077 typedef enum shaderpermutation_e
1078 {
1079         SHADERPERMUTATION_DIFFUSE = 1<<0, // (lightsource) whether to use directional shading
1080         SHADERPERMUTATION_VERTEXTEXTUREBLEND = 1<<1, // indicates this is a two-layer material blend based on vertex alpha (q3bsp)
1081         SHADERPERMUTATION_COLORMAPPING = 1<<2, // indicates this is a colormapped skin
1082         SHADERPERMUTATION_CONTRASTBOOST = 1<<3, // r_glsl_contrastboost boosts the contrast at low color levels (similar to gamma)
1083         SHADERPERMUTATION_FOG = 1<<4, // tint the color by fog color or black if using additive blend mode
1084         SHADERPERMUTATION_CUBEFILTER = 1<<5, // (lightsource) use cubemap light filter
1085         SHADERPERMUTATION_GLOW = 1<<6, // (lightmap) blend in an additive glow texture
1086         SHADERPERMUTATION_SPECULAR = 1<<7, // (lightsource or deluxemapping) render specular effects
1087         SHADERPERMUTATION_REFLECTION = 1<<8, // normalmap-perturbed reflection of the scene infront of the surface, preformed as an overlay on the surface
1088         SHADERPERMUTATION_OFFSETMAPPING = 1<<9, // adjust texcoords to roughly simulate a displacement mapped surface
1089         SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING = 1<<10, // adjust texcoords to accurately simulate a displacement mapped surface (requires OFFSETMAPPING to also be set!)
1090         SHADERPERMUTATION_GAMMARAMPS = 1<<11, // gamma (postprocessing only)
1091         SHADERPERMUTATION_POSTPROCESSING = 1<<12, // user defined postprocessing
1092         SHADERPERMUTATION_LIMIT = 1<<13, // size of permutations array
1093         SHADERPERMUTATION_COUNT = 13 // size of shaderpermutationinfo array
1094 }
1095 shaderpermutation_t;
1096
1097 // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
1098 shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
1099 {
1100         {"#define USEDIFFUSE\n", " diffuse"},
1101         {"#define USEVERTEXTEXTUREBLEND\n", " vertextextureblend"},
1102         {"#define USECOLORMAPPING\n", " colormapping"},
1103         {"#define USECONTRASTBOOST\n", " contrastboost"},
1104         {"#define USEFOG\n", " fog"},
1105         {"#define USECUBEFILTER\n", " cubefilter"},
1106         {"#define USEGLOW\n", " glow"},
1107         {"#define USESPECULAR\n", " specular"},
1108         {"#define USEREFLECTION\n", " reflection"},
1109         {"#define USEOFFSETMAPPING\n", " offsetmapping"},
1110         {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
1111         {"#define USEGAMMARAMPS\n", " gammaramps"},
1112         {"#define USEPOSTPROCESSING\n", " postprocessing"},
1113 };
1114
1115 // this enum is multiplied by SHADERPERMUTATION_MODEBASE
1116 typedef enum shadermode_e
1117 {
1118         SHADERMODE_GENERIC, // (particles/HUD/etc) vertex color, optionally multiplied by one texture
1119         SHADERMODE_POSTPROCESS, // postprocessing shader (r_glsl_postprocess)
1120         SHADERMODE_DEPTH_OR_SHADOW, // (depthfirst/shadows) vertex shader only
1121         SHADERMODE_FLATCOLOR, // (lightmap) modulate texture by uniform color (q1bsp, q3bsp)
1122         SHADERMODE_VERTEXCOLOR, // (lightmap) modulate texture by vertex colors (q3bsp)
1123         SHADERMODE_LIGHTMAP, // (lightmap) modulate texture by lightmap texture (q1bsp, q3bsp)
1124         SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE, // (lightmap) use directional pixel shading from texture containing modelspace light directions (q3bsp deluxemap)
1125         SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE, // (lightmap) use directional pixel shading from texture containing tangentspace light directions (q1bsp deluxemap)
1126         SHADERMODE_LIGHTDIRECTION, // (lightmap) use directional pixel shading from fixed light direction (q3bsp)
1127         SHADERMODE_LIGHTSOURCE, // (lightsource) use directional pixel shading from light source (rtlight)
1128         SHADERMODE_REFRACTION, // refract background (the material is rendered normally after this pass)
1129         SHADERMODE_WATER, // refract background and reflection (the material is rendered normally after this pass)
1130         SHADERMODE_COUNT
1131 }
1132 shadermode_t;
1133
1134 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
1135 shadermodeinfo_t shadermodeinfo[SHADERMODE_COUNT] =
1136 {
1137         {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_GENERIC\n", " generic"},
1138         {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_POSTPROCESS\n", " postprocess"},
1139         {"glsl/default.glsl", NULL, NULL               , "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
1140         {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_FLATCOLOR\n", " flatcolor"},
1141         {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
1142         {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTMAP\n", " lightmap"},
1143         {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
1144         {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
1145         {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
1146         {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTSOURCE\n", " lightsource"},
1147         {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_REFRACTION\n", " refraction"},
1148         {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_WATER\n", " water"},
1149 };
1150
1151 typedef struct r_glsl_permutation_s
1152 {
1153         // indicates if we have tried compiling this permutation already
1154         qboolean compiled;
1155         // 0 if compilation failed
1156         int program;
1157         // locations of detected uniforms in program object, or -1 if not found
1158         int loc_Texture_First;
1159         int loc_Texture_Second;
1160         int loc_Texture_Normal;
1161         int loc_Texture_Color;
1162         int loc_Texture_Gloss;
1163         int loc_Texture_Glow;
1164         int loc_Texture_SecondaryNormal;
1165         int loc_Texture_SecondaryColor;
1166         int loc_Texture_SecondaryGloss;
1167         int loc_Texture_SecondaryGlow;
1168         int loc_Texture_Pants;
1169         int loc_Texture_Shirt;
1170         int loc_Texture_FogMask;
1171         int loc_Texture_Lightmap;
1172         int loc_Texture_Deluxemap;
1173         int loc_Texture_Attenuation;
1174         int loc_Texture_Cube;
1175         int loc_Texture_Refraction;
1176         int loc_Texture_Reflection;
1177         int loc_FogColor;
1178         int loc_LightPosition;
1179         int loc_EyePosition;
1180         int loc_Color_Pants;
1181         int loc_Color_Shirt;
1182         int loc_FogRangeRecip;
1183         int loc_AmbientScale;
1184         int loc_DiffuseScale;
1185         int loc_SpecularScale;
1186         int loc_SpecularPower;
1187         int loc_GlowScale;
1188         int loc_SceneBrightness; // or: Scenebrightness * ContrastBoost
1189         int loc_OffsetMapping_Scale;
1190         int loc_TintColor;
1191         int loc_AmbientColor;
1192         int loc_DiffuseColor;
1193         int loc_SpecularColor;
1194         int loc_LightDir;
1195         int loc_ContrastBoostCoeff; // 1 - 1/ContrastBoost
1196         int loc_GammaCoeff; // 1 / gamma
1197         int loc_DistortScaleRefractReflect;
1198         int loc_ScreenScaleRefractReflect;
1199         int loc_ScreenCenterRefractReflect;
1200         int loc_RefractColor;
1201         int loc_ReflectColor;
1202         int loc_ReflectFactor;
1203         int loc_ReflectOffset;
1204         int loc_UserVec1;
1205         int loc_UserVec2;
1206         int loc_UserVec3;
1207         int loc_UserVec4;
1208         int loc_ClientTime;
1209 }
1210 r_glsl_permutation_t;
1211
1212 // information about each possible shader permutation
1213 r_glsl_permutation_t r_glsl_permutations[SHADERMODE_COUNT][SHADERPERMUTATION_LIMIT];
1214 // currently selected permutation
1215 r_glsl_permutation_t *r_glsl_permutation;
1216
1217 static char *R_GLSL_GetText(const char *filename, qboolean printfromdisknotice)
1218 {
1219         char *shaderstring;
1220         if (!filename || !filename[0])
1221                 return NULL;
1222         shaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL);
1223         if (shaderstring)
1224         {
1225                 if (printfromdisknotice)
1226                         Con_DPrint("from disk... ");
1227                 return shaderstring;
1228         }
1229         else if (!strcmp(filename, "glsl/default.glsl"))
1230         {
1231                 shaderstring = Mem_Alloc(r_main_mempool, strlen(builtinshaderstring) + 1);
1232                 memcpy(shaderstring, builtinshaderstring, strlen(builtinshaderstring) + 1);
1233         }
1234         return shaderstring;
1235 }
1236
1237 static void R_GLSL_CompilePermutation(shadermode_t mode, shaderpermutation_t permutation)
1238 {
1239         int i;
1240         shadermodeinfo_t *modeinfo = shadermodeinfo + mode;
1241         r_glsl_permutation_t *p = &r_glsl_permutations[mode][permutation];
1242         int vertstrings_count = 0;
1243         int geomstrings_count = 0;
1244         int fragstrings_count = 0;
1245         char *vertexstring, *geometrystring, *fragmentstring;
1246         const char *vertstrings_list[32+3];
1247         const char *geomstrings_list[32+3];
1248         const char *fragstrings_list[32+3];
1249         char permutationname[256];
1250
1251         if (p->compiled)
1252                 return;
1253         p->compiled = true;
1254         p->program = 0;
1255
1256         permutationname[0] = 0;
1257         vertexstring   = R_GLSL_GetText(modeinfo->vertexfilename, true);
1258         geometrystring = R_GLSL_GetText(modeinfo->geometryfilename, false);
1259         fragmentstring = R_GLSL_GetText(modeinfo->fragmentfilename, false);
1260
1261         strlcat(permutationname, shadermodeinfo[mode].vertexfilename, sizeof(permutationname));
1262
1263         // the first pretext is which type of shader to compile as
1264         // (later these will all be bound together as a program object)
1265         vertstrings_list[vertstrings_count++] = "#define VERTEX_SHADER\n";
1266         geomstrings_list[geomstrings_count++] = "#define GEOMETRY_SHADER\n";
1267         fragstrings_list[fragstrings_count++] = "#define FRAGMENT_SHADER\n";
1268
1269         // the second pretext is the mode (for example a light source)
1270         vertstrings_list[vertstrings_count++] = shadermodeinfo[mode].pretext;
1271         geomstrings_list[geomstrings_count++] = shadermodeinfo[mode].pretext;
1272         fragstrings_list[fragstrings_count++] = shadermodeinfo[mode].pretext;
1273         strlcat(permutationname, modeinfo->name, sizeof(permutationname));
1274
1275         // now add all the permutation pretexts
1276         for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1277         {
1278                 if (permutation & (1<<i))
1279                 {
1280                         vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i].pretext;
1281                         geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i].pretext;
1282                         fragstrings_list[fragstrings_count++] = shaderpermutationinfo[i].pretext;
1283                         strlcat(permutationname, shaderpermutationinfo[i].name, sizeof(permutationname));
1284                 }
1285                 else
1286                 {
1287                         // keep line numbers correct
1288                         vertstrings_list[vertstrings_count++] = "\n";
1289                         geomstrings_list[geomstrings_count++] = "\n";
1290                         fragstrings_list[fragstrings_count++] = "\n";
1291                 }
1292         }
1293
1294         // now append the shader text itself
1295         vertstrings_list[vertstrings_count++] = vertexstring;
1296         geomstrings_list[geomstrings_count++] = geometrystring;
1297         fragstrings_list[fragstrings_count++] = fragmentstring;
1298
1299         // if any sources were NULL, clear the respective list
1300         if (!vertexstring)
1301                 vertstrings_count = 0;
1302         if (!geometrystring)
1303                 geomstrings_count = 0;
1304         if (!fragmentstring)
1305                 fragstrings_count = 0;
1306
1307         // compile the shader program
1308         if (vertstrings_count + geomstrings_count + fragstrings_count)
1309                 p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
1310         if (p->program)
1311         {
1312                 CHECKGLERROR
1313                 qglUseProgramObjectARB(p->program);CHECKGLERROR
1314                 // look up all the uniform variable names we care about, so we don't
1315                 // have to look them up every time we set them
1316                 p->loc_Texture_First              = qglGetUniformLocationARB(p->program, "Texture_First");
1317                 p->loc_Texture_Second             = qglGetUniformLocationARB(p->program, "Texture_Second");
1318                 p->loc_Texture_Normal             = qglGetUniformLocationARB(p->program, "Texture_Normal");
1319                 p->loc_Texture_Color              = qglGetUniformLocationARB(p->program, "Texture_Color");
1320                 p->loc_Texture_Gloss              = qglGetUniformLocationARB(p->program, "Texture_Gloss");
1321                 p->loc_Texture_Glow               = qglGetUniformLocationARB(p->program, "Texture_Glow");
1322                 p->loc_Texture_SecondaryNormal    = qglGetUniformLocationARB(p->program, "Texture_SecondaryNormal");
1323                 p->loc_Texture_SecondaryColor     = qglGetUniformLocationARB(p->program, "Texture_SecondaryColor");
1324                 p->loc_Texture_SecondaryGloss     = qglGetUniformLocationARB(p->program, "Texture_SecondaryGloss");
1325                 p->loc_Texture_SecondaryGlow      = qglGetUniformLocationARB(p->program, "Texture_SecondaryGlow");
1326                 p->loc_Texture_FogMask            = qglGetUniformLocationARB(p->program, "Texture_FogMask");
1327                 p->loc_Texture_Pants              = qglGetUniformLocationARB(p->program, "Texture_Pants");
1328                 p->loc_Texture_Shirt              = qglGetUniformLocationARB(p->program, "Texture_Shirt");
1329                 p->loc_Texture_Lightmap           = qglGetUniformLocationARB(p->program, "Texture_Lightmap");
1330                 p->loc_Texture_Deluxemap          = qglGetUniformLocationARB(p->program, "Texture_Deluxemap");
1331                 p->loc_Texture_Refraction         = qglGetUniformLocationARB(p->program, "Texture_Refraction");
1332                 p->loc_Texture_Reflection         = qglGetUniformLocationARB(p->program, "Texture_Reflection");
1333                 p->loc_Texture_Attenuation        = qglGetUniformLocationARB(p->program, "Texture_Attenuation");
1334                 p->loc_Texture_Cube               = qglGetUniformLocationARB(p->program, "Texture_Cube");
1335                 p->loc_FogColor                   = qglGetUniformLocationARB(p->program, "FogColor");
1336                 p->loc_LightPosition              = qglGetUniformLocationARB(p->program, "LightPosition");
1337                 p->loc_EyePosition                = qglGetUniformLocationARB(p->program, "EyePosition");
1338                 p->loc_Color_Pants                = qglGetUniformLocationARB(p->program, "Color_Pants");
1339                 p->loc_Color_Shirt                = qglGetUniformLocationARB(p->program, "Color_Shirt");
1340                 p->loc_FogRangeRecip              = qglGetUniformLocationARB(p->program, "FogRangeRecip");
1341                 p->loc_AmbientScale               = qglGetUniformLocationARB(p->program, "AmbientScale");
1342                 p->loc_DiffuseScale               = qglGetUniformLocationARB(p->program, "DiffuseScale");
1343                 p->loc_SpecularPower              = qglGetUniformLocationARB(p->program, "SpecularPower");
1344                 p->loc_SpecularScale              = qglGetUniformLocationARB(p->program, "SpecularScale");
1345                 p->loc_GlowScale                  = qglGetUniformLocationARB(p->program, "GlowScale");
1346                 p->loc_SceneBrightness            = qglGetUniformLocationARB(p->program, "SceneBrightness");
1347                 p->loc_OffsetMapping_Scale        = qglGetUniformLocationARB(p->program, "OffsetMapping_Scale");
1348                 p->loc_TintColor                  = qglGetUniformLocationARB(p->program, "TintColor");
1349                 p->loc_AmbientColor               = qglGetUniformLocationARB(p->program, "AmbientColor");
1350                 p->loc_DiffuseColor               = qglGetUniformLocationARB(p->program, "DiffuseColor");
1351                 p->loc_SpecularColor              = qglGetUniformLocationARB(p->program, "SpecularColor");
1352                 p->loc_LightDir                   = qglGetUniformLocationARB(p->program, "LightDir");
1353                 p->loc_ContrastBoostCoeff         = qglGetUniformLocationARB(p->program, "ContrastBoostCoeff");
1354                 p->loc_DistortScaleRefractReflect = qglGetUniformLocationARB(p->program, "DistortScaleRefractReflect");
1355                 p->loc_ScreenScaleRefractReflect  = qglGetUniformLocationARB(p->program, "ScreenScaleRefractReflect");
1356                 p->loc_ScreenCenterRefractReflect = qglGetUniformLocationARB(p->program, "ScreenCenterRefractReflect");
1357                 p->loc_RefractColor               = qglGetUniformLocationARB(p->program, "RefractColor");
1358                 p->loc_ReflectColor               = qglGetUniformLocationARB(p->program, "ReflectColor");
1359                 p->loc_ReflectFactor              = qglGetUniformLocationARB(p->program, "ReflectFactor");
1360                 p->loc_ReflectOffset              = qglGetUniformLocationARB(p->program, "ReflectOffset");
1361                 p->loc_GammaCoeff                 = qglGetUniformLocationARB(p->program, "GammaCoeff");
1362                 p->loc_UserVec1                   = qglGetUniformLocationARB(p->program, "UserVec1");
1363                 p->loc_UserVec2                   = qglGetUniformLocationARB(p->program, "UserVec2");
1364                 p->loc_UserVec3                   = qglGetUniformLocationARB(p->program, "UserVec3");
1365                 p->loc_UserVec4                   = qglGetUniformLocationARB(p->program, "UserVec4");
1366                 p->loc_ClientTime                 = qglGetUniformLocationARB(p->program, "ClientTime");
1367                 // initialize the samplers to refer to the texture units we use
1368                 if (p->loc_Texture_First           >= 0) qglUniform1iARB(p->loc_Texture_First          , GL20TU_FIRST);
1369                 if (p->loc_Texture_Second          >= 0) qglUniform1iARB(p->loc_Texture_Second         , GL20TU_SECOND);
1370                 if (p->loc_Texture_Normal          >= 0) qglUniform1iARB(p->loc_Texture_Normal         , GL20TU_NORMAL);
1371                 if (p->loc_Texture_Color           >= 0) qglUniform1iARB(p->loc_Texture_Color          , GL20TU_COLOR);
1372                 if (p->loc_Texture_Gloss           >= 0) qglUniform1iARB(p->loc_Texture_Gloss          , GL20TU_GLOSS);
1373                 if (p->loc_Texture_Glow            >= 0) qglUniform1iARB(p->loc_Texture_Glow           , GL20TU_GLOW);
1374                 if (p->loc_Texture_SecondaryNormal >= 0) qglUniform1iARB(p->loc_Texture_SecondaryNormal, GL20TU_SECONDARY_NORMAL);
1375                 if (p->loc_Texture_SecondaryColor  >= 0) qglUniform1iARB(p->loc_Texture_SecondaryColor , GL20TU_SECONDARY_COLOR);
1376                 if (p->loc_Texture_SecondaryGloss  >= 0) qglUniform1iARB(p->loc_Texture_SecondaryGloss , GL20TU_SECONDARY_GLOSS);
1377                 if (p->loc_Texture_SecondaryGlow   >= 0) qglUniform1iARB(p->loc_Texture_SecondaryGlow  , GL20TU_SECONDARY_GLOW);
1378                 if (p->loc_Texture_Pants           >= 0) qglUniform1iARB(p->loc_Texture_Pants          , GL20TU_PANTS);
1379                 if (p->loc_Texture_Shirt           >= 0) qglUniform1iARB(p->loc_Texture_Shirt          , GL20TU_SHIRT);
1380                 if (p->loc_Texture_FogMask         >= 0) qglUniform1iARB(p->loc_Texture_FogMask        , GL20TU_FOGMASK);
1381                 if (p->loc_Texture_Lightmap        >= 0) qglUniform1iARB(p->loc_Texture_Lightmap       , GL20TU_LIGHTMAP);
1382                 if (p->loc_Texture_Deluxemap       >= 0) qglUniform1iARB(p->loc_Texture_Deluxemap      , GL20TU_DELUXEMAP);
1383                 if (p->loc_Texture_Attenuation     >= 0) qglUniform1iARB(p->loc_Texture_Attenuation    , GL20TU_ATTENUATION);
1384                 if (p->loc_Texture_Cube            >= 0) qglUniform1iARB(p->loc_Texture_Cube           , GL20TU_CUBE);
1385                 if (p->loc_Texture_Refraction      >= 0) qglUniform1iARB(p->loc_Texture_Refraction     , GL20TU_REFRACTION);
1386                 if (p->loc_Texture_Reflection      >= 0) qglUniform1iARB(p->loc_Texture_Reflection     , GL20TU_REFLECTION);
1387                 CHECKGLERROR
1388                 if (developer.integer)
1389                         Con_Printf("GLSL shader %s compiled.\n", permutationname);
1390         }
1391         else
1392                 Con_Printf("GLSL shader %s failed!  some features may not work properly.\n", permutationname);
1393
1394         // free the strings
1395         if (vertexstring)
1396                 Mem_Free(vertexstring);
1397         if (geometrystring)
1398                 Mem_Free(geometrystring);
1399         if (fragmentstring)
1400                 Mem_Free(fragmentstring);
1401 }
1402
1403 void R_GLSL_Restart_f(void)
1404 {
1405         shadermode_t mode;
1406         shaderpermutation_t permutation;
1407         for (mode = 0;mode < SHADERMODE_COUNT;mode++)
1408                 for (permutation = 0;permutation < SHADERPERMUTATION_LIMIT;permutation++)
1409                         if (r_glsl_permutations[mode][permutation].program)
1410                                 GL_Backend_FreeProgram(r_glsl_permutations[mode][permutation].program);
1411         memset(r_glsl_permutations, 0, sizeof(r_glsl_permutations));
1412 }
1413
1414 void R_GLSL_DumpShader_f(void)
1415 {
1416         int i;
1417
1418         qfile_t *file = FS_Open("glsl/default.glsl", "w", false, false);
1419         if(!file)
1420         {
1421                 Con_Printf("failed to write to glsl/default.glsl\n");
1422                 return;
1423         }
1424
1425         FS_Print(file, "// The engine may define the following macros:\n");
1426         FS_Print(file, "// #define VERTEX_SHADER\n// #define GEOMETRY_SHADER\n// #define FRAGMENT_SHADER\n");
1427         for (i = 0;i < SHADERMODE_COUNT;i++)
1428                 FS_Printf(file, "// %s", shadermodeinfo[i].pretext);
1429         for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1430                 FS_Printf(file, "// %s", shaderpermutationinfo[i].pretext);
1431         FS_Print(file, "\n");
1432         FS_Print(file, builtinshaderstring);
1433         FS_Close(file);
1434
1435         Con_Printf("glsl/default.glsl written\n");
1436 }
1437
1438 void R_SetupShader_SetPermutation(shadermode_t mode, unsigned int permutation)
1439 {
1440         r_glsl_permutation_t *perm = &r_glsl_permutations[mode][permutation];
1441         if (r_glsl_permutation != perm)
1442         {
1443                 r_glsl_permutation = perm;
1444                 if (!r_glsl_permutation->program)
1445                 {
1446                         if (!r_glsl_permutation->compiled)
1447                                 R_GLSL_CompilePermutation(mode, permutation);
1448                         if (!r_glsl_permutation->program)
1449                         {
1450                                 // remove features until we find a valid permutation
1451                                 int i;
1452                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1453                                 {
1454                                         // reduce i more quickly whenever it would not remove any bits
1455                                         int j = 1<<(SHADERPERMUTATION_COUNT-1-i);
1456                                         if (!(permutation & j))
1457                                                 continue;
1458                                         permutation -= j;
1459                                         r_glsl_permutation = &r_glsl_permutations[mode][permutation];
1460                                         if (!r_glsl_permutation->compiled)
1461                                                 R_GLSL_CompilePermutation(mode, permutation);
1462                                         if (r_glsl_permutation->program)
1463                                                 break;
1464                                 }
1465                                 if (i >= SHADERPERMUTATION_COUNT)
1466                                 {
1467                                         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");
1468                                         Cvar_SetValueQuick(&r_glsl, 0);
1469                                         R_GLSL_Restart_f(); // unload shaders
1470                                         return; // no bit left to clear
1471                                 }
1472                         }
1473                 }
1474                 CHECKGLERROR
1475                 qglUseProgramObjectARB(r_glsl_permutation->program);CHECKGLERROR
1476         }
1477 }
1478
1479 void R_SetupGenericShader(qboolean usetexture)
1480 {
1481         if (gl_support_fragment_shader)
1482         {
1483                 if (r_glsl.integer && r_glsl_usegeneric.integer)
1484                         R_SetupShader_SetPermutation(SHADERMODE_GENERIC, usetexture ? SHADERPERMUTATION_DIFFUSE : 0);
1485                 else if (r_glsl_permutation)
1486                 {
1487                         r_glsl_permutation = NULL;
1488                         qglUseProgramObjectARB(0);CHECKGLERROR
1489                 }
1490         }
1491 }
1492
1493 void R_SetupGenericTwoTextureShader(int texturemode)
1494 {
1495         if (gl_support_fragment_shader)
1496         {
1497                 if (r_glsl.integer && r_glsl_usegeneric.integer)
1498                         R_SetupShader_SetPermutation(SHADERMODE_GENERIC, SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_SPECULAR | (texturemode == GL_MODULATE ? SHADERPERMUTATION_COLORMAPPING : (texturemode == GL_ADD ? SHADERPERMUTATION_GLOW : (texturemode == GL_DECAL ? SHADERPERMUTATION_VERTEXTEXTUREBLEND : 0))));
1499                 else if (r_glsl_permutation)
1500                 {
1501                         r_glsl_permutation = NULL;
1502                         qglUseProgramObjectARB(0);CHECKGLERROR
1503                 }
1504         }
1505         if (!r_glsl_permutation)
1506         {
1507                 if (texturemode == GL_DECAL && gl_combine.integer)
1508                         texturemode = GL_INTERPOLATE_ARB;
1509                 R_Mesh_TexCombine(1, texturemode, texturemode, 1, 1);
1510         }
1511 }
1512
1513 void R_SetupDepthOrShadowShader(void)
1514 {
1515         if (gl_support_fragment_shader)
1516         {
1517                 if (r_glsl.integer && r_glsl_usegeneric.integer)
1518                         R_SetupShader_SetPermutation(SHADERMODE_DEPTH_OR_SHADOW, 0);
1519                 else if (r_glsl_permutation)
1520                 {
1521                         r_glsl_permutation = NULL;
1522                         qglUseProgramObjectARB(0);CHECKGLERROR
1523                 }
1524         }
1525 }
1526
1527 extern rtexture_t *r_shadow_attenuationgradienttexture;
1528 extern rtexture_t *r_shadow_attenuation2dtexture;
1529 extern rtexture_t *r_shadow_attenuation3dtexture;
1530 void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, float ambientscale, float diffusescale, float specularscale, rsurfacepass_t rsurfacepass)
1531 {
1532         // select a permutation of the lighting shader appropriate to this
1533         // combination of texture, entity, light source, and fogging, only use the
1534         // minimum features necessary to avoid wasting rendering time in the
1535         // fragment shader on features that are not being used
1536         unsigned int permutation = 0;
1537         shadermode_t mode = 0;
1538         // TODO: implement geometry-shader based shadow volumes someday
1539         if (r_glsl_offsetmapping.integer)
1540         {
1541                 permutation |= SHADERPERMUTATION_OFFSETMAPPING;
1542                 if (r_glsl_offsetmapping_reliefmapping.integer)
1543                         permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
1544         }
1545         if (rsurfacepass == RSURFPASS_BACKGROUND)
1546         {
1547                 // distorted background
1548                 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1549                         mode = SHADERMODE_WATER;
1550                 else
1551                         mode = SHADERMODE_REFRACTION;
1552         }
1553         else if (rsurfacepass == RSURFPASS_RTLIGHT)
1554         {
1555                 // light source
1556                 mode = SHADERMODE_LIGHTSOURCE;
1557                 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1558                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1559                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1560                         permutation |= SHADERPERMUTATION_CUBEFILTER;
1561                 if (diffusescale > 0)
1562                         permutation |= SHADERPERMUTATION_DIFFUSE;
1563                 if (specularscale > 0)
1564                         permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1565                 if (r_refdef.fogenabled)
1566                         permutation |= SHADERPERMUTATION_FOG;
1567                 if (rsurface.texture->colormapping)
1568                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1569                 if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
1570                         permutation |= SHADERPERMUTATION_CONTRASTBOOST;
1571         }
1572         else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
1573         {
1574                 // unshaded geometry (fullbright or ambient model lighting)
1575                 mode = SHADERMODE_FLATCOLOR;
1576                 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1577                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1578                 if (rsurface.texture->currentskinframe->glow && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1579                         permutation |= SHADERPERMUTATION_GLOW;
1580                 if (r_refdef.fogenabled)
1581                         permutation |= SHADERPERMUTATION_FOG;
1582                 if (rsurface.texture->colormapping)
1583                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1584                 if (r_glsl_offsetmapping.integer)
1585                 {
1586                         permutation |= SHADERPERMUTATION_OFFSETMAPPING;
1587                         if (r_glsl_offsetmapping_reliefmapping.integer)
1588                                 permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
1589                 }
1590                 if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
1591                         permutation |= SHADERPERMUTATION_CONTRASTBOOST;
1592                 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
1593                         permutation |= SHADERPERMUTATION_REFLECTION;
1594         }
1595         else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT_DIRECTIONAL)
1596         {
1597                 // directional model lighting
1598                 mode = SHADERMODE_LIGHTDIRECTION;
1599                 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1600                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1601                 if (rsurface.texture->currentskinframe->glow && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1602                         permutation |= SHADERPERMUTATION_GLOW;
1603                 permutation |= SHADERPERMUTATION_DIFFUSE;
1604                 if (specularscale > 0)
1605                         permutation |= SHADERPERMUTATION_SPECULAR;
1606                 if (r_refdef.fogenabled)
1607                         permutation |= SHADERPERMUTATION_FOG;
1608                 if (rsurface.texture->colormapping)
1609                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1610                 if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
1611                         permutation |= SHADERPERMUTATION_CONTRASTBOOST;
1612                 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
1613                         permutation |= SHADERPERMUTATION_REFLECTION;
1614         }
1615         else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
1616         {
1617                 // ambient model lighting
1618                 mode = SHADERMODE_LIGHTDIRECTION;
1619                 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1620                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1621                 if (rsurface.texture->currentskinframe->glow && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1622                         permutation |= SHADERPERMUTATION_GLOW;
1623                 if (r_refdef.fogenabled)
1624                         permutation |= SHADERPERMUTATION_FOG;
1625                 if (rsurface.texture->colormapping)
1626                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1627                 if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
1628                         permutation |= SHADERPERMUTATION_CONTRASTBOOST;
1629                 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
1630                         permutation |= SHADERPERMUTATION_REFLECTION;
1631         }
1632         else
1633         {
1634                 // lightmapped wall
1635                 if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping)
1636                 {
1637                         // deluxemapping (light direction texture)
1638                         if (rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping && r_refdef.scene.worldmodel->brushq3.deluxemapping_modelspace)
1639                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE;
1640                         else
1641                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1642                         permutation |= SHADERPERMUTATION_DIFFUSE;
1643                         if (specularscale > 0)
1644                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1645                 }
1646                 else if (r_glsl_deluxemapping.integer >= 2)
1647                 {
1648                         // fake deluxemapping (uniform light direction in tangentspace)
1649                         mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1650                         permutation |= SHADERPERMUTATION_DIFFUSE;
1651                         if (specularscale > 0)
1652                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1653                 }
1654                 else if (rsurface.uselightmaptexture)
1655                 {
1656                         // ordinary lightmapping (q1bsp, q3bsp)
1657                         mode = SHADERMODE_LIGHTMAP;
1658                 }
1659                 else
1660                 {
1661                         // ordinary vertex coloring (q3bsp)
1662                         mode = SHADERMODE_VERTEXCOLOR;
1663                 }
1664                 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1665                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1666                 if (rsurface.texture->currentskinframe->glow && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1667                         permutation |= SHADERPERMUTATION_GLOW;
1668                 if (r_refdef.fogenabled)
1669                         permutation |= SHADERPERMUTATION_FOG;
1670                 if (rsurface.texture->colormapping)
1671                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1672                 if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
1673                         permutation |= SHADERPERMUTATION_CONTRASTBOOST;
1674                 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
1675                         permutation |= SHADERPERMUTATION_REFLECTION;
1676         }
1677         R_SetupShader_SetPermutation(mode, permutation);
1678         if (mode == SHADERMODE_LIGHTSOURCE)
1679         {
1680                 if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
1681                 if (permutation & SHADERPERMUTATION_DIFFUSE)
1682                 {
1683                         if (r_glsl_permutation->loc_TintColor >= 0) qglUniform4fARB(r_glsl_permutation->loc_TintColor, lightcolorbase[0], lightcolorbase[1], lightcolorbase[2], rsurface.texture->lightmapcolor[3]);
1684                         if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, ambientscale);
1685                         if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, diffusescale);
1686                         if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, specularscale);
1687                 }
1688                 else
1689                 {
1690                         // ambient only is simpler
1691                         if (r_glsl_permutation->loc_TintColor >= 0) qglUniform4fARB(r_glsl_permutation->loc_TintColor, lightcolorbase[0] * ambientscale, lightcolorbase[1] * ambientscale, lightcolorbase[2] * ambientscale, rsurface.texture->lightmapcolor[3]);
1692                         if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, 1);
1693                         if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, 0);
1694                         if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, 0);
1695                 }
1696                 // additive passes are only darkened by fog, not tinted
1697                 if (r_glsl_permutation->loc_FogColor >= 0)
1698                         qglUniform3fARB(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1699         }
1700         else
1701         {
1702                 if (mode == SHADERMODE_LIGHTDIRECTION)
1703                 {
1704                         if (r_glsl_permutation->loc_AmbientColor  >= 0) qglUniform3fARB(r_glsl_permutation->loc_AmbientColor , rsurface.modellight_ambient[0] * ambientscale  * 0.5f, rsurface.modellight_ambient[1] * ambientscale  * 0.5f, rsurface.modellight_ambient[2] * ambientscale  * 0.5f);
1705                         if (r_glsl_permutation->loc_DiffuseColor  >= 0) qglUniform3fARB(r_glsl_permutation->loc_DiffuseColor , rsurface.modellight_diffuse[0] * diffusescale  * 0.5f, rsurface.modellight_diffuse[1] * diffusescale  * 0.5f, rsurface.modellight_diffuse[2] * diffusescale  * 0.5f);
1706                         if (r_glsl_permutation->loc_SpecularColor >= 0) qglUniform3fARB(r_glsl_permutation->loc_SpecularColor, rsurface.modellight_diffuse[0] * specularscale * 0.5f, rsurface.modellight_diffuse[1] * specularscale * 0.5f, rsurface.modellight_diffuse[2] * specularscale * 0.5f);
1707                         if (r_glsl_permutation->loc_LightDir      >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightDir, rsurface.modellight_lightdir[0], rsurface.modellight_lightdir[1], rsurface.modellight_lightdir[2]);
1708                 }
1709                 else
1710                 {
1711                         if (r_glsl_permutation->loc_AmbientScale  >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, r_ambient.value * 1.0f / 128.0f);
1712                         if (r_glsl_permutation->loc_DiffuseScale  >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, r_refdef.lightmapintensity);
1713                         if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, r_refdef.lightmapintensity * specularscale);
1714                 }
1715                 if (r_glsl_permutation->loc_TintColor >= 0) qglUniform4fARB(r_glsl_permutation->loc_TintColor, rsurface.texture->lightmapcolor[0], rsurface.texture->lightmapcolor[1], rsurface.texture->lightmapcolor[2], rsurface.texture->lightmapcolor[3]);
1716                 if (r_glsl_permutation->loc_GlowScale     >= 0) qglUniform1fARB(r_glsl_permutation->loc_GlowScale, r_hdr_glowintensity.value);
1717                 // additive passes are only darkened by fog, not tinted
1718                 if (r_glsl_permutation->loc_FogColor >= 0)
1719                 {
1720                         if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ADD)
1721                                 qglUniform3fARB(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1722                         else
1723                                 qglUniform3fARB(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1724                 }
1725                 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);
1726                 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]);
1727                 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]);
1728                 if (r_glsl_permutation->loc_RefractColor >= 0) qglUniform4fvARB(r_glsl_permutation->loc_RefractColor, 1, rsurface.texture->refractcolor4f);
1729                 if (r_glsl_permutation->loc_ReflectColor >= 0) qglUniform4fvARB(r_glsl_permutation->loc_ReflectColor, 1, rsurface.texture->reflectcolor4f);
1730                 if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1fARB(r_glsl_permutation->loc_ReflectFactor, rsurface.texture->reflectmax - rsurface.texture->reflectmin);
1731                 if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1fARB(r_glsl_permutation->loc_ReflectOffset, rsurface.texture->reflectmin);
1732         }
1733         if (r_glsl_permutation->loc_ContrastBoostCoeff >= 0)
1734         {
1735                 // The formula used is actually:
1736                 //   color.rgb *= ContrastBoost / ((ContrastBoost - 1) * color.rgb + 1);
1737                 //   color.rgb *= SceneBrightness;
1738                 // simplified:
1739                 //   color.rgb = [[SceneBrightness * ContrastBoost]] * color.rgb / ([[ContrastBoost - 1]] * color.rgb + 1);
1740                 // and do [[calculations]] here in the engine
1741                 qglUniform1fARB(r_glsl_permutation->loc_ContrastBoostCoeff, r_glsl_contrastboost.value - 1);
1742                 if (r_glsl_permutation->loc_SceneBrightness >= 0) qglUniform1fARB(r_glsl_permutation->loc_SceneBrightness, r_refdef.view.colorscale * r_glsl_contrastboost.value);
1743         }
1744         else
1745                 if (r_glsl_permutation->loc_SceneBrightness >= 0) qglUniform1fARB(r_glsl_permutation->loc_SceneBrightness, r_refdef.view.colorscale);
1746         if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_EyePosition, rsurface.modelorg[0], rsurface.modelorg[1], rsurface.modelorg[2]);
1747         if (r_glsl_permutation->loc_Color_Pants >= 0)
1748         {
1749                 if (rsurface.texture->currentskinframe->pants)
1750                         qglUniform3fARB(r_glsl_permutation->loc_Color_Pants, rsurface.colormap_pantscolor[0], rsurface.colormap_pantscolor[1], rsurface.colormap_pantscolor[2]);
1751                 else
1752                         qglUniform3fARB(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
1753         }
1754         if (r_glsl_permutation->loc_Color_Shirt >= 0)
1755         {
1756                 if (rsurface.texture->currentskinframe->shirt)
1757                         qglUniform3fARB(r_glsl_permutation->loc_Color_Shirt, rsurface.colormap_shirtcolor[0], rsurface.colormap_shirtcolor[1], rsurface.colormap_shirtcolor[2]);
1758                 else
1759                         qglUniform3fARB(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
1760         }
1761         if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1fARB(r_glsl_permutation->loc_FogRangeRecip, r_refdef.fograngerecip);
1762         if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularPower, rsurface.texture->specularpower);
1763         if (r_glsl_permutation->loc_OffsetMapping_Scale >= 0) qglUniform1fARB(r_glsl_permutation->loc_OffsetMapping_Scale, r_glsl_offsetmapping_scale.value);
1764         CHECKGLERROR
1765 }
1766
1767 #define SKINFRAME_HASH 1024
1768
1769 struct
1770 {
1771         int loadsequence; // incremented each level change
1772         memexpandablearray_t array;
1773         skinframe_t *hash[SKINFRAME_HASH];
1774 }
1775 r_skinframe;
1776
1777 void R_SkinFrame_PrepareForPurge(void)
1778 {
1779         r_skinframe.loadsequence++;
1780         // wrap it without hitting zero
1781         if (r_skinframe.loadsequence >= 200)
1782                 r_skinframe.loadsequence = 1;
1783 }
1784
1785 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
1786 {
1787         if (!skinframe)
1788                 return;
1789         // mark the skinframe as used for the purging code
1790         skinframe->loadsequence = r_skinframe.loadsequence;
1791 }
1792
1793 void R_SkinFrame_Purge(void)
1794 {
1795         int i;
1796         skinframe_t *s;
1797         for (i = 0;i < SKINFRAME_HASH;i++)
1798         {
1799                 for (s = r_skinframe.hash[i];s;s = s->next)
1800                 {
1801                         if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
1802                         {
1803                                 if (s->merged == s->base)
1804                                         s->merged = NULL;
1805                                 // FIXME: maybe pass a pointer to the pointer to R_PurgeTexture and reset it to NULL inside? [11/29/2007 Black]
1806                                 R_PurgeTexture(s->stain );s->stain  = NULL;
1807                                 R_PurgeTexture(s->merged);s->merged = NULL;
1808                                 R_PurgeTexture(s->base  );s->base   = NULL;
1809                                 R_PurgeTexture(s->pants );s->pants  = NULL;
1810                                 R_PurgeTexture(s->shirt );s->shirt  = NULL;
1811                                 R_PurgeTexture(s->nmap  );s->nmap   = NULL;
1812                                 R_PurgeTexture(s->gloss );s->gloss  = NULL;
1813                                 R_PurgeTexture(s->glow  );s->glow   = NULL;
1814                                 R_PurgeTexture(s->fog   );s->fog    = NULL;
1815                                 s->loadsequence = 0;
1816                         }
1817                 }
1818         }
1819 }
1820
1821 skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name ) {
1822         skinframe_t *item;
1823         char basename[MAX_QPATH];
1824
1825         Image_StripImageExtension(name, basename, sizeof(basename));
1826
1827         if( last == NULL ) {
1828                 int hashindex;
1829                 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
1830                 item = r_skinframe.hash[hashindex];
1831         } else {
1832                 item = last->next;
1833         }
1834
1835         // linearly search through the hash bucket
1836         for( ; item ; item = item->next ) {
1837                 if( !strcmp( item->basename, basename ) ) {
1838                         return item;
1839                 }
1840         }
1841         return NULL;
1842 }
1843
1844 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qboolean add)
1845 {
1846         skinframe_t *item;
1847         int hashindex;
1848         char basename[MAX_QPATH];
1849
1850         Image_StripImageExtension(name, basename, sizeof(basename));
1851
1852         hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
1853         for (item = r_skinframe.hash[hashindex];item;item = item->next)
1854                 if (!strcmp(item->basename, basename) && item->textureflags == textureflags && item->comparewidth == comparewidth && item->compareheight == compareheight && item->comparecrc == comparecrc)
1855                         break;
1856
1857         if (!item) {
1858                 rtexture_t *dyntexture;
1859                 // check whether its a dynamic texture
1860                 dyntexture = CL_GetDynTexture( basename );
1861                 if (!add && !dyntexture)
1862                         return NULL;
1863                 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
1864                 memset(item, 0, sizeof(*item));
1865                 strlcpy(item->basename, basename, sizeof(item->basename));
1866                 item->base = dyntexture; // either NULL or dyntexture handle
1867                 item->textureflags = textureflags;
1868                 item->comparewidth = comparewidth;
1869                 item->compareheight = compareheight;
1870                 item->comparecrc = comparecrc;
1871                 item->next = r_skinframe.hash[hashindex];
1872                 r_skinframe.hash[hashindex] = item;
1873         }
1874         else if( item->base == NULL )
1875         {
1876                 rtexture_t *dyntexture;
1877                 // check whether its a dynamic texture
1878                 // 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]
1879                 dyntexture = CL_GetDynTexture( basename );
1880                 item->base = dyntexture; // either NULL or dyntexture handle
1881         }
1882
1883         R_SkinFrame_MarkUsed(item);
1884         return item;
1885 }
1886
1887 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain)
1888 {
1889         // FIXME: it should be possible to disable loading various layers using
1890         // cvars, to prevent wasted loading time and memory usage if the user does
1891         // not want them
1892         qboolean loadnormalmap = true;
1893         qboolean loadgloss = true;
1894         qboolean loadpantsandshirt = true;
1895         qboolean loadglow = true;
1896         int j;
1897         unsigned char *pixels;
1898         unsigned char *bumppixels;
1899         unsigned char *basepixels = NULL;
1900         int basepixels_width;
1901         int basepixels_height;
1902         skinframe_t *skinframe;
1903
1904         if (cls.state == ca_dedicated)
1905                 return NULL;
1906
1907         // return an existing skinframe if already loaded
1908         // if loading of the first image fails, don't make a new skinframe as it
1909         // would cause all future lookups of this to be missing
1910         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
1911         if (skinframe && skinframe->base)
1912                 return skinframe;
1913
1914         basepixels = loadimagepixelsbgra(name, complain, true);
1915         if (basepixels == NULL)
1916                 return NULL;
1917
1918         // we've got some pixels to store, so really allocate this new texture now
1919         if (!skinframe)
1920                 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
1921         skinframe->stain = NULL;
1922         skinframe->merged = NULL;
1923         skinframe->base = r_texture_notexture;
1924         skinframe->pants = NULL;
1925         skinframe->shirt = NULL;
1926         skinframe->nmap = r_texture_blanknormalmap;
1927         skinframe->gloss = NULL;
1928         skinframe->glow = NULL;
1929         skinframe->fog = NULL;
1930
1931         basepixels_width = image_width;
1932         basepixels_height = image_height;
1933         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);
1934
1935         if (textureflags & TEXF_ALPHA)
1936         {
1937                 for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
1938                         if (basepixels[j] < 255)
1939                                 break;
1940                 if (j < basepixels_width * basepixels_height * 4)
1941                 {
1942                         // has transparent pixels
1943                         pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
1944                         for (j = 0;j < image_width * image_height * 4;j += 4)
1945                         {
1946                                 pixels[j+0] = 255;
1947                                 pixels[j+1] = 255;
1948                                 pixels[j+2] = 255;
1949                                 pixels[j+3] = basepixels[j+3];
1950                         }
1951                         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);
1952                         Mem_Free(pixels);
1953                 }
1954         }
1955
1956         // _norm is the name used by tenebrae and has been adopted as standard
1957         if (loadnormalmap)
1958         {
1959                 if ((pixels = loadimagepixelsbgra(va("%s_norm", skinframe->basename), false, false)) != NULL)
1960                 {
1961                         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);
1962                         Mem_Free(pixels);
1963                         pixels = NULL;
1964                 }
1965                 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va("%s_bump", skinframe->basename), false, false)) != NULL)
1966                 {
1967                         pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
1968                         Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
1969                         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);
1970                         Mem_Free(pixels);
1971                         Mem_Free(bumppixels);
1972                 }
1973                 else if (r_shadow_bumpscale_basetexture.value > 0)
1974                 {
1975                         pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
1976                         Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
1977                         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);
1978                         Mem_Free(pixels);
1979                 }
1980         }
1981         // _luma is supported for tenebrae compatibility
1982         // (I think it's a very stupid name, but oh well)
1983         // _glow is the preferred name
1984         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;}
1985         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;}
1986         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;}
1987         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;}
1988
1989         if (basepixels)
1990                 Mem_Free(basepixels);
1991
1992         return skinframe;
1993 }
1994
1995 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)
1996 {
1997         int i;
1998         if (!force)
1999         {
2000                 for (i = 0;i < width*height;i++)
2001                         if (((unsigned char *)&palette[in[i]])[3] > 0)
2002                                 break;
2003                 if (i == width*height)
2004                         return NULL;
2005         }
2006         return R_LoadTexture2D (r_main_texturepool, name, width, height, in, TEXTYPE_PALETTE, textureflags, palette);
2007 }
2008
2009 // this is only used by .spr32 sprites, HL .spr files, HL .bsp files
2010 skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height)
2011 {
2012         int i;
2013         unsigned char *temp1, *temp2;
2014         skinframe_t *skinframe;
2015
2016         if (cls.state == ca_dedicated)
2017                 return NULL;
2018
2019         // if already loaded just return it, otherwise make a new skinframe
2020         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height*4) : 0, true);
2021         if (skinframe && skinframe->base)
2022                 return skinframe;
2023
2024         skinframe->stain = NULL;
2025         skinframe->merged = NULL;
2026         skinframe->base = r_texture_notexture;
2027         skinframe->pants = NULL;
2028         skinframe->shirt = NULL;
2029         skinframe->nmap = r_texture_blanknormalmap;
2030         skinframe->gloss = NULL;
2031         skinframe->glow = NULL;
2032         skinframe->fog = NULL;
2033
2034         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2035         if (!skindata)
2036                 return NULL;
2037
2038         if (r_shadow_bumpscale_basetexture.value > 0)
2039         {
2040                 temp1 = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2041                 temp2 = temp1 + width * height * 4;
2042                 Image_HeightmapToNormalmap_BGRA(skindata, temp2, width, height, false, r_shadow_bumpscale_basetexture.value);
2043                 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va("%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_BGRA, skinframe->textureflags | TEXF_ALPHA, NULL);
2044                 Mem_Free(temp1);
2045         }
2046         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_BGRA, skinframe->textureflags, NULL);
2047         if (textureflags & TEXF_ALPHA)
2048         {
2049                 for (i = 3;i < width * height * 4;i += 4)
2050                         if (skindata[i] < 255)
2051                                 break;
2052                 if (i < width * height * 4)
2053                 {
2054                         unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
2055                         memcpy(fogpixels, skindata, width * height * 4);
2056                         for (i = 0;i < width * height * 4;i += 4)
2057                                 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
2058                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va("%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, skinframe->textureflags, NULL);
2059                         Mem_Free(fogpixels);
2060                 }
2061         }
2062
2063         return skinframe;
2064 }
2065
2066 skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height)
2067 {
2068         int i;
2069         unsigned char *temp1, *temp2;
2070         skinframe_t *skinframe;
2071
2072         if (cls.state == ca_dedicated)
2073                 return NULL;
2074
2075         // if already loaded just return it, otherwise make a new skinframe
2076         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2077         if (skinframe && skinframe->base)
2078                 return skinframe;
2079
2080         skinframe->stain = NULL;
2081         skinframe->merged = NULL;
2082         skinframe->base = r_texture_notexture;
2083         skinframe->pants = NULL;
2084         skinframe->shirt = NULL;
2085         skinframe->nmap = r_texture_blanknormalmap;
2086         skinframe->gloss = NULL;
2087         skinframe->glow = NULL;
2088         skinframe->fog = NULL;
2089
2090         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2091         if (!skindata)
2092                 return NULL;
2093
2094         if (r_shadow_bumpscale_basetexture.value > 0)
2095         {
2096                 temp1 = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2097                 temp2 = temp1 + width * height * 4;
2098                 // use either a custom palette or the quake palette
2099                 Image_Copy8bitBGRA(skindata, temp1, width * height, palette_bgra_complete);
2100                 Image_HeightmapToNormalmap_BGRA(temp1, temp2, width, height, false, r_shadow_bumpscale_basetexture.value);
2101                 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va("%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_BGRA, skinframe->textureflags | TEXF_ALPHA, NULL);
2102                 Mem_Free(temp1);
2103         }
2104         // use either a custom palette, or the quake palette
2105         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
2106         if (loadglowtexture)
2107                 skinframe->glow = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_glow", skinframe->basename), palette_bgra_onlyfullbrights, skinframe->textureflags, false); // glow
2108         if (loadpantsandshirt)
2109         {
2110                 skinframe->pants = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_pants", skinframe->basename), palette_bgra_pantsaswhite, skinframe->textureflags, false); // pants
2111                 skinframe->shirt = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_shirt", skinframe->basename), palette_bgra_shirtaswhite, skinframe->textureflags, false); // shirt
2112         }
2113         if (skinframe->pants || skinframe->shirt)
2114                 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
2115         if (textureflags & TEXF_ALPHA)
2116         {
2117                 for (i = 0;i < width * height;i++)
2118                         if (((unsigned char *)palette_bgra_alpha)[skindata[i]*4+3] < 255)
2119                                 break;
2120                 if (i < width * height)
2121                         skinframe->fog = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_fog", skinframe->basename), palette_bgra_alpha, skinframe->textureflags, true); // fog mask
2122         }
2123
2124         return skinframe;
2125 }
2126
2127 skinframe_t *R_SkinFrame_LoadMissing(void)
2128 {
2129         skinframe_t *skinframe;
2130
2131         if (cls.state == ca_dedicated)
2132                 return NULL;
2133
2134         skinframe = R_SkinFrame_Find("missing", TEXF_PRECACHE, 0, 0, 0, true);
2135         skinframe->stain = NULL;
2136         skinframe->merged = NULL;
2137         skinframe->base = r_texture_notexture;
2138         skinframe->pants = NULL;
2139         skinframe->shirt = NULL;
2140         skinframe->nmap = r_texture_blanknormalmap;
2141         skinframe->gloss = NULL;
2142         skinframe->glow = NULL;
2143         skinframe->fog = NULL;
2144
2145         return skinframe;
2146 }
2147
2148 void gl_main_start(void)
2149 {
2150         memset(r_qwskincache, 0, sizeof(r_qwskincache));
2151         memset(r_qwskincache_skinframe, 0, sizeof(r_qwskincache_skinframe));
2152
2153         // set up r_skinframe loading system for textures
2154         memset(&r_skinframe, 0, sizeof(r_skinframe));
2155         r_skinframe.loadsequence = 1;
2156         Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
2157
2158         r_main_texturepool = R_AllocTexturePool();
2159         R_BuildBlankTextures();
2160         R_BuildNoTexture();
2161         if (gl_texturecubemap)
2162         {
2163                 R_BuildWhiteCube();
2164                 R_BuildNormalizationCube();
2165         }
2166         r_texture_fogattenuation = NULL;
2167         r_texture_gammaramps = NULL;
2168         //r_texture_fogintensity = NULL;
2169         memset(&r_bloomstate, 0, sizeof(r_bloomstate));
2170         memset(&r_waterstate, 0, sizeof(r_waterstate));
2171         memset(r_glsl_permutations, 0, sizeof(r_glsl_permutations));
2172         memset(&r_svbsp, 0, sizeof (r_svbsp));
2173
2174         r_refdef.fogmasktable_density = 0;
2175 }
2176
2177 void gl_main_shutdown(void)
2178 {
2179         memset(r_qwskincache, 0, sizeof(r_qwskincache));
2180         memset(r_qwskincache_skinframe, 0, sizeof(r_qwskincache_skinframe));
2181
2182         // clear out the r_skinframe state
2183         Mem_ExpandableArray_FreeArray(&r_skinframe.array);
2184         memset(&r_skinframe, 0, sizeof(r_skinframe));
2185
2186         if (r_svbsp.nodes)
2187                 Mem_Free(r_svbsp.nodes);
2188         memset(&r_svbsp, 0, sizeof (r_svbsp));
2189         R_FreeTexturePool(&r_main_texturepool);
2190         r_texture_blanknormalmap = NULL;
2191         r_texture_white = NULL;
2192         r_texture_grey128 = NULL;
2193         r_texture_black = NULL;
2194         r_texture_whitecube = NULL;
2195         r_texture_normalizationcube = NULL;
2196         r_texture_fogattenuation = NULL;
2197         r_texture_gammaramps = NULL;
2198         //r_texture_fogintensity = NULL;
2199         memset(&r_bloomstate, 0, sizeof(r_bloomstate));
2200         memset(&r_waterstate, 0, sizeof(r_waterstate));
2201         R_GLSL_Restart_f();
2202 }
2203
2204 extern void CL_ParseEntityLump(char *entitystring);
2205 void gl_main_newmap(void)
2206 {
2207         // FIXME: move this code to client
2208         int l;
2209         char *entities, entname[MAX_QPATH];
2210         if (cl.worldmodel)
2211         {
2212                 strlcpy(entname, cl.worldmodel->name, sizeof(entname));
2213                 l = (int)strlen(entname) - 4;
2214                 if (l >= 0 && !strcmp(entname + l, ".bsp"))
2215                 {
2216                         memcpy(entname + l, ".ent", 5);
2217                         if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
2218                         {
2219                                 CL_ParseEntityLump(entities);
2220                                 Mem_Free(entities);
2221                                 return;
2222                         }
2223                 }
2224                 if (cl.worldmodel->brush.entities)
2225                         CL_ParseEntityLump(cl.worldmodel->brush.entities);
2226         }
2227 }
2228
2229 void GL_Main_Init(void)
2230 {
2231         r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
2232
2233         Cmd_AddCommand("r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
2234         Cmd_AddCommand("r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
2235         // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
2236         if (gamemode == GAME_NEHAHRA)
2237         {
2238                 Cvar_RegisterVariable (&gl_fogenable);
2239                 Cvar_RegisterVariable (&gl_fogdensity);
2240                 Cvar_RegisterVariable (&gl_fogred);
2241                 Cvar_RegisterVariable (&gl_foggreen);
2242                 Cvar_RegisterVariable (&gl_fogblue);
2243                 Cvar_RegisterVariable (&gl_fogstart);
2244                 Cvar_RegisterVariable (&gl_fogend);
2245                 Cvar_RegisterVariable (&gl_skyclip);
2246         }
2247         Cvar_RegisterVariable(&r_depthfirst);
2248         Cvar_RegisterVariable(&r_nearclip);
2249         Cvar_RegisterVariable(&r_showbboxes);
2250         Cvar_RegisterVariable(&r_showsurfaces);
2251         Cvar_RegisterVariable(&r_showtris);
2252         Cvar_RegisterVariable(&r_shownormals);
2253         Cvar_RegisterVariable(&r_showlighting);
2254         Cvar_RegisterVariable(&r_showshadowvolumes);
2255         Cvar_RegisterVariable(&r_showcollisionbrushes);
2256         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
2257         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
2258         Cvar_RegisterVariable(&r_showdisabledepthtest);
2259         Cvar_RegisterVariable(&r_drawportals);
2260         Cvar_RegisterVariable(&r_drawentities);
2261         Cvar_RegisterVariable(&r_cullentities_trace);
2262         Cvar_RegisterVariable(&r_cullentities_trace_samples);
2263         Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
2264         Cvar_RegisterVariable(&r_cullentities_trace_delay);
2265         Cvar_RegisterVariable(&r_drawviewmodel);
2266         Cvar_RegisterVariable(&r_speeds);
2267         Cvar_RegisterVariable(&r_fullbrights);
2268         Cvar_RegisterVariable(&r_wateralpha);
2269         Cvar_RegisterVariable(&r_dynamic);
2270         Cvar_RegisterVariable(&r_fullbright);
2271         Cvar_RegisterVariable(&r_shadows);
2272         Cvar_RegisterVariable(&r_shadows_throwdistance);
2273         Cvar_RegisterVariable(&r_q1bsp_skymasking);
2274         Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
2275         Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
2276         Cvar_RegisterVariable(&r_fog_exp2);
2277         Cvar_RegisterVariable(&r_textureunits);
2278         Cvar_RegisterVariable(&r_glsl);
2279         Cvar_RegisterVariable(&r_glsl_contrastboost);
2280         Cvar_RegisterVariable(&r_glsl_deluxemapping);
2281         Cvar_RegisterVariable(&r_glsl_offsetmapping);
2282         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
2283         Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
2284         Cvar_RegisterVariable(&r_glsl_postprocess);
2285         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1);
2286         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2);
2287         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3);
2288         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4);
2289         Cvar_RegisterVariable(&r_glsl_usegeneric);
2290         Cvar_RegisterVariable(&r_water);
2291         Cvar_RegisterVariable(&r_water_resolutionmultiplier);
2292         Cvar_RegisterVariable(&r_water_clippingplanebias);
2293         Cvar_RegisterVariable(&r_water_refractdistort);
2294         Cvar_RegisterVariable(&r_water_reflectdistort);
2295         Cvar_RegisterVariable(&r_lerpsprites);
2296         Cvar_RegisterVariable(&r_lerpmodels);
2297         Cvar_RegisterVariable(&r_lerplightstyles);
2298         Cvar_RegisterVariable(&r_waterscroll);
2299         Cvar_RegisterVariable(&r_bloom);
2300         Cvar_RegisterVariable(&r_bloom_colorscale);
2301         Cvar_RegisterVariable(&r_bloom_brighten);
2302         Cvar_RegisterVariable(&r_bloom_blur);
2303         Cvar_RegisterVariable(&r_bloom_resolution);
2304         Cvar_RegisterVariable(&r_bloom_colorexponent);
2305         Cvar_RegisterVariable(&r_bloom_colorsubtract);
2306         Cvar_RegisterVariable(&r_hdr);
2307         Cvar_RegisterVariable(&r_hdr_scenebrightness);
2308         Cvar_RegisterVariable(&r_hdr_glowintensity);
2309         Cvar_RegisterVariable(&r_hdr_range);
2310         Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
2311         Cvar_RegisterVariable(&developer_texturelogging);
2312         Cvar_RegisterVariable(&gl_lightmaps);
2313         Cvar_RegisterVariable(&r_test);
2314         Cvar_RegisterVariable(&r_batchmode);
2315         if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
2316                 Cvar_SetValue("r_fullbrights", 0);
2317         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
2318
2319         Cvar_RegisterVariable(&r_track_sprites);
2320         Cvar_RegisterVariable(&r_track_sprites_flags);
2321         Cvar_RegisterVariable(&r_track_sprites_scalew);
2322         Cvar_RegisterVariable(&r_track_sprites_scaleh);
2323 }
2324
2325 extern void R_Textures_Init(void);
2326 extern void GL_Draw_Init(void);
2327 extern void GL_Main_Init(void);
2328 extern void R_Shadow_Init(void);
2329 extern void R_Sky_Init(void);
2330 extern void GL_Surf_Init(void);
2331 extern void R_Particles_Init(void);
2332 extern void R_Explosion_Init(void);
2333 extern void gl_backend_init(void);
2334 extern void Sbar_Init(void);
2335 extern void R_LightningBeams_Init(void);
2336 extern void Mod_RenderInit(void);
2337
2338 void Render_Init(void)
2339 {
2340         gl_backend_init();
2341         R_Textures_Init();
2342         GL_Main_Init();
2343         GL_Draw_Init();
2344         R_Shadow_Init();
2345         R_Sky_Init();
2346         GL_Surf_Init();
2347         Sbar_Init();
2348         R_Particles_Init();
2349         R_Explosion_Init();
2350         R_LightningBeams_Init();
2351         Mod_RenderInit();
2352 }
2353
2354 /*
2355 ===============
2356 GL_Init
2357 ===============
2358 */
2359 extern char *ENGINE_EXTENSIONS;
2360 void GL_Init (void)
2361 {
2362         VID_CheckExtensions();
2363
2364         // LordHavoc: report supported extensions
2365         Con_DPrintf("\nQuakeC extensions for server and client: %s\nQuakeC extensions for menu: %s\n", vm_sv_extensions, vm_m_extensions );
2366
2367         // clear to black (loading plaque will be seen over this)
2368         CHECKGLERROR
2369         qglClearColor(0,0,0,1);CHECKGLERROR
2370         qglClear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
2371 }
2372
2373 int R_CullBox(const vec3_t mins, const vec3_t maxs)
2374 {
2375         int i;
2376         mplane_t *p;
2377         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
2378         {
2379                 // skip nearclip plane, it often culls portals when you are very close, and is almost never useful
2380                 if (i == 4)
2381                         continue;
2382                 p = r_refdef.view.frustum + i;
2383                 switch(p->signbits)
2384                 {
2385                 default:
2386                 case 0:
2387                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
2388                                 return true;
2389                         break;
2390                 case 1:
2391                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
2392                                 return true;
2393                         break;
2394                 case 2:
2395                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
2396                                 return true;
2397                         break;
2398                 case 3:
2399                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
2400                                 return true;
2401                         break;
2402                 case 4:
2403                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
2404                                 return true;
2405                         break;
2406                 case 5:
2407                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
2408                                 return true;
2409                         break;
2410                 case 6:
2411                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
2412                                 return true;
2413                         break;
2414                 case 7:
2415                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
2416                                 return true;
2417                         break;
2418                 }
2419         }
2420         return false;
2421 }
2422
2423 int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
2424 {
2425         int i;
2426         const mplane_t *p;
2427         for (i = 0;i < numplanes;i++)
2428         {
2429                 p = planes + i;
2430                 switch(p->signbits)
2431                 {
2432                 default:
2433                 case 0:
2434                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
2435                                 return true;
2436                         break;
2437                 case 1:
2438                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
2439                                 return true;
2440                         break;
2441                 case 2:
2442                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
2443                                 return true;
2444                         break;
2445                 case 3:
2446                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
2447                                 return true;
2448                         break;
2449                 case 4:
2450                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
2451                                 return true;
2452                         break;
2453                 case 5:
2454                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
2455                                 return true;
2456                         break;
2457                 case 6:
2458                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
2459                                 return true;
2460                         break;
2461                 case 7:
2462                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
2463                                 return true;
2464                         break;
2465                 }
2466         }
2467         return false;
2468 }
2469
2470 //==================================================================================
2471
2472 static void R_View_UpdateEntityVisible (void)
2473 {
2474         int i, renderimask;
2475         entity_render_t *ent;
2476
2477         if (!r_drawentities.integer)
2478                 return;
2479
2480         renderimask = r_refdef.envmap ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL) : ((chase_active.integer || r_waterstate.renderingscene) ? RENDER_VIEWMODEL : RENDER_EXTERIORMODEL);
2481         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
2482         {
2483                 // worldmodel can check visibility
2484                 for (i = 0;i < r_refdef.scene.numentities;i++)
2485                 {
2486                         ent = r_refdef.scene.entities[i];
2487                         r_refdef.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.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, ent->mins, ent->maxs));
2488
2489                 }
2490                 if(r_cullentities_trace.integer && r_refdef.scene.worldmodel->brush.TraceLineOfSight)
2491                 {
2492                         for (i = 0;i < r_refdef.scene.numentities;i++)
2493                         {
2494                                 ent = r_refdef.scene.entities[i];
2495                                 if(r_refdef.viewcache.entityvisible[i] && !(ent->effects & EF_NODEPTHTEST) && !(ent->flags & RENDER_VIEWMODEL) && !(ent->model && (ent->model->name[0] == '*')))
2496                                 {
2497                                         if(Mod_CanSeeBox_Trace(r_cullentities_trace_samples.integer, r_cullentities_trace_enlarge.value, r_refdef.scene.worldmodel, r_refdef.view.origin, ent->mins, ent->maxs))
2498                                                 ent->last_trace_visibility = realtime;
2499                                         if(ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
2500                                                 r_refdef.viewcache.entityvisible[i] = 0;
2501                                 }
2502                         }
2503                 }
2504         }
2505         else
2506         {
2507                 // no worldmodel or it can't check visibility
2508                 for (i = 0;i < r_refdef.scene.numentities;i++)
2509                 {
2510                         ent = r_refdef.scene.entities[i];
2511                         r_refdef.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));
2512                 }
2513         }
2514 }
2515
2516 // only used if skyrendermasked, and normally returns false
2517 int R_DrawBrushModelsSky (void)
2518 {
2519         int i, sky;
2520         entity_render_t *ent;
2521
2522         if (!r_drawentities.integer)
2523                 return false;
2524
2525         sky = false;
2526         for (i = 0;i < r_refdef.scene.numentities;i++)
2527         {
2528                 if (!r_refdef.viewcache.entityvisible[i])
2529                         continue;
2530                 ent = r_refdef.scene.entities[i];
2531                 if (!ent->model || !ent->model->DrawSky)
2532                         continue;
2533                 ent->model->DrawSky(ent);
2534                 sky = true;
2535         }
2536         return sky;
2537 }
2538
2539 static void R_DrawNoModel(entity_render_t *ent);
2540 static void R_DrawModels(void)
2541 {
2542         int i;
2543         entity_render_t *ent;
2544
2545         if (!r_drawentities.integer)
2546                 return;
2547
2548         for (i = 0;i < r_refdef.scene.numentities;i++)
2549         {
2550                 if (!r_refdef.viewcache.entityvisible[i])
2551                         continue;
2552                 ent = r_refdef.scene.entities[i];
2553                 r_refdef.stats.entities++;
2554                 if (ent->model && ent->model->Draw != NULL)
2555                         ent->model->Draw(ent);
2556                 else
2557                         R_DrawNoModel(ent);
2558         }
2559 }
2560
2561 static void R_DrawModelsDepth(void)
2562 {
2563         int i;
2564         entity_render_t *ent;
2565
2566         if (!r_drawentities.integer)
2567                 return;
2568
2569         for (i = 0;i < r_refdef.scene.numentities;i++)
2570         {
2571                 if (!r_refdef.viewcache.entityvisible[i])
2572                         continue;
2573                 ent = r_refdef.scene.entities[i];
2574                 if (ent->model && ent->model->DrawDepth != NULL)
2575                         ent->model->DrawDepth(ent);
2576         }
2577 }
2578
2579 static void R_DrawModelsDebug(void)
2580 {
2581         int i;
2582         entity_render_t *ent;
2583
2584         if (!r_drawentities.integer)
2585                 return;
2586
2587         for (i = 0;i < r_refdef.scene.numentities;i++)
2588         {
2589                 if (!r_refdef.viewcache.entityvisible[i])
2590                         continue;
2591                 ent = r_refdef.scene.entities[i];
2592                 if (ent->model && ent->model->DrawDebug != NULL)
2593                         ent->model->DrawDebug(ent);
2594         }
2595 }
2596
2597 static void R_DrawModelsAddWaterPlanes(void)
2598 {
2599         int i;
2600         entity_render_t *ent;
2601
2602         if (!r_drawentities.integer)
2603                 return;
2604
2605         for (i = 0;i < r_refdef.scene.numentities;i++)
2606         {
2607                 if (!r_refdef.viewcache.entityvisible[i])
2608                         continue;
2609                 ent = r_refdef.scene.entities[i];
2610                 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
2611                         ent->model->DrawAddWaterPlanes(ent);
2612         }
2613 }
2614
2615 static void R_View_SetFrustum(void)
2616 {
2617         int i;
2618         double slopex, slopey;
2619         vec3_t forward, left, up, origin;
2620
2621         // we can't trust r_refdef.view.forward and friends in reflected scenes
2622         Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin);
2623
2624 #if 0
2625         r_refdef.view.frustum[0].normal[0] = 0 - 1.0 / r_refdef.view.frustum_x;
2626         r_refdef.view.frustum[0].normal[1] = 0 - 0;
2627         r_refdef.view.frustum[0].normal[2] = -1 - 0;
2628         r_refdef.view.frustum[1].normal[0] = 0 + 1.0 / r_refdef.view.frustum_x;
2629         r_refdef.view.frustum[1].normal[1] = 0 + 0;
2630         r_refdef.view.frustum[1].normal[2] = -1 + 0;
2631         r_refdef.view.frustum[2].normal[0] = 0 - 0;
2632         r_refdef.view.frustum[2].normal[1] = 0 - 1.0 / r_refdef.view.frustum_y;
2633         r_refdef.view.frustum[2].normal[2] = -1 - 0;
2634         r_refdef.view.frustum[3].normal[0] = 0 + 0;
2635         r_refdef.view.frustum[3].normal[1] = 0 + 1.0 / r_refdef.view.frustum_y;
2636         r_refdef.view.frustum[3].normal[2] = -1 + 0;
2637 #endif
2638
2639 #if 0
2640         zNear = r_refdef.nearclip;
2641         nudge = 1.0 - 1.0 / (1<<23);
2642         r_refdef.view.frustum[4].normal[0] = 0 - 0;
2643         r_refdef.view.frustum[4].normal[1] = 0 - 0;
2644         r_refdef.view.frustum[4].normal[2] = -1 - -nudge;
2645         r_refdef.view.frustum[4].dist = 0 - -2 * zNear * nudge;
2646         r_refdef.view.frustum[5].normal[0] = 0 + 0;
2647         r_refdef.view.frustum[5].normal[1] = 0 + 0;
2648         r_refdef.view.frustum[5].normal[2] = -1 + -nudge;
2649         r_refdef.view.frustum[5].dist = 0 + -2 * zNear * nudge;
2650 #endif
2651
2652
2653
2654 #if 0
2655         r_refdef.view.frustum[0].normal[0] = m[3] - m[0];
2656         r_refdef.view.frustum[0].normal[1] = m[7] - m[4];
2657         r_refdef.view.frustum[0].normal[2] = m[11] - m[8];
2658         r_refdef.view.frustum[0].dist = m[15] - m[12];
2659
2660         r_refdef.view.frustum[1].normal[0] = m[3] + m[0];
2661         r_refdef.view.frustum[1].normal[1] = m[7] + m[4];
2662         r_refdef.view.frustum[1].normal[2] = m[11] + m[8];
2663         r_refdef.view.frustum[1].dist = m[15] + m[12];
2664
2665         r_refdef.view.frustum[2].normal[0] = m[3] - m[1];
2666         r_refdef.view.frustum[2].normal[1] = m[7] - m[5];
2667         r_refdef.view.frustum[2].normal[2] = m[11] - m[9];
2668         r_refdef.view.frustum[2].dist = m[15] - m[13];
2669
2670         r_refdef.view.frustum[3].normal[0] = m[3] + m[1];
2671         r_refdef.view.frustum[3].normal[1] = m[7] + m[5];
2672         r_refdef.view.frustum[3].normal[2] = m[11] + m[9];
2673         r_refdef.view.frustum[3].dist = m[15] + m[13];
2674
2675         r_refdef.view.frustum[4].normal[0] = m[3] - m[2];
2676         r_refdef.view.frustum[4].normal[1] = m[7] - m[6];
2677         r_refdef.view.frustum[4].normal[2] = m[11] - m[10];
2678         r_refdef.view.frustum[4].dist = m[15] - m[14];
2679
2680         r_refdef.view.frustum[5].normal[0] = m[3] + m[2];
2681         r_refdef.view.frustum[5].normal[1] = m[7] + m[6];
2682         r_refdef.view.frustum[5].normal[2] = m[11] + m[10];
2683         r_refdef.view.frustum[5].dist = m[15] + m[14];
2684 #endif
2685
2686         if (r_refdef.view.useperspective)
2687         {
2688                 slopex = 1.0 / r_refdef.view.frustum_x;
2689                 slopey = 1.0 / r_refdef.view.frustum_y;
2690                 VectorMA(forward, -slopex, left, r_refdef.view.frustum[0].normal);
2691                 VectorMA(forward,  slopex, left, r_refdef.view.frustum[1].normal);
2692                 VectorMA(forward, -slopey, up  , r_refdef.view.frustum[2].normal);
2693                 VectorMA(forward,  slopey, up  , r_refdef.view.frustum[3].normal);
2694                 VectorCopy(forward, r_refdef.view.frustum[4].normal);
2695
2696                 // Leaving those out was a mistake, those were in the old code, and they
2697                 // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix
2698                 // I couldn't reproduce it after adding those normalizations. --blub
2699                 VectorNormalize(r_refdef.view.frustum[0].normal);
2700                 VectorNormalize(r_refdef.view.frustum[1].normal);
2701                 VectorNormalize(r_refdef.view.frustum[2].normal);
2702                 VectorNormalize(r_refdef.view.frustum[3].normal);
2703
2704                 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
2705                 VectorMAMAMAM(1, r_refdef.view.origin, 1024, forward, -1024 * slopex, left, -1024 * slopey, up, r_refdef.view.frustumcorner[0]);
2706                 VectorMAMAMAM(1, r_refdef.view.origin, 1024, forward,  1024 * slopex, left, -1024 * slopey, up, r_refdef.view.frustumcorner[1]);
2707                 VectorMAMAMAM(1, r_refdef.view.origin, 1024, forward, -1024 * slopex, left,  1024 * slopey, up, r_refdef.view.frustumcorner[2]);
2708                 VectorMAMAMAM(1, r_refdef.view.origin, 1024, forward,  1024 * slopex, left,  1024 * slopey, up, r_refdef.view.frustumcorner[3]);
2709
2710                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal);
2711                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal);
2712                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal);
2713                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal);
2714                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip;
2715         }
2716         else
2717         {
2718                 VectorScale(left, -r_refdef.view.ortho_x, r_refdef.view.frustum[0].normal);
2719                 VectorScale(left,  r_refdef.view.ortho_x, r_refdef.view.frustum[1].normal);
2720                 VectorScale(up, -r_refdef.view.ortho_y, r_refdef.view.frustum[2].normal);
2721                 VectorScale(up,  r_refdef.view.ortho_y, r_refdef.view.frustum[3].normal);
2722                 VectorCopy(forward, r_refdef.view.frustum[4].normal);
2723                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal) + r_refdef.view.ortho_x;
2724                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal) + r_refdef.view.ortho_x;
2725                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal) + r_refdef.view.ortho_y;
2726                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal) + r_refdef.view.ortho_y;
2727                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip;
2728         }
2729         r_refdef.view.numfrustumplanes = 5;
2730
2731         if (r_refdef.view.useclipplane)
2732         {
2733                 r_refdef.view.numfrustumplanes = 6;
2734                 r_refdef.view.frustum[5] = r_refdef.view.clipplane;
2735         }
2736
2737         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
2738                 PlaneClassify(r_refdef.view.frustum + i);
2739
2740         // LordHavoc: note to all quake engine coders, Quake had a special case
2741         // for 90 degrees which assumed a square view (wrong), so I removed it,
2742         // Quake2 has it disabled as well.
2743
2744         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
2745         //RotatePointAroundVector( r_refdef.view.frustum[0].normal, up, forward, -(90 - r_refdef.fov_x / 2));
2746         //r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, frustum[0].normal);
2747         //PlaneClassify(&frustum[0]);
2748
2749         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
2750         //RotatePointAroundVector( r_refdef.view.frustum[1].normal, up, forward, (90 - r_refdef.fov_x / 2));
2751         //r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, frustum[1].normal);
2752         //PlaneClassify(&frustum[1]);
2753
2754         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
2755         //RotatePointAroundVector( r_refdef.view.frustum[2].normal, left, forward, -(90 - r_refdef.fov_y / 2));
2756         //r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, frustum[2].normal);
2757         //PlaneClassify(&frustum[2]);
2758
2759         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
2760         //RotatePointAroundVector( r_refdef.view.frustum[3].normal, left, forward, (90 - r_refdef.fov_y / 2));
2761         //r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, frustum[3].normal);
2762         //PlaneClassify(&frustum[3]);
2763
2764         // nearclip plane
2765         //VectorCopy(forward, r_refdef.view.frustum[4].normal);
2766         //r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, frustum[4].normal) + r_nearclip.value;
2767         //PlaneClassify(&frustum[4]);
2768 }
2769
2770 void R_View_Update(void)
2771 {
2772         R_View_SetFrustum();
2773         R_View_WorldVisibility(r_refdef.view.useclipplane);
2774         R_View_UpdateEntityVisible();
2775 }
2776
2777 void R_SetupView(qboolean allowwaterclippingplane)
2778 {
2779         if (!r_refdef.view.useperspective)
2780                 GL_SetupView_Mode_Ortho(-r_refdef.view.ortho_x, -r_refdef.view.ortho_y, r_refdef.view.ortho_x, r_refdef.view.ortho_y, -r_refdef.farclip, r_refdef.farclip);
2781         else if (r_refdef.rtworldshadows || r_refdef.rtdlightshadows)
2782                 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip);
2783         else
2784                 GL_SetupView_Mode_Perspective(r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, r_refdef.farclip);
2785
2786         GL_SetupView_Orientation_FromEntity(&r_refdef.view.matrix);
2787
2788         if (r_refdef.view.useclipplane && allowwaterclippingplane)
2789         {
2790                 // LordHavoc: couldn't figure out how to make this approach the
2791                 vec_t dist = r_refdef.view.clipplane.dist - r_water_clippingplanebias.value;
2792                 vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
2793                 if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
2794                         dist = r_refdef.view.clipplane.dist;
2795                 GL_SetupView_ApplyCustomNearClipPlane(r_refdef.view.clipplane.normal[0], r_refdef.view.clipplane.normal[1], r_refdef.view.clipplane.normal[2], dist);
2796         }
2797 }
2798
2799 void R_ResetViewRendering2D(void)
2800 {
2801         DrawQ_Finish();
2802
2803         // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
2804         qglViewport(r_refdef.view.x, vid.height - (r_refdef.view.y + r_refdef.view.height), r_refdef.view.width, r_refdef.view.height);CHECKGLERROR
2805         GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
2806         GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
2807         GL_Color(1, 1, 1, 1);
2808         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
2809         GL_BlendFunc(GL_ONE, GL_ZERO);
2810         GL_AlphaTest(false);
2811         GL_ScissorTest(false);
2812         GL_DepthMask(false);
2813         GL_DepthRange(0, 1);
2814         GL_DepthTest(false);
2815         R_Mesh_Matrix(&identitymatrix);
2816         R_Mesh_ResetTextureState();
2817         GL_PolygonOffset(0, 0);
2818         qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
2819         qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2820         qglDisable(GL_STENCIL_TEST);CHECKGLERROR
2821         qglStencilMask(~0);CHECKGLERROR
2822         qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
2823         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
2824         GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
2825         R_SetupGenericShader(true);
2826 }
2827
2828 void R_ResetViewRendering3D(void)
2829 {
2830         DrawQ_Finish();
2831
2832         // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
2833         qglViewport(r_refdef.view.x, vid.height - (r_refdef.view.y + r_refdef.view.height), r_refdef.view.width, r_refdef.view.height);CHECKGLERROR
2834         R_SetupView(true);
2835         GL_Scissor(r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
2836         GL_Color(1, 1, 1, 1);
2837         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
2838         GL_BlendFunc(GL_ONE, GL_ZERO);
2839         GL_AlphaTest(false);
2840         GL_ScissorTest(true);
2841         GL_DepthMask(true);
2842         GL_DepthRange(0, 1);
2843         GL_DepthTest(true);
2844         R_Mesh_Matrix(&identitymatrix);
2845         R_Mesh_ResetTextureState();
2846         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
2847         qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
2848         qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2849         qglDisable(GL_STENCIL_TEST);CHECKGLERROR
2850         qglStencilMask(~0);CHECKGLERROR
2851         qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
2852         qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
2853         GL_CullFace(r_refdef.view.cullface_back);
2854         R_SetupGenericShader(true);
2855 }
2856
2857 void R_RenderScene(qboolean addwaterplanes);
2858
2859 static void R_Water_StartFrame(void)
2860 {
2861         int i;
2862         int waterwidth, waterheight, texturewidth, textureheight;
2863         r_waterstate_waterplane_t *p;
2864
2865         // set waterwidth and waterheight to the water resolution that will be
2866         // used (often less than the screen resolution for faster rendering)
2867         waterwidth = (int)bound(1, r_refdef.view.width * r_water_resolutionmultiplier.value, r_refdef.view.width);
2868         waterheight = (int)bound(1, r_refdef.view.height * r_water_resolutionmultiplier.value, r_refdef.view.height);
2869
2870         // calculate desired texture sizes
2871         // can't use water if the card does not support the texture size
2872         if (!r_water.integer || !r_glsl.integer || !gl_support_fragment_shader || waterwidth > gl_max_texture_size || waterheight > gl_max_texture_size)
2873                 texturewidth = textureheight = waterwidth = waterheight = 0;
2874         else if (gl_support_arb_texture_non_power_of_two)
2875         {
2876                 texturewidth = waterwidth;
2877                 textureheight = waterheight;
2878         }
2879         else
2880         {
2881                 for (texturewidth   = 1;texturewidth   < waterwidth ;texturewidth   *= 2);
2882                 for (textureheight  = 1;textureheight  < waterheight;textureheight  *= 2);
2883         }
2884
2885         // allocate textures as needed
2886         if (r_waterstate.waterwidth != waterwidth || r_waterstate.waterheight != waterheight || r_waterstate.texturewidth != texturewidth || r_waterstate.textureheight != textureheight)
2887         {
2888                 r_waterstate.maxwaterplanes = MAX_WATERPLANES;
2889                 for (i = 0, p = r_waterstate.waterplanes;i < r_waterstate.maxwaterplanes;i++, p++)
2890                 {
2891                         if (p->texture_refraction)
2892                                 R_FreeTexture(p->texture_refraction);
2893                         p->texture_refraction = NULL;
2894                         if (p->texture_reflection)
2895                                 R_FreeTexture(p->texture_reflection);
2896                         p->texture_reflection = NULL;
2897                 }
2898                 memset(&r_waterstate, 0, sizeof(r_waterstate));
2899                 r_waterstate.waterwidth = waterwidth;
2900                 r_waterstate.waterheight = waterheight;
2901                 r_waterstate.texturewidth = texturewidth;
2902                 r_waterstate.textureheight = textureheight;
2903         }
2904
2905         if (r_waterstate.waterwidth)
2906         {
2907                 r_waterstate.enabled = true;
2908
2909                 // set up variables that will be used in shader setup
2910                 r_waterstate.screenscale[0] = 0.5f * (float)waterwidth / (float)texturewidth;
2911                 r_waterstate.screenscale[1] = 0.5f * (float)waterheight / (float)textureheight;
2912                 r_waterstate.screencenter[0] = 0.5f * (float)waterwidth / (float)texturewidth;
2913                 r_waterstate.screencenter[1] = 0.5f * (float)waterheight / (float)textureheight;
2914         }
2915
2916         r_waterstate.maxwaterplanes = MAX_WATERPLANES;
2917         r_waterstate.numwaterplanes = 0;
2918 }
2919
2920 static void R_Water_AddWaterPlane(msurface_t *surface)
2921 {
2922         int triangleindex, planeindex;
2923         const int *e;
2924         vec3_t vert[3];
2925         vec3_t normal;
2926         vec3_t center;
2927         r_waterstate_waterplane_t *p;
2928         // just use the first triangle with a valid normal for any decisions
2929         VectorClear(normal);
2930         for (triangleindex = 0, e = rsurface.modelelement3i + surface->num_firsttriangle * 3;triangleindex < surface->num_triangles;triangleindex++, e += 3)
2931         {
2932                 Matrix4x4_Transform(&rsurface.matrix, rsurface.modelvertex3f + e[0]*3, vert[0]);
2933                 Matrix4x4_Transform(&rsurface.matrix, rsurface.modelvertex3f + e[1]*3, vert[1]);
2934                 Matrix4x4_Transform(&rsurface.matrix, rsurface.modelvertex3f + e[2]*3, vert[2]);
2935                 TriangleNormal(vert[0], vert[1], vert[2], normal);
2936                 if (VectorLength2(normal) >= 0.001)
2937                         break;
2938         }
2939
2940         // find a matching plane if there is one
2941         for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++)
2942                 if (fabs(PlaneDiff(vert[0], &p->plane)) < 1 && fabs(PlaneDiff(vert[1], &p->plane)) < 1 && fabs(PlaneDiff(vert[2], &p->plane)) < 1)
2943                         break;
2944         if (planeindex >= r_waterstate.maxwaterplanes)
2945                 return; // nothing we can do, out of planes
2946
2947         // if this triangle does not fit any known plane rendered this frame, add one
2948         if (planeindex >= r_waterstate.numwaterplanes)
2949         {
2950                 // store the new plane
2951                 r_waterstate.numwaterplanes++;
2952                 VectorCopy(normal, p->plane.normal);
2953                 VectorNormalize(p->plane.normal);
2954                 p->plane.dist = DotProduct(vert[0], p->plane.normal);
2955                 PlaneClassify(&p->plane);
2956                 // flip the plane if it does not face the viewer
2957                 if (PlaneDiff(r_refdef.view.origin, &p->plane) < 0)
2958                 {
2959                         VectorNegate(p->plane.normal, p->plane.normal);
2960                         p->plane.dist *= -1;
2961                         PlaneClassify(&p->plane);
2962                 }
2963                 // clear materialflags and pvs
2964                 p->materialflags = 0;
2965                 p->pvsvalid = false;
2966         }
2967         // merge this surface's materialflags into the waterplane
2968         p->materialflags |= surface->texture->currentframe->currentmaterialflags;
2969         // merge this surface's PVS into the waterplane
2970         VectorMAM(0.5f, surface->mins, 0.5f, surface->maxs, center);
2971         if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
2972          && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
2973         {
2974                 r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
2975                 p->pvsvalid = true;
2976         }
2977 }
2978
2979 static void R_Water_ProcessPlanes(void)
2980 {
2981         r_refdef_view_t originalview;
2982         int planeindex;
2983         r_waterstate_waterplane_t *p;
2984
2985         originalview = r_refdef.view;
2986
2987         // make sure enough textures are allocated
2988         for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++)
2989         {
2990                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
2991                 {
2992                         if (!p->texture_refraction)
2993                                 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);
2994                         if (!p->texture_refraction)
2995                                 goto error;
2996                 }
2997
2998                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
2999                 {
3000                         if (!p->texture_reflection)
3001                                 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);
3002                         if (!p->texture_reflection)
3003                                 goto error;
3004                 }
3005         }
3006
3007         // render views
3008         for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++)
3009         {
3010                 r_refdef.view.showdebug = false;
3011                 r_refdef.view.width = r_waterstate.waterwidth;
3012                 r_refdef.view.height = r_waterstate.waterheight;
3013                 r_refdef.view.useclipplane = true;
3014                 r_waterstate.renderingscene = true;
3015
3016                 // render the normal view scene and copy into texture
3017                 // (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)
3018                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
3019                 {
3020                         r_refdef.view.clipplane = p->plane;
3021                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
3022                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
3023                         PlaneClassify(&r_refdef.view.clipplane);
3024
3025                         R_RenderScene(false);
3026
3027                         // copy view into the screen texture
3028                         R_Mesh_TexBind(0, R_GetTexture(p->texture_refraction));
3029                         GL_ActiveTexture(0);
3030                         CHECKGLERROR
3031                         qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.x, vid.height - (r_refdef.view.y + r_refdef.view.height), r_refdef.view.width, r_refdef.view.height);CHECKGLERROR
3032                 }
3033
3034                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
3035                 {
3036                         // render reflected scene and copy into texture
3037                         Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
3038                         // update the r_refdef.view.origin because otherwise the sky renders at the wrong location (amongst other problems)
3039                         Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
3040                         r_refdef.view.clipplane = p->plane;
3041                         // reverse the cullface settings for this render
3042                         r_refdef.view.cullface_front = GL_FRONT;
3043                         r_refdef.view.cullface_back = GL_BACK;
3044                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
3045                         {
3046                                 r_refdef.view.usecustompvs = true;
3047                                 if (p->pvsvalid)
3048                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
3049                                 else
3050                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
3051                         }
3052
3053                         R_ResetViewRendering3D();
3054                         R_ClearScreen(r_refdef.fogenabled);
3055                         if (r_timereport_active)
3056                                 R_TimeReport("viewclear");
3057
3058                         R_RenderScene(false);
3059
3060                         R_Mesh_TexBind(0, R_GetTexture(p->texture_reflection));
3061                         GL_ActiveTexture(0);
3062                         CHECKGLERROR
3063                         qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.x, vid.height - (r_refdef.view.y + r_refdef.view.height), r_refdef.view.width, r_refdef.view.height);CHECKGLERROR
3064
3065                         R_ResetViewRendering3D();
3066                         R_ClearScreen(r_refdef.fogenabled);
3067                         if (r_timereport_active)
3068                                 R_TimeReport("viewclear");
3069                 }
3070
3071                 r_refdef.view = originalview;
3072                 r_refdef.view.clear = true;
3073                 r_waterstate.renderingscene = false;
3074         }
3075         return;
3076 error:
3077         r_refdef.view = originalview;
3078         r_waterstate.renderingscene = false;
3079         Cvar_SetValueQuick(&r_water, 0);
3080         Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed!  Turned off r_water.\n");
3081         return;
3082 }
3083
3084 void R_Bloom_StartFrame(void)
3085 {
3086         int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight;
3087
3088         // set bloomwidth and bloomheight to the bloom resolution that will be
3089         // used (often less than the screen resolution for faster rendering)
3090         r_bloomstate.bloomwidth = bound(1, r_bloom_resolution.integer, r_refdef.view.width);
3091         r_bloomstate.bloomheight = r_bloomstate.bloomwidth * r_refdef.view.height / r_refdef.view.width;
3092         r_bloomstate.bloomheight = bound(1, r_bloomstate.bloomheight, r_refdef.view.height);
3093         r_bloomstate.bloomwidth = min(r_bloomstate.bloomwidth, gl_max_texture_size);
3094         r_bloomstate.bloomheight = min(r_bloomstate.bloomheight, gl_max_texture_size);
3095
3096         // calculate desired texture sizes
3097         if (gl_support_arb_texture_non_power_of_two)
3098         {
3099                 screentexturewidth = r_refdef.view.width;
3100                 screentextureheight = r_refdef.view.height;
3101                 bloomtexturewidth = r_bloomstate.bloomwidth;
3102                 bloomtextureheight = r_bloomstate.bloomheight;
3103         }
3104         else
3105         {
3106                 for (screentexturewidth  = 1;screentexturewidth  < vid.width               ;screentexturewidth  *= 2);
3107                 for (screentextureheight = 1;screentextureheight < vid.height              ;screentextureheight *= 2);
3108                 for (bloomtexturewidth   = 1;bloomtexturewidth   < r_bloomstate.bloomwidth ;bloomtexturewidth   *= 2);
3109                 for (bloomtextureheight  = 1;bloomtextureheight  < r_bloomstate.bloomheight;bloomtextureheight  *= 2);
3110         }
3111
3112         if ((r_hdr.integer || r_bloom.integer) && ((r_bloom_resolution.integer < 4 || r_bloom_blur.value < 1 || r_bloom_blur.value >= 512) || r_refdef.view.width > gl_max_texture_size || r_refdef.view.height > gl_max_texture_size))
3113         {
3114                 Cvar_SetValueQuick(&r_hdr, 0);
3115                 Cvar_SetValueQuick(&r_bloom, 0);
3116         }
3117
3118         if (!(r_glsl.integer && (r_glsl_postprocess.integer || (v_glslgamma.integer && !vid_gammatables_trivial) || r_bloom.integer || r_hdr.integer)) && !r_bloom.integer)
3119                 screentexturewidth = screentextureheight = 0;
3120         if (!r_hdr.integer && !r_bloom.integer)
3121                 bloomtexturewidth = bloomtextureheight = 0;
3122
3123         // allocate textures as needed
3124         if (r_bloomstate.screentexturewidth != screentexturewidth || r_bloomstate.screentextureheight != screentextureheight)
3125         {
3126                 if (r_bloomstate.texture_screen)
3127                         R_FreeTexture(r_bloomstate.texture_screen);
3128                 r_bloomstate.texture_screen = NULL;
3129                 r_bloomstate.screentexturewidth = screentexturewidth;
3130                 r_bloomstate.screentextureheight = screentextureheight;
3131                 if (r_bloomstate.screentexturewidth && r_bloomstate.screentextureheight)
3132                         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);
3133         }
3134         if (r_bloomstate.bloomtexturewidth != bloomtexturewidth || r_bloomstate.bloomtextureheight != bloomtextureheight)
3135         {
3136                 if (r_bloomstate.texture_bloom)
3137                         R_FreeTexture(r_bloomstate.texture_bloom);
3138                 r_bloomstate.texture_bloom = NULL;
3139                 r_bloomstate.bloomtexturewidth = bloomtexturewidth;
3140                 r_bloomstate.bloomtextureheight = bloomtextureheight;
3141                 if (r_bloomstate.bloomtexturewidth && r_bloomstate.bloomtextureheight)
3142                         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);
3143         }
3144
3145         // set up a texcoord array for the full resolution screen image
3146         // (we have to keep this around to copy back during final render)
3147         r_bloomstate.screentexcoord2f[0] = 0;
3148         r_bloomstate.screentexcoord2f[1] = (float)r_refdef.view.height    / (float)r_bloomstate.screentextureheight;
3149         r_bloomstate.screentexcoord2f[2] = (float)r_refdef.view.width     / (float)r_bloomstate.screentexturewidth;
3150         r_bloomstate.screentexcoord2f[3] = (float)r_refdef.view.height    / (float)r_bloomstate.screentextureheight;
3151         r_bloomstate.screentexcoord2f[4] = (float)r_refdef.view.width     / (float)r_bloomstate.screentexturewidth;
3152         r_bloomstate.screentexcoord2f[5] = 0;
3153         r_bloomstate.screentexcoord2f[6] = 0;
3154         r_bloomstate.screentexcoord2f[7] = 0;
3155
3156         // set up a texcoord array for the reduced resolution bloom image
3157         // (which will be additive blended over the screen image)
3158         r_bloomstate.bloomtexcoord2f[0] = 0;
3159         r_bloomstate.bloomtexcoord2f[1] = (float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
3160         r_bloomstate.bloomtexcoord2f[2] = (float)r_bloomstate.bloomwidth  / (float)r_bloomstate.bloomtexturewidth;
3161         r_bloomstate.bloomtexcoord2f[3] = (float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
3162         r_bloomstate.bloomtexcoord2f[4] = (float)r_bloomstate.bloomwidth  / (float)r_bloomstate.bloomtexturewidth;
3163         r_bloomstate.bloomtexcoord2f[5] = 0;
3164         r_bloomstate.bloomtexcoord2f[6] = 0;
3165         r_bloomstate.bloomtexcoord2f[7] = 0;
3166
3167         if (r_hdr.integer || r_bloom.integer)
3168         {
3169                 r_bloomstate.enabled = true;
3170                 r_bloomstate.hdr = r_hdr.integer != 0;
3171         }
3172 }
3173
3174 void R_Bloom_CopyBloomTexture(float colorscale)
3175 {
3176         r_refdef.stats.bloom++;
3177
3178         // scale down screen texture to the bloom texture size
3179         CHECKGLERROR
3180         qglViewport(r_refdef.view.x, vid.height - (r_refdef.view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
3181         GL_BlendFunc(GL_ONE, GL_ZERO);
3182         GL_Color(colorscale, colorscale, colorscale, 1);
3183         // TODO: optimize with multitexture or GLSL
3184         R_SetupGenericShader(true);
3185         R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
3186         R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
3187         R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3188         r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
3189
3190         // we now have a bloom image in the framebuffer
3191         // copy it into the bloom image texture for later processing
3192         R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
3193         GL_ActiveTexture(0);
3194         CHECKGLERROR
3195         qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.x, vid.height - (r_refdef.view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
3196         r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
3197 }
3198
3199 void R_Bloom_CopyHDRTexture(void)
3200 {
3201         R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
3202         GL_ActiveTexture(0);
3203         CHECKGLERROR
3204         qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.x, vid.height - (r_refdef.view.y + r_refdef.view.height), r_refdef.view.width, r_refdef.view.height);CHECKGLERROR
3205         r_refdef.stats.bloom_copypixels += r_refdef.view.width * r_refdef.view.height;
3206 }
3207
3208 void R_Bloom_MakeTexture(void)
3209 {
3210         int x, range, dir;
3211         float xoffset, yoffset, r, brighten;
3212
3213         r_refdef.stats.bloom++;
3214
3215         R_ResetViewRendering2D();
3216         R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
3217         R_Mesh_ColorPointer(NULL, 0, 0);
3218         R_SetupGenericShader(true);
3219
3220         // we have a bloom image in the framebuffer
3221         CHECKGLERROR
3222         qglViewport(r_refdef.view.x, vid.height - (r_refdef.view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
3223
3224         for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
3225         {
3226                 x *= 2;
3227                 r = bound(0, r_bloom_colorexponent.value / x, 1);
3228                 GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
3229                 GL_Color(r, r, r, 1);
3230                 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
3231                 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
3232                 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3233                 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
3234
3235                 // copy the vertically blurred bloom view to a texture
3236                 GL_ActiveTexture(0);
3237                 CHECKGLERROR
3238                 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.x, vid.height - (r_refdef.view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
3239                 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
3240         }
3241
3242         range = r_bloom_blur.integer * r_bloomstate.bloomwidth / 320;
3243         brighten = r_bloom_brighten.value;
3244         if (r_hdr.integer)
3245                 brighten *= r_hdr_range.value;
3246         R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
3247         R_Mesh_TexCoordPointer(0, 2, r_bloomstate.offsettexcoord2f, 0, 0);
3248
3249         for (dir = 0;dir < 2;dir++)
3250         {
3251                 // blend on at multiple vertical offsets to achieve a vertical blur
3252                 // TODO: do offset blends using GLSL
3253                 GL_BlendFunc(GL_ONE, GL_ZERO);
3254                 for (x = -range;x <= range;x++)
3255                 {
3256                         if (!dir){xoffset = 0;yoffset = x;}
3257                         else {xoffset = x;yoffset = 0;}
3258                         xoffset /= (float)r_bloomstate.bloomtexturewidth;
3259                         yoffset /= (float)r_bloomstate.bloomtextureheight;
3260                         // compute a texcoord array with the specified x and y offset
3261                         r_bloomstate.offsettexcoord2f[0] = xoffset+0;
3262                         r_bloomstate.offsettexcoord2f[1] = yoffset+(float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
3263                         r_bloomstate.offsettexcoord2f[2] = xoffset+(float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
3264                         r_bloomstate.offsettexcoord2f[3] = yoffset+(float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
3265                         r_bloomstate.offsettexcoord2f[4] = xoffset+(float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
3266                         r_bloomstate.offsettexcoord2f[5] = yoffset+0;
3267                         r_bloomstate.offsettexcoord2f[6] = xoffset+0;
3268                         r_bloomstate.offsettexcoord2f[7] = yoffset+0;
3269                         // this r value looks like a 'dot' particle, fading sharply to
3270                         // black at the edges
3271                         // (probably not realistic but looks good enough)
3272                         //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
3273                         //r = (dir ? 1.0f : brighten)/(range*2+1);
3274                         r = (dir ? 1.0f : brighten)/(range*2+1)*(1 - x*x/(float)(range*range));
3275                         GL_Color(r, r, r, 1);
3276                         R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3277                         r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
3278                         GL_BlendFunc(GL_ONE, GL_ONE);
3279                 }
3280
3281                 // copy the vertically blurred bloom view to a texture
3282                 GL_ActiveTexture(0);
3283                 CHECKGLERROR
3284                 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.x, vid.height - (r_refdef.view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
3285                 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
3286         }
3287
3288         // apply subtract last
3289         // (just like it would be in a GLSL shader)
3290         if (r_bloom_colorsubtract.value > 0 && gl_support_ext_blend_subtract)
3291         {
3292                 GL_BlendFunc(GL_ONE, GL_ZERO);
3293                 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
3294                 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
3295                 GL_Color(1, 1, 1, 1);
3296                 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3297                 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
3298
3299                 GL_BlendFunc(GL_ONE, GL_ONE);
3300                 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
3301                 R_Mesh_TexBind(0, R_GetTexture(r_texture_white));
3302                 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
3303                 GL_Color(r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, 1);
3304                 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3305                 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
3306                 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
3307
3308                 // copy the darkened bloom view to a texture
3309                 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
3310                 GL_ActiveTexture(0);
3311                 CHECKGLERROR
3312                 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.x, vid.height - (r_refdef.view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
3313                 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
3314         }
3315 }
3316
3317 void R_HDR_RenderBloomTexture(void)
3318 {
3319         int oldwidth, oldheight;
3320         float oldcolorscale;
3321
3322         oldcolorscale = r_refdef.view.colorscale;
3323         oldwidth = r_refdef.view.width;
3324         oldheight = r_refdef.view.height;
3325         r_refdef.view.width = r_bloomstate.bloomwidth;
3326         r_refdef.view.height = r_bloomstate.bloomheight;
3327
3328         // TODO: support GL_EXT_framebuffer_object rather than reusing the framebuffer?  it might improve SLI performance.
3329         // TODO: add exposure compensation features
3330         // TODO: add fp16 framebuffer support
3331
3332         r_refdef.view.showdebug = false;
3333         r_refdef.view.colorscale *= r_bloom_colorscale.value / bound(1, r_hdr_range.value, 16);
3334
3335         R_ClearScreen(r_refdef.fogenabled);
3336         if (r_timereport_active)
3337                 R_TimeReport("HDRclear");
3338
3339         r_waterstate.numwaterplanes = 0;
3340         R_RenderScene(r_waterstate.enabled);
3341         r_refdef.view.showdebug = true;
3342
3343         R_ResetViewRendering2D();
3344
3345         R_Bloom_CopyHDRTexture();
3346         R_Bloom_MakeTexture();
3347
3348         // restore the view settings
3349         r_refdef.view.width = oldwidth;
3350         r_refdef.view.height = oldheight;
3351         r_refdef.view.colorscale = oldcolorscale;
3352
3353         R_ResetViewRendering3D();
3354
3355         R_ClearScreen(r_refdef.fogenabled);
3356         if (r_timereport_active)
3357                 R_TimeReport("viewclear");
3358 }
3359
3360 static void R_BlendView(void)
3361 {
3362         if (r_bloomstate.texture_screen)
3363         {
3364                 // copy view into the screen texture
3365                 R_ResetViewRendering2D();
3366                 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
3367                 R_Mesh_ColorPointer(NULL, 0, 0);
3368                 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
3369                 GL_ActiveTexture(0);CHECKGLERROR
3370                 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.x, vid.height - (r_refdef.view.y + r_refdef.view.height), r_refdef.view.width, r_refdef.view.height);CHECKGLERROR
3371                 r_refdef.stats.bloom_copypixels += r_refdef.view.width * r_refdef.view.height;
3372         }
3373
3374         if (r_glsl.integer && gl_support_fragment_shader && (r_bloomstate.texture_screen || r_bloomstate.texture_bloom))
3375         {
3376                 unsigned int permutation =
3377                           (r_bloomstate.texture_bloom ? SHADERPERMUTATION_GLOW : 0)
3378                         | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VERTEXTEXTUREBLEND : 0)
3379                         | ((v_glslgamma.value && !vid_gammatables_trivial) ? SHADERPERMUTATION_GAMMARAMPS : 0)
3380                         | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0);
3381
3382                 if (r_bloomstate.texture_bloom && !r_bloomstate.hdr)
3383                 {
3384                         // render simple bloom effect
3385                         // copy the screen and shrink it and darken it for the bloom process
3386                         R_Bloom_CopyBloomTexture(r_bloom_colorscale.value);
3387                         // make the bloom texture
3388                         R_Bloom_MakeTexture();
3389                 }
3390
3391                 R_ResetViewRendering2D();
3392                 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
3393                 R_Mesh_ColorPointer(NULL, 0, 0);
3394                 GL_Color(1, 1, 1, 1);
3395                 GL_BlendFunc(GL_ONE, GL_ZERO);
3396                 R_SetupShader_SetPermutation(SHADERMODE_POSTPROCESS, permutation);
3397                 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
3398                 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
3399                 R_Mesh_TexBind(1, R_GetTexture(r_bloomstate.texture_bloom));
3400                 R_Mesh_TexCoordPointer(1, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
3401                 if (r_glsl_permutation->loc_Texture_Attenuation >= 0)
3402                         R_Mesh_TexBind(GL20TU_ATTENUATION, R_GetTexture(r_texture_gammaramps));
3403                 if (r_glsl_permutation->loc_TintColor >= 0)
3404                         qglUniform4fARB(r_glsl_permutation->loc_TintColor, r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
3405                 if (r_glsl_permutation->loc_ClientTime >= 0)
3406                         qglUniform1fARB(r_glsl_permutation->loc_ClientTime, cl.time);
3407                 if (r_glsl_permutation->loc_UserVec1 >= 0)
3408                 {
3409                         float a=0, b=0, c=0, d=0;
3410                         sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &a, &b, &c, &d);
3411                         qglUniform4fARB(r_glsl_permutation->loc_UserVec1, a, b, c, d);
3412                 }
3413                 if (r_glsl_permutation->loc_UserVec2 >= 0)
3414                 {
3415                         float a=0, b=0, c=0, d=0;
3416                         sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &a, &b, &c, &d);
3417                         qglUniform4fARB(r_glsl_permutation->loc_UserVec2, a, b, c, d);
3418                 }
3419                 if (r_glsl_permutation->loc_UserVec3 >= 0)
3420                 {
3421                         float a=0, b=0, c=0, d=0;
3422                         sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &a, &b, &c, &d);
3423                         qglUniform4fARB(r_glsl_permutation->loc_UserVec3, a, b, c, d);
3424                 }
3425                 if (r_glsl_permutation->loc_UserVec4 >= 0)
3426                 {
3427                         float a=0, b=0, c=0, d=0;
3428                         sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &a, &b, &c, &d);
3429                         qglUniform4fARB(r_glsl_permutation->loc_UserVec4, a, b, c, d);
3430                 }
3431                 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3432                 r_refdef.stats.bloom_drawpixels += r_refdef.view.width * r_refdef.view.height;
3433                 return;
3434         }
3435
3436
3437
3438         if (r_bloomstate.texture_bloom && r_bloomstate.hdr)
3439         {
3440                 // render high dynamic range bloom effect
3441                 // the bloom texture was made earlier this render, so we just need to
3442                 // blend it onto the screen...
3443                 R_ResetViewRendering2D();
3444                 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
3445                 R_Mesh_ColorPointer(NULL, 0, 0);
3446                 R_SetupGenericShader(true);
3447                 GL_Color(1, 1, 1, 1);
3448                 GL_BlendFunc(GL_ONE, GL_ONE);
3449                 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
3450                 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
3451                 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3452                 r_refdef.stats.bloom_drawpixels += r_refdef.view.width * r_refdef.view.height;
3453         }
3454         else if (r_bloomstate.texture_bloom)
3455         {
3456                 // render simple bloom effect
3457                 // copy the screen and shrink it and darken it for the bloom process
3458                 R_Bloom_CopyBloomTexture(r_bloom_colorscale.value);
3459                 // make the bloom texture
3460                 R_Bloom_MakeTexture();
3461                 // put the original screen image back in place and blend the bloom
3462                 // texture on it
3463                 R_ResetViewRendering2D();
3464                 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
3465                 R_Mesh_ColorPointer(NULL, 0, 0);
3466                 GL_Color(1, 1, 1, 1);
3467                 GL_BlendFunc(GL_ONE, GL_ZERO);
3468                 // do both in one pass if possible
3469                 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
3470                 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
3471                 if (r_textureunits.integer >= 2 && gl_combine.integer)
3472                 {
3473                         R_SetupGenericTwoTextureShader(GL_ADD);
3474                         R_Mesh_TexBind(1, R_GetTexture(r_bloomstate.texture_screen));
3475                         R_Mesh_TexCoordPointer(1, 2, r_bloomstate.screentexcoord2f, 0, 0);
3476                 }
3477                 else
3478                 {
3479                         R_SetupGenericShader(true);
3480                         R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3481                         r_refdef.stats.bloom_drawpixels += r_refdef.view.width * r_refdef.view.height;
3482                         // now blend on the bloom texture
3483                         GL_BlendFunc(GL_ONE, GL_ONE);
3484                         R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
3485                         R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
3486                 }
3487                 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3488                 r_refdef.stats.bloom_drawpixels += r_refdef.view.width * r_refdef.view.height;
3489         }
3490         if (r_refdef.viewblend[3] >= (1.0f / 256.0f))
3491         {
3492                 // apply a color tint to the whole view
3493                 R_ResetViewRendering2D();
3494                 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
3495                 R_Mesh_ColorPointer(NULL, 0, 0);
3496                 R_SetupGenericShader(false);
3497                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3498                 GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
3499                 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3500         }
3501 }
3502
3503 void R_RenderScene(qboolean addwaterplanes);
3504
3505 matrix4x4_t r_waterscrollmatrix;
3506
3507 void R_UpdateFogColor(void) // needs to be called before HDR subrender too, as that changes colorscale!
3508 {
3509         if (r_refdef.fog_density)
3510         {
3511                 r_refdef.fogcolor[0] = r_refdef.fog_red;
3512                 r_refdef.fogcolor[1] = r_refdef.fog_green;
3513                 r_refdef.fogcolor[2] = r_refdef.fog_blue;
3514
3515                 {
3516                         vec3_t fogvec;
3517                         VectorCopy(r_refdef.fogcolor, fogvec);
3518                         if(r_glsl.integer && (r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)) // need to support contrast boost
3519                         {
3520                                 //   color.rgb /= ((ContrastBoost - 1) * color.rgb + 1);
3521                                 fogvec[0] *= r_glsl_contrastboost.value / ((r_glsl_contrastboost.value - 1) * fogvec[0] + 1);
3522                                 fogvec[1] *= r_glsl_contrastboost.value / ((r_glsl_contrastboost.value - 1) * fogvec[1] + 1);
3523                                 fogvec[2] *= r_glsl_contrastboost.value / ((r_glsl_contrastboost.value - 1) * fogvec[2] + 1);
3524                         }
3525                         //   color.rgb *= ContrastBoost * SceneBrightness;
3526                         VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
3527                         r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
3528                         r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f);
3529                         r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f);
3530                 }
3531         }
3532 }
3533
3534 void R_UpdateVariables(void)
3535 {
3536         R_Textures_Frame();
3537
3538         r_refdef.farclip = 4096;
3539         if (r_refdef.scene.worldmodel)
3540                 r_refdef.farclip += VectorDistance(r_refdef.scene.worldmodel->normalmins, r_refdef.scene.worldmodel->normalmaxs);
3541         r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
3542
3543         if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
3544                 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
3545         r_refdef.polygonfactor = 0;
3546         r_refdef.polygonoffset = 0;
3547         r_refdef.shadowpolygonfactor = r_refdef.polygonfactor + r_shadow_polygonfactor.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
3548         r_refdef.shadowpolygonoffset = r_refdef.polygonoffset + r_shadow_polygonoffset.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
3549
3550         r_refdef.rtworld = r_shadow_realtime_world.integer;
3551         r_refdef.rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
3552         r_refdef.rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer && r_dynamic.integer;
3553         r_refdef.rtdlightshadows = r_refdef.rtdlight && r_shadow_realtime_dlight_shadows.integer && gl_stencil;
3554         r_refdef.lightmapintensity = r_refdef.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
3555         if (r_showsurfaces.integer)
3556         {
3557                 r_refdef.rtworld = false;
3558                 r_refdef.rtworldshadows = false;
3559                 r_refdef.rtdlight = false;
3560                 r_refdef.rtdlightshadows = false;
3561                 r_refdef.lightmapintensity = 0;
3562         }
3563
3564         if (gamemode == GAME_NEHAHRA)
3565         {
3566                 if (gl_fogenable.integer)
3567                 {
3568                         r_refdef.oldgl_fogenable = true;
3569                         r_refdef.fog_density = gl_fogdensity.value;
3570                         r_refdef.fog_red = gl_fogred.value;
3571                         r_refdef.fog_green = gl_foggreen.value;
3572                         r_refdef.fog_blue = gl_fogblue.value;
3573                         r_refdef.fog_alpha = 1;
3574                         r_refdef.fog_start = 0;
3575                         r_refdef.fog_end = gl_skyclip.value;
3576                 }
3577                 else if (r_refdef.oldgl_fogenable)
3578                 {
3579                         r_refdef.oldgl_fogenable = false;
3580                         r_refdef.fog_density = 0;
3581                         r_refdef.fog_red = 0;
3582                         r_refdef.fog_green = 0;
3583                         r_refdef.fog_blue = 0;
3584                         r_refdef.fog_alpha = 0;
3585                         r_refdef.fog_start = 0;
3586                         r_refdef.fog_end = 0;
3587                 }
3588         }
3589
3590         r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1);
3591         r_refdef.fog_start = max(0, r_refdef.fog_start);
3592         r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end);
3593
3594         // R_UpdateFogColor(); // why? R_RenderScene does it anyway
3595
3596         if (r_refdef.fog_density)
3597         {
3598                 r_refdef.fogenabled = true;
3599                 // this is the point where the fog reaches 0.9986 alpha, which we
3600                 // consider a good enough cutoff point for the texture
3601                 // (0.9986 * 256 == 255.6)
3602                 if (r_fog_exp2.integer)
3603                         r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start;
3604                 else
3605                         r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start;
3606                 r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end);
3607                 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
3608                 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
3609                 // fog color was already set
3610                 // update the fog texture
3611                 if (r_refdef.fogmasktable_start != r_refdef.fog_start || r_refdef.fogmasktable_alpha != r_refdef.fog_alpha || r_refdef.fogmasktable_density != r_refdef.fog_density || r_refdef.fogmasktable_range != r_refdef.fogrange)
3612                         R_BuildFogTexture();
3613         }
3614         else
3615                 r_refdef.fogenabled = false;
3616
3617         if(r_glsl.integer && v_glslgamma.integer && !vid_gammatables_trivial)
3618         {
3619                 if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
3620                 {
3621                         // build GLSL gamma texture
3622 #define RAMPWIDTH 256
3623                         unsigned short ramp[RAMPWIDTH * 3];
3624                         unsigned char ramprgb[RAMPWIDTH][4];
3625                         int i;
3626
3627                         r_texture_gammaramps_serial = vid_gammatables_serial;
3628
3629                         VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
3630                         for(i = 0; i < RAMPWIDTH; ++i)
3631                         {
3632                                 ramprgb[i][0] = ramp[i] >> 8;
3633                                 ramprgb[i][1] = ramp[i + RAMPWIDTH] >> 8;
3634                                 ramprgb[i][2] = ramp[i + 2 * RAMPWIDTH] >> 8;
3635                                 ramprgb[i][3] = 0;
3636                         }
3637                         if (r_texture_gammaramps)
3638                         {
3639                                 R_UpdateTexture(r_texture_gammaramps, &ramprgb[0][0], 0, 0, RAMPWIDTH, 1);
3640                         }
3641                         else
3642                         {
3643                                 r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &ramprgb[0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, NULL);
3644                         }
3645                 }
3646         }
3647         else
3648         {
3649                 // remove GLSL gamma texture
3650         }
3651 }
3652
3653 static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT;
3654 static r_refdef_scene_t r_scenes_store[ RST_COUNT ];
3655 /*
3656 ================
3657 R_SelectScene
3658 ================
3659 */
3660 void R_SelectScene( r_refdef_scene_type_t scenetype ) {
3661         if( scenetype != r_currentscenetype ) {
3662                 // store the old scenetype
3663                 r_scenes_store[ r_currentscenetype ] = r_refdef.scene;
3664                 r_currentscenetype = scenetype;
3665                 // move in the new scene
3666                 r_refdef.scene = r_scenes_store[ r_currentscenetype ];
3667         }
3668 }
3669
3670 /*
3671 ================
3672 R_GetScenePointer
3673 ================
3674 */
3675 r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype )
3676 {
3677         // of course, we could also add a qboolean that provides a lock state and a ReleaseScenePointer function..
3678         if( scenetype == r_currentscenetype ) {
3679                 return &r_refdef.scene;
3680         } else {
3681                 return &r_scenes_store[ scenetype ];
3682         }
3683 }
3684
3685 /*
3686 ================
3687 R_RenderView
3688 ================
3689 */
3690 void R_RenderView(void)
3691 {
3692         if (!r_refdef.scene.entities/* || !r_refdef.scene.worldmodel*/)
3693                 return; //Host_Error ("R_RenderView: NULL worldmodel");
3694
3695         r_refdef.view.colorscale = r_hdr_scenebrightness.value;
3696
3697         // break apart the view matrix into vectors for various purposes
3698         // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
3699         // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc
3700         Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);