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