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