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