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