2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
27 mempool_t *r_main_mempool;
28 rtexturepool_t *r_main_texturepool;
35 r_viewcache_t r_viewcache;
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"};
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)"};
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)"};
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)"};
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"};
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"};
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"};
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)"};
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"};
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"};
111 cvar_t gl_lightmaps = {0, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers)"};
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 cvar_t r_track_sprites = {CVAR_SAVE, "r_track_sprites", "1", "track SPR_LABEL* sprites by putting them as indicator at the screen border to rotate to"};
116 cvar_t r_track_sprites_flags = {CVAR_SAVE, "r_track_sprites_flags", "1", "1: Rotate sprites accodringly, 2: Make it a continuous rotation"};
117 cvar_t r_track_sprites_scalew = {CVAR_SAVE, "r_track_sprites_scalew", "1", "width scaling of tracked sprites"};
118 cvar_t r_track_sprites_scaleh = {CVAR_SAVE, "r_track_sprites_scaleh", "1", "height scaling of tracked sprites"};
120 extern qboolean v_flipped_state;
122 typedef struct r_glsl_bloomshader_s
125 int loc_Texture_Bloom;
127 r_glsl_bloomshader_t;
129 static struct r_bloomstate_s
134 int bloomwidth, bloomheight;
136 int screentexturewidth, screentextureheight;
137 rtexture_t *texture_screen;
139 int bloomtexturewidth, bloomtextureheight;
140 rtexture_t *texture_bloom;
142 r_glsl_bloomshader_t *shader;
144 // arrays for rendering the screen passes
145 float screentexcoord2f[8];
146 float bloomtexcoord2f[8];
147 float offsettexcoord2f[8];
151 typedef struct r_waterstate_waterplane_s
153 rtexture_t *texture_refraction;
154 rtexture_t *texture_reflection;
156 int materialflags; // combined flags of all water surfaces on this plane
157 unsigned char pvsbits[(32768+7)>>3]; // FIXME: buffer overflow on huge maps
160 r_waterstate_waterplane_t;
162 #define MAX_WATERPLANES 16
164 static struct r_waterstate_s
168 qboolean renderingscene; // true while rendering a refraction or reflection texture, disables water surfaces
170 int waterwidth, waterheight;
171 int texturewidth, textureheight;
173 int maxwaterplanes; // same as MAX_WATERPLANES
175 r_waterstate_waterplane_t waterplanes[MAX_WATERPLANES];
177 float screenscale[2];
178 float screencenter[2];
182 // shadow volume bsp struct with automatically growing nodes buffer
185 rtexture_t *r_texture_blanknormalmap;
186 rtexture_t *r_texture_white;
187 rtexture_t *r_texture_grey128;
188 rtexture_t *r_texture_black;
189 rtexture_t *r_texture_notexture;
190 rtexture_t *r_texture_whitecube;
191 rtexture_t *r_texture_normalizationcube;
192 rtexture_t *r_texture_fogattenuation;
193 //rtexture_t *r_texture_fogintensity;
195 char r_qwskincache[MAX_SCOREBOARD][MAX_QPATH];
196 skinframe_t *r_qwskincache_skinframe[MAX_SCOREBOARD];
198 // vertex coordinates for a quad that covers the screen exactly
199 const static float r_screenvertex3f[12] =
207 extern void R_DrawModelShadows(void);
209 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
212 for (i = 0;i < verts;i++)
223 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
226 for (i = 0;i < verts;i++)
236 // FIXME: move this to client?
239 if (gamemode == GAME_NEHAHRA)
241 Cvar_Set("gl_fogenable", "0");
242 Cvar_Set("gl_fogdensity", "0.2");
243 Cvar_Set("gl_fogred", "0.3");
244 Cvar_Set("gl_foggreen", "0.3");
245 Cvar_Set("gl_fogblue", "0.3");
247 r_refdef.fog_density = r_refdef.fog_red = r_refdef.fog_green = r_refdef.fog_blue = 0.0f;
250 float FogPoint_World(const vec3_t p)
252 int fogmasktableindex = (int)(VectorDistance((p), r_view.origin) * r_refdef.fogmasktabledistmultiplier);
253 return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
256 float FogPoint_Model(const vec3_t p)
258 int fogmasktableindex = (int)(VectorDistance((p), rsurface.modelorg) * r_refdef.fogmasktabledistmultiplier);
259 return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
262 static void R_BuildBlankTextures(void)
264 unsigned char data[4];
265 data[0] = 128; // normal X
266 data[1] = 128; // normal Y
267 data[2] = 255; // normal Z
268 data[3] = 128; // height
269 r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
274 r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
279 r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
284 r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
287 static void R_BuildNoTexture(void)
290 unsigned char pix[16][16][4];
291 // this makes a light grey/dark grey checkerboard texture
292 for (y = 0;y < 16;y++)
294 for (x = 0;x < 16;x++)
296 if ((y < 8) ^ (x < 8))
312 r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP, NULL);
315 static void R_BuildWhiteCube(void)
317 unsigned char data[6*1*1*4];
318 data[ 0] = 255;data[ 1] = 255;data[ 2] = 255;data[ 3] = 255;
319 data[ 4] = 255;data[ 5] = 255;data[ 6] = 255;data[ 7] = 255;
320 data[ 8] = 255;data[ 9] = 255;data[10] = 255;data[11] = 255;
321 data[12] = 255;data[13] = 255;data[14] = 255;data[15] = 255;
322 data[16] = 255;data[17] = 255;data[18] = 255;data[19] = 255;
323 data[20] = 255;data[21] = 255;data[22] = 255;data[23] = 255;
324 r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
327 static void R_BuildNormalizationCube(void)
331 vec_t s, t, intensity;
333 unsigned char data[6][NORMSIZE][NORMSIZE][4];
334 for (side = 0;side < 6;side++)
336 for (y = 0;y < NORMSIZE;y++)
338 for (x = 0;x < NORMSIZE;x++)
340 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
341 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
376 intensity = 127.0f / sqrt(DotProduct(v, v));
377 data[side][y][x][0] = (unsigned char)(128.0f + intensity * v[0]);
378 data[side][y][x][1] = (unsigned char)(128.0f + intensity * v[1]);
379 data[side][y][x][2] = (unsigned char)(128.0f + intensity * v[2]);
380 data[side][y][x][3] = 255;
384 r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, &data[0][0][0][0], TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
387 static void R_BuildFogTexture(void)
391 unsigned char data1[FOGWIDTH][4];
392 //unsigned char data2[FOGWIDTH][4];
393 for (x = 0;x < FOGWIDTH;x++)
395 b = (int)(r_refdef.fogmasktable[x * (FOGMASKTABLEWIDTH - 1) / (FOGWIDTH - 1)] * 255);
400 //data2[x][0] = 255 - b;
401 //data2[x][1] = 255 - b;
402 //data2[x][2] = 255 - b;
405 r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
406 //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
409 static const char *builtinshaderstring =
410 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
411 "// written by Forest 'LordHavoc' Hale\n"
413 "// common definitions between vertex shader and fragment shader:\n"
415 "#ifdef __GLSL_CG_DATA_TYPES\n"
416 "# define myhalf half\n"
417 "# define myhvec2 hvec2\n"
418 "# define myhvec3 hvec3\n"
419 "# define myhvec4 hvec4\n"
421 "# define myhalf float\n"
422 "# define myhvec2 vec2\n"
423 "# define myhvec3 vec3\n"
424 "# define myhvec4 vec4\n"
427 "varying vec2 TexCoord;\n"
428 "varying vec2 TexCoordLightmap;\n"
430 "//#ifdef MODE_LIGHTSOURCE\n"
431 "varying vec3 CubeVector;\n"
434 "//#ifdef MODE_LIGHTSOURCE\n"
435 "varying vec3 LightVector;\n"
437 "//# ifdef MODE_LIGHTDIRECTION\n"
438 "//varying vec3 LightVector;\n"
442 "varying vec3 EyeVector;\n"
444 "varying vec3 EyeVectorModelSpace;\n"
447 "varying vec3 VectorS; // direction of S texcoord (sometimes crudely called tangent)\n"
448 "varying vec3 VectorT; // direction of T texcoord (sometimes crudely called binormal)\n"
449 "varying vec3 VectorR; // direction of R texcoord (surface normal)\n"
451 "//#ifdef MODE_WATER\n"
452 "varying vec4 ModelViewProjectionPosition;\n"
454 "//# ifdef MODE_REFRACTION\n"
455 "//varying vec4 ModelViewProjectionPosition;\n"
457 "//# ifdef USEREFLECTION\n"
458 "//varying vec4 ModelViewProjectionPosition;\n"
467 "// vertex shader specific:\n"
468 "#ifdef VERTEX_SHADER\n"
470 "uniform vec3 LightPosition;\n"
471 "uniform vec3 EyePosition;\n"
472 "uniform vec3 LightDir;\n"
474 "// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3)\n"
478 " gl_FrontColor = gl_Color;\n"
479 " // copy the surface texcoord\n"
480 " TexCoord = vec2(gl_TextureMatrix[0] * gl_MultiTexCoord0);\n"
481 "#ifndef MODE_LIGHTSOURCE\n"
482 "# ifndef MODE_LIGHTDIRECTION\n"
483 " TexCoordLightmap = vec2(gl_MultiTexCoord4);\n"
487 "#ifdef MODE_LIGHTSOURCE\n"
488 " // transform vertex position into light attenuation/cubemap space\n"
489 " // (-1 to +1 across the light box)\n"
490 " CubeVector = vec3(gl_TextureMatrix[3] * gl_Vertex);\n"
492 " // transform unnormalized light direction into tangent space\n"
493 " // (we use unnormalized to ensure that it interpolates correctly and then\n"
494 " // normalize it per pixel)\n"
495 " vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n"
496 " LightVector.x = dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
497 " LightVector.y = dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
498 " LightVector.z = dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n"
501 "#ifdef MODE_LIGHTDIRECTION\n"
502 " LightVector.x = dot(LightDir, gl_MultiTexCoord1.xyz);\n"
503 " LightVector.y = dot(LightDir, gl_MultiTexCoord2.xyz);\n"
504 " LightVector.z = dot(LightDir, gl_MultiTexCoord3.xyz);\n"
507 " // transform unnormalized eye direction into tangent space\n"
509 " vec3 EyeVectorModelSpace;\n"
511 " EyeVectorModelSpace = EyePosition - gl_Vertex.xyz;\n"
512 " EyeVector.x = dot(EyeVectorModelSpace, gl_MultiTexCoord1.xyz);\n"
513 " EyeVector.y = dot(EyeVectorModelSpace, gl_MultiTexCoord2.xyz);\n"
514 " EyeVector.z = dot(EyeVectorModelSpace, gl_MultiTexCoord3.xyz);\n"
516 "#ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
517 " VectorS = gl_MultiTexCoord1.xyz;\n"
518 " VectorT = gl_MultiTexCoord2.xyz;\n"
519 " VectorR = gl_MultiTexCoord3.xyz;\n"
522 "//#if defined(MODE_WATER) || defined(MODE_REFRACTION) || defined(USEREFLECTION)\n"
523 "// ModelViewProjectionPosition = gl_Vertex * gl_ModelViewProjectionMatrix;\n"
524 "// //ModelViewProjectionPosition_svector = (gl_Vertex + vec4(gl_MultiTexCoord1.xyz, 0)) * gl_ModelViewProjectionMatrix - ModelViewProjectionPosition;\n"
525 "// //ModelViewProjectionPosition_tvector = (gl_Vertex + vec4(gl_MultiTexCoord2.xyz, 0)) * gl_ModelViewProjectionMatrix - ModelViewProjectionPosition;\n"
528 "// transform vertex to camera space, using ftransform to match non-VS\n"
530 " gl_Position = ftransform();\n"
532 "#ifdef MODE_WATER\n"
533 " ModelViewProjectionPosition = gl_Position;\n"
535 "#ifdef MODE_REFRACTION\n"
536 " ModelViewProjectionPosition = gl_Position;\n"
538 "#ifdef USEREFLECTION\n"
539 " ModelViewProjectionPosition = gl_Position;\n"
543 "#endif // VERTEX_SHADER\n"
548 "// fragment shader specific:\n"
549 "#ifdef FRAGMENT_SHADER\n"
551 "// 13 textures, we can only use up to 16 on DX9-class hardware\n"
552 "uniform sampler2D Texture_Normal;\n"
553 "uniform sampler2D Texture_Color;\n"
554 "uniform sampler2D Texture_Gloss;\n"
555 "uniform samplerCube Texture_Cube;\n"
556 "uniform sampler2D Texture_Attenuation;\n"
557 "uniform sampler2D Texture_FogMask;\n"
558 "uniform sampler2D Texture_Pants;\n"
559 "uniform sampler2D Texture_Shirt;\n"
560 "uniform sampler2D Texture_Lightmap;\n"
561 "uniform sampler2D Texture_Deluxemap;\n"
562 "uniform sampler2D Texture_Glow;\n"
563 "uniform sampler2D Texture_Reflection;\n"
564 "uniform sampler2D Texture_Refraction;\n"
566 "uniform myhvec3 LightColor;\n"
567 "uniform myhvec3 AmbientColor;\n"
568 "uniform myhvec3 DiffuseColor;\n"
569 "uniform myhvec3 SpecularColor;\n"
570 "uniform myhvec3 Color_Pants;\n"
571 "uniform myhvec3 Color_Shirt;\n"
572 "uniform myhvec3 FogColor;\n"
574 "//#ifdef MODE_WATER\n"
575 "uniform vec4 DistortScaleRefractReflect;\n"
576 "uniform vec4 ScreenScaleRefractReflect;\n"
577 "uniform vec4 ScreenCenterRefractReflect;\n"
578 "uniform myhvec4 RefractColor;\n"
579 "uniform myhvec4 ReflectColor;\n"
580 "uniform myhalf ReflectFactor;\n"
581 "uniform myhalf ReflectOffset;\n"
583 "//# ifdef MODE_REFRACTION\n"
584 "//uniform vec4 DistortScaleRefractReflect;\n"
585 "//uniform vec4 ScreenScaleRefractReflect;\n"
586 "//uniform vec4 ScreenCenterRefractReflect;\n"
587 "//uniform myhvec4 RefractColor;\n"
588 "//# ifdef USEREFLECTION\n"
589 "//uniform myhvec4 ReflectColor;\n"
592 "//# ifdef USEREFLECTION\n"
593 "//uniform vec4 DistortScaleRefractReflect;\n"
594 "//uniform vec4 ScreenScaleRefractReflect;\n"
595 "//uniform vec4 ScreenCenterRefractReflect;\n"
596 "//uniform myhvec4 ReflectColor;\n"
601 "uniform myhalf GlowScale;\n"
602 "uniform myhalf SceneBrightness;\n"
603 "#ifdef USECONTRASTBOOST\n"
604 "uniform myhalf ContrastBoostCoeff;\n"
607 "uniform float OffsetMapping_Scale;\n"
608 "uniform float OffsetMapping_Bias;\n"
609 "uniform float FogRangeRecip;\n"
611 "uniform myhalf AmbientScale;\n"
612 "uniform myhalf DiffuseScale;\n"
613 "uniform myhalf SpecularScale;\n"
614 "uniform myhalf SpecularPower;\n"
616 "#ifdef USEOFFSETMAPPING\n"
617 "vec2 OffsetMapping(vec2 TexCoord)\n"
619 "#ifdef USEOFFSETMAPPING_RELIEFMAPPING\n"
620 " // 14 sample relief mapping: linear search and then binary search\n"
621 " // this basically steps forward a small amount repeatedly until it finds\n"
622 " // itself inside solid, then jitters forward and back using decreasing\n"
623 " // amounts to find the impact\n"
624 " //vec3 OffsetVector = vec3(EyeVector.xy * ((1.0 / EyeVector.z) * OffsetMapping_Scale) * vec2(-1, 1), -1);\n"
625 " //vec3 OffsetVector = vec3(normalize(EyeVector.xy) * OffsetMapping_Scale * vec2(-1, 1), -1);\n"
626 " vec3 OffsetVector = vec3(normalize(EyeVector).xy * OffsetMapping_Scale * vec2(-1, 1), -1);\n"
627 " vec3 RT = vec3(TexCoord, 1);\n"
628 " OffsetVector *= 0.1;\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);\n"
635 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
636 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
637 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
638 " RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) - 0.5);\n"
639 " RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) * 0.5 - 0.25);\n"
640 " RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) * 0.25 - 0.125);\n"
641 " RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) * 0.125 - 0.0625);\n"
642 " RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) * 0.0625 - 0.03125);\n"
645 " // 3 sample offset mapping (only 3 samples because of ATI Radeon 9500-9800/X300 limits)\n"
646 " // this basically moves forward the full distance, and then backs up based\n"
647 " // on height of samples\n"
648 " //vec2 OffsetVector = vec2(EyeVector.xy * ((1.0 / EyeVector.z) * OffsetMapping_Scale) * vec2(-1, 1));\n"
649 " //vec2 OffsetVector = vec2(normalize(EyeVector.xy) * OffsetMapping_Scale * vec2(-1, 1));\n"
650 " vec2 OffsetVector = vec2(normalize(EyeVector).xy * OffsetMapping_Scale * vec2(-1, 1));\n"
651 " TexCoord += OffsetVector;\n"
652 " OffsetVector *= 0.333;\n"
653 " TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
654 " TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
655 " TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
656 " return TexCoord;\n"
659 "#endif // USEOFFSETMAPPING\n"
661 "#ifdef MODE_WATER\n"
666 "#ifdef USEOFFSETMAPPING\n"
667 " // apply offsetmapping\n"
668 " vec2 TexCoordOffset = OffsetMapping(TexCoord);\n"
669 "#define TexCoord TexCoordOffset\n"
672 " vec4 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect * (1.0 / ModelViewProjectionPosition.w);\n"
673 " //vec4 ScreenTexCoord = (ModelViewProjectionPosition.xyxy + normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
674 " vec4 ScreenTexCoord = ModelViewProjectionPosition.xyxy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect + vec2(normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5))).xyxy * DistortScaleRefractReflect;\n"
675 " float Fresnel = pow(min(1.0, 1.0 - float(normalize(EyeVector).z)), 5.0) * ReflectFactor + ReflectOffset;\n"
676 " gl_FragColor = mix(texture2D(Texture_Refraction, ScreenTexCoord.xy) * RefractColor, texture2D(Texture_Reflection, ScreenTexCoord.zw) * ReflectColor, Fresnel);\n"
679 "#else // MODE_WATER\n"
680 "#ifdef MODE_REFRACTION\n"
682 "// refraction pass\n"
685 "#ifdef USEOFFSETMAPPING\n"
686 " // apply offsetmapping\n"
687 " vec2 TexCoordOffset = OffsetMapping(TexCoord);\n"
688 "#define TexCoord TexCoordOffset\n"
691 " vec2 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect.xy * (1.0 / ModelViewProjectionPosition.w);\n"
692 " //vec2 ScreenTexCoord = (ModelViewProjectionPosition.xy + normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5)).xy * DistortScaleRefractReflect.xy * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy;\n"
693 " vec2 ScreenTexCoord = ModelViewProjectionPosition.xy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy + vec2(normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5))).xy * DistortScaleRefractReflect.xy;\n"
694 " gl_FragColor = texture2D(Texture_Refraction, ScreenTexCoord) * RefractColor;\n"
697 "#else // MODE_REFRACTION\n"
700 "#ifdef USEOFFSETMAPPING\n"
701 " // apply offsetmapping\n"
702 " vec2 TexCoordOffset = OffsetMapping(TexCoord);\n"
703 "#define TexCoord TexCoordOffset\n"
706 " // combine the diffuse textures (base, pants, shirt)\n"
707 " myhvec4 color = myhvec4(texture2D(Texture_Color, TexCoord));\n"
708 "#ifdef USECOLORMAPPING\n"
709 " color.rgb += myhvec3(texture2D(Texture_Pants, TexCoord)) * Color_Pants + myhvec3(texture2D(Texture_Shirt, TexCoord)) * Color_Shirt;\n"
715 "#ifdef MODE_LIGHTSOURCE\n"
718 " // calculate surface normal, light normal, and specular normal\n"
719 " // compute color intensity for the two textures (colormap and glossmap)\n"
720 " // scale by light color and attenuation as efficiently as possible\n"
721 " // (do as much scalar math as possible rather than vector math)\n"
722 "# ifdef USESPECULAR\n"
723 " myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5));\n"
724 " myhvec3 diffusenormal = myhvec3(normalize(LightVector));\n"
725 " myhvec3 specularnormal = normalize(diffusenormal + myhvec3(normalize(EyeVector)));\n"
727 " // calculate directional shading\n"
728 " 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"
730 "# ifdef USEDIFFUSE\n"
731 " myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5));\n"
732 " myhvec3 diffusenormal = myhvec3(normalize(LightVector));\n"
734 " // calculate directional shading\n"
735 " 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"
737 " // calculate directionless shading\n"
738 " color.rgb = color.rgb * LightColor * myhalf(texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0)));\n"
742 "# ifdef USECUBEFILTER\n"
743 " // apply light cubemap filter\n"
744 " //color.rgb *= normalize(CubeVector) * 0.5 + 0.5;//vec3(textureCube(Texture_Cube, CubeVector));\n"
745 " color.rgb *= myhvec3(textureCube(Texture_Cube, CubeVector));\n"
747 " color *= myhvec4(gl_Color);\n"
748 "#endif // MODE_LIGHTSOURCE\n"
753 "#ifdef MODE_LIGHTDIRECTION\n"
754 " // directional model lighting\n"
756 " // get the surface normal and light normal\n"
757 " myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5));\n"
758 " myhvec3 diffusenormal = myhvec3(LightVector);\n"
760 " // calculate directional shading\n"
761 " color.rgb *= AmbientColor + DiffuseColor * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0));\n"
762 "# ifdef USESPECULAR\n"
763 " myhvec3 specularnormal = normalize(diffusenormal + myhvec3(normalize(EyeVector)));\n"
764 " color.rgb += myhvec3(texture2D(Texture_Gloss, TexCoord)) * SpecularColor * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
766 " color *= myhvec4(gl_Color);\n"
767 "#endif // MODE_LIGHTDIRECTION\n"
772 "#ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
773 " // deluxemap lightmapping using light vectors in modelspace (evil q3map2)\n"
775 " // get the surface normal and light normal\n"
776 " myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5));\n"
778 " myhvec3 diffusenormal_modelspace = myhvec3(texture2D(Texture_Deluxemap, TexCoordLightmap)) - myhvec3(0.5);\n"
779 " myhvec3 diffusenormal = normalize(myhvec3(dot(diffusenormal_modelspace, myhvec3(VectorS)), dot(diffusenormal_modelspace, myhvec3(VectorT)), dot(diffusenormal_modelspace, myhvec3(VectorR))));\n"
780 " // calculate directional shading\n"
781 " myhvec3 tempcolor = color.rgb * (DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0)));\n"
782 "# ifdef USESPECULAR\n"
783 " myhvec3 specularnormal = myhvec3(normalize(diffusenormal + myhvec3(normalize(EyeVector))));\n"
784 " tempcolor += myhvec3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
787 " // apply lightmap color\n"
788 " color.rgb = myhvec4(tempcolor,1) * myhvec4(texture2D(Texture_Lightmap, TexCoordLightmap)) * myhvec4(gl_Color) + myhvec4(color.rgb * AmbientScale, 0);\n"
789 "#endif // MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
794 "#ifdef MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n"
795 " // deluxemap lightmapping using light vectors in tangentspace (hmap2 -light)\n"
797 " // get the surface normal and light normal\n"
798 " myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5));\n"
800 " myhvec3 diffusenormal = normalize(myhvec3(texture2D(Texture_Deluxemap, TexCoordLightmap)) - myhvec3(0.5));\n"
801 " // calculate directional shading\n"
802 " myhvec3 tempcolor = color.rgb * (DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0)));\n"
803 "# ifdef USESPECULAR\n"
804 " myhvec3 specularnormal = myhvec3(normalize(diffusenormal + myhvec3(normalize(EyeVector))));\n"
805 " tempcolor += myhvec3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
808 " // apply lightmap color\n"
809 " color = myhvec4(tempcolor, 1) * myhvec4(texture2D(Texture_Lightmap, TexCoordLightmap)) * myhvec4(gl_Color) + myhvec4(color.rgb * AmbientScale, 0);\n"
810 "#endif // MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n"
815 "#ifdef MODE_LIGHTMAP\n"
816 " // apply lightmap color\n"
817 " color *= myhvec4(texture2D(Texture_Lightmap, TexCoordLightmap)) * myhvec4(gl_Color) * myhvec4(myhvec3(DiffuseScale), 1) + myhvec4(myhvec3(AmbientScale), 0);\n"
818 "#endif // MODE_LIGHTMAP\n"
828 " color.rgb += myhvec3(texture2D(Texture_Glow, TexCoord)) * GlowScale;\n"
831 "#ifdef USECONTRASTBOOST\n"
832 " color.rgb = color.rgb / (ContrastBoostCoeff * color.rgb + myhvec3(1, 1, 1));\n"
835 " color.rgb *= SceneBrightness;\n"
837 "#ifndef MODE_LIGHTSOURCE\n"
838 "# ifdef USEREFLECTION\n"
839 " vec4 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect * (1.0 / ModelViewProjectionPosition.w);\n"
840 " //vec4 ScreenTexCoord = (ModelViewProjectionPosition.xyxy + normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
841 " vec4 ScreenTexCoord = ModelViewProjectionPosition.xyxy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect + vec3(normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5))).xyxy * DistortScaleRefractReflect;\n"
842 " color.rgb = mix(color.rgb, myhvec3(texture2D(Texture_Reflection, ScreenTexCoord.zw)) * ReflectColor.rgb, ReflectColor.a);\n"
848 " color.rgb = mix(FogColor, color.rgb, myhalf(texture2D(Texture_FogMask, myhvec2(length(EyeVectorModelSpace)*FogRangeRecip, 0.0))));\n"
851 " gl_FragColor = vec4(color);\n"
853 "#endif // MODE_REFRACTION\n"
854 "#endif // MODE_WATER\n"
856 "#endif // FRAGMENT_SHADER\n"
859 #define SHADERPERMUTATION_COLORMAPPING (1<<0) // indicates this is a colormapped skin
860 #define SHADERPERMUTATION_CONTRASTBOOST (1<<1) // r_glsl_contrastboost boosts the contrast at low color levels (similar to gamma)
861 #define SHADERPERMUTATION_FOG (1<<2) // tint the color by fog color or black if using additive blend mode
862 #define SHADERPERMUTATION_CUBEFILTER (1<<3) // (lightsource) use cubemap light filter
863 #define SHADERPERMUTATION_GLOW (1<<4) // (lightmap) blend in an additive glow texture
864 #define SHADERPERMUTATION_DIFFUSE (1<<5) // (lightsource) whether to use directional shading
865 #define SHADERPERMUTATION_SPECULAR (1<<6) // (lightsource or deluxemapping) render specular effects
866 #define SHADERPERMUTATION_REFLECTION (1<<7) // normalmap-perturbed reflection of the scene infront of the surface, preformed as an overlay on the surface
867 #define SHADERPERMUTATION_OFFSETMAPPING (1<<8) // adjust texcoords to roughly simulate a displacement mapped surface
868 #define SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING (1<<9) // adjust texcoords to accurately simulate a displacement mapped surface (requires OFFSETMAPPING to also be set!)
869 #define SHADERPERMUTATION_MODEBASE (1<<10) // multiplier for the SHADERMODE_ values to get a valid index
871 // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
872 const char *shaderpermutationinfo[][2] =
874 {"#define USECOLORMAPPING\n", " colormapping"},
875 {"#define USECONTRASTBOOST\n", " contrastboost"},
876 {"#define USEFOG\n", " fog"},
877 {"#define USECUBEFILTER\n", " cubefilter"},
878 {"#define USEGLOW\n", " glow"},
879 {"#define USEDIFFUSE\n", " diffuse"},
880 {"#define USESPECULAR\n", " specular"},
881 {"#define USEREFLECTION\n", " reflection"},
882 {"#define USEOFFSETMAPPING\n", " offsetmapping"},
883 {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
887 // this enum is multiplied by SHADERPERMUTATION_MODEBASE
888 typedef enum shadermode_e
890 SHADERMODE_LIGHTMAP, // (lightmap) use directional pixel shading from fixed light direction (q3bsp)
891 SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE, // (lightmap) use directional pixel shading from texture containing modelspace light directions (deluxemap)
892 SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE, // (lightmap) use directional pixel shading from texture containing tangentspace light directions (deluxemap)
893 SHADERMODE_LIGHTDIRECTION, // (lightmap) use directional pixel shading from fixed light direction (q3bsp)
894 SHADERMODE_LIGHTSOURCE, // (lightsource) use directional pixel shading from light source (rtlight)
895 SHADERMODE_REFRACTION, // refract background (the material is rendered normally after this pass)
896 SHADERMODE_WATER, // refract background and reflection (the material is rendered normally after this pass)
901 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
902 const char *shadermodeinfo[][2] =
904 {"#define MODE_LIGHTMAP\n", " lightmap"},
905 {"#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
906 {"#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
907 {"#define MODE_LIGHTDIRECTION\n", " lightdirection"},
908 {"#define MODE_LIGHTSOURCE\n", " lightsource"},
909 {"#define MODE_REFRACTION\n", " refraction"},
910 {"#define MODE_WATER\n", " water"},
914 #define SHADERPERMUTATION_INDICES (SHADERPERMUTATION_MODEBASE * SHADERMODE_COUNT)
916 typedef struct r_glsl_permutation_s
918 // indicates if we have tried compiling this permutation already
920 // 0 if compilation failed
922 // locations of detected uniforms in program object, or -1 if not found
923 int loc_Texture_Normal;
924 int loc_Texture_Color;
925 int loc_Texture_Gloss;
926 int loc_Texture_Cube;
927 int loc_Texture_Attenuation;
928 int loc_Texture_FogMask;
929 int loc_Texture_Pants;
930 int loc_Texture_Shirt;
931 int loc_Texture_Lightmap;
932 int loc_Texture_Deluxemap;
933 int loc_Texture_Glow;
934 int loc_Texture_Refraction;
935 int loc_Texture_Reflection;
937 int loc_LightPosition;
942 int loc_FogRangeRecip;
943 int loc_AmbientScale;
944 int loc_DiffuseScale;
945 int loc_SpecularScale;
946 int loc_SpecularPower;
948 int loc_SceneBrightness; // or: Scenebrightness * ContrastBoost
949 int loc_OffsetMapping_Scale;
950 int loc_AmbientColor;
951 int loc_DiffuseColor;
952 int loc_SpecularColor;
954 int loc_ContrastBoostCoeff; // 1 - 1/ContrastBoost
955 int loc_DistortScaleRefractReflect;
956 int loc_ScreenScaleRefractReflect;
957 int loc_ScreenCenterRefractReflect;
958 int loc_RefractColor;
959 int loc_ReflectColor;
960 int loc_ReflectFactor;
961 int loc_ReflectOffset;
963 r_glsl_permutation_t;
965 // information about each possible shader permutation
966 r_glsl_permutation_t r_glsl_permutations[SHADERPERMUTATION_INDICES];
967 // currently selected permutation
968 r_glsl_permutation_t *r_glsl_permutation;
970 // these are additional flags used only by R_GLSL_CompilePermutation
971 #define SHADERTYPE_USES_VERTEXSHADER (1<<0)
972 #define SHADERTYPE_USES_GEOMETRYSHADER (1<<1)
973 #define SHADERTYPE_USES_FRAGMENTSHADER (1<<2)
975 static void R_GLSL_CompilePermutation(const char *filename, int permutation, int shadertype)
978 qboolean shaderfound;
979 r_glsl_permutation_t *p = r_glsl_permutations + permutation;
980 int vertstrings_count;
981 int geomstrings_count;
982 int fragstrings_count;
984 const char *vertstrings_list[32+1];
985 const char *geomstrings_list[32+1];
986 const char *fragstrings_list[32+1];
987 char permutationname[256];
992 vertstrings_list[0] = "#define VERTEX_SHADER\n";
993 geomstrings_list[0] = "#define GEOMETRY_SHADER\n";
994 fragstrings_list[0] = "#define FRAGMENT_SHADER\n";
995 vertstrings_count = 1;
996 geomstrings_count = 1;
997 fragstrings_count = 1;
998 permutationname[0] = 0;
999 i = permutation / SHADERPERMUTATION_MODEBASE;
1000 vertstrings_list[vertstrings_count++] = shadermodeinfo[i][0];
1001 geomstrings_list[geomstrings_count++] = shadermodeinfo[i][0];
1002 fragstrings_list[fragstrings_count++] = shadermodeinfo[i][0];
1003 strlcat(permutationname, shadermodeinfo[i][1], sizeof(permutationname));
1004 for (i = 0;shaderpermutationinfo[i][0];i++)
1006 if (permutation & (1<<i))
1008 vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i][0];
1009 geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i][0];
1010 fragstrings_list[fragstrings_count++] = shaderpermutationinfo[i][0];
1011 strlcat(permutationname, shaderpermutationinfo[i][1], sizeof(permutationname));
1015 // keep line numbers correct
1016 vertstrings_list[vertstrings_count++] = "\n";
1017 geomstrings_list[geomstrings_count++] = "\n";
1018 fragstrings_list[fragstrings_count++] = "\n";
1021 shaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL);
1022 shaderfound = false;
1025 Con_DPrint("from disk... ");
1026 vertstrings_list[vertstrings_count++] = shaderstring;
1027 geomstrings_list[geomstrings_count++] = shaderstring;
1028 fragstrings_list[fragstrings_count++] = shaderstring;
1031 else if (!strcmp(filename, "glsl/default.glsl"))
1033 vertstrings_list[vertstrings_count++] = builtinshaderstring;
1034 geomstrings_list[geomstrings_count++] = builtinshaderstring;
1035 fragstrings_list[fragstrings_count++] = builtinshaderstring;
1038 // clear any lists that are not needed by this shader
1039 if (!(shadertype & SHADERTYPE_USES_VERTEXSHADER))
1040 vertstrings_count = 0;
1041 if (!(shadertype & SHADERTYPE_USES_GEOMETRYSHADER))
1042 geomstrings_count = 0;
1043 if (!(shadertype & SHADERTYPE_USES_FRAGMENTSHADER))
1044 fragstrings_count = 0;
1045 // compile the shader program
1046 if (shaderfound && vertstrings_count + geomstrings_count + fragstrings_count)
1047 p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
1051 qglUseProgramObjectARB(p->program);CHECKGLERROR
1052 // look up all the uniform variable names we care about, so we don't
1053 // have to look them up every time we set them
1054 p->loc_Texture_Normal = qglGetUniformLocationARB(p->program, "Texture_Normal");
1055 p->loc_Texture_Color = qglGetUniformLocationARB(p->program, "Texture_Color");
1056 p->loc_Texture_Gloss = qglGetUniformLocationARB(p->program, "Texture_Gloss");
1057 p->loc_Texture_Cube = qglGetUniformLocationARB(p->program, "Texture_Cube");
1058 p->loc_Texture_Attenuation = qglGetUniformLocationARB(p->program, "Texture_Attenuation");
1059 p->loc_Texture_FogMask = qglGetUniformLocationARB(p->program, "Texture_FogMask");
1060 p->loc_Texture_Pants = qglGetUniformLocationARB(p->program, "Texture_Pants");
1061 p->loc_Texture_Shirt = qglGetUniformLocationARB(p->program, "Texture_Shirt");
1062 p->loc_Texture_Lightmap = qglGetUniformLocationARB(p->program, "Texture_Lightmap");
1063 p->loc_Texture_Deluxemap = qglGetUniformLocationARB(p->program, "Texture_Deluxemap");
1064 p->loc_Texture_Glow = qglGetUniformLocationARB(p->program, "Texture_Glow");
1065 p->loc_Texture_Refraction = qglGetUniformLocationARB(p->program, "Texture_Refraction");
1066 p->loc_Texture_Reflection = qglGetUniformLocationARB(p->program, "Texture_Reflection");
1067 p->loc_FogColor = qglGetUniformLocationARB(p->program, "FogColor");
1068 p->loc_LightPosition = qglGetUniformLocationARB(p->program, "LightPosition");
1069 p->loc_EyePosition = qglGetUniformLocationARB(p->program, "EyePosition");
1070 p->loc_LightColor = qglGetUniformLocationARB(p->program, "LightColor");
1071 p->loc_Color_Pants = qglGetUniformLocationARB(p->program, "Color_Pants");
1072 p->loc_Color_Shirt = qglGetUniformLocationARB(p->program, "Color_Shirt");
1073 p->loc_FogRangeRecip = qglGetUniformLocationARB(p->program, "FogRangeRecip");
1074 p->loc_AmbientScale = qglGetUniformLocationARB(p->program, "AmbientScale");
1075 p->loc_DiffuseScale = qglGetUniformLocationARB(p->program, "DiffuseScale");
1076 p->loc_SpecularPower = qglGetUniformLocationARB(p->program, "SpecularPower");
1077 p->loc_SpecularScale = qglGetUniformLocationARB(p->program, "SpecularScale");
1078 p->loc_GlowScale = qglGetUniformLocationARB(p->program, "GlowScale");
1079 p->loc_SceneBrightness = qglGetUniformLocationARB(p->program, "SceneBrightness");
1080 p->loc_OffsetMapping_Scale = qglGetUniformLocationARB(p->program, "OffsetMapping_Scale");
1081 p->loc_AmbientColor = qglGetUniformLocationARB(p->program, "AmbientColor");
1082 p->loc_DiffuseColor = qglGetUniformLocationARB(p->program, "DiffuseColor");
1083 p->loc_SpecularColor = qglGetUniformLocationARB(p->program, "SpecularColor");
1084 p->loc_LightDir = qglGetUniformLocationARB(p->program, "LightDir");
1085 p->loc_ContrastBoostCoeff = qglGetUniformLocationARB(p->program, "ContrastBoostCoeff");
1086 p->loc_DistortScaleRefractReflect = qglGetUniformLocationARB(p->program, "DistortScaleRefractReflect");
1087 p->loc_ScreenScaleRefractReflect = qglGetUniformLocationARB(p->program, "ScreenScaleRefractReflect");
1088 p->loc_ScreenCenterRefractReflect = qglGetUniformLocationARB(p->program, "ScreenCenterRefractReflect");
1089 p->loc_RefractColor = qglGetUniformLocationARB(p->program, "RefractColor");
1090 p->loc_ReflectColor = qglGetUniformLocationARB(p->program, "ReflectColor");
1091 p->loc_ReflectFactor = qglGetUniformLocationARB(p->program, "ReflectFactor");
1092 p->loc_ReflectOffset = qglGetUniformLocationARB(p->program, "ReflectOffset");
1093 // initialize the samplers to refer to the texture units we use
1094 if (p->loc_Texture_Normal >= 0) qglUniform1iARB(p->loc_Texture_Normal, 0);
1095 if (p->loc_Texture_Color >= 0) qglUniform1iARB(p->loc_Texture_Color, 1);
1096 if (p->loc_Texture_Gloss >= 0) qglUniform1iARB(p->loc_Texture_Gloss, 2);
1097 if (p->loc_Texture_Cube >= 0) qglUniform1iARB(p->loc_Texture_Cube, 3);
1098 if (p->loc_Texture_FogMask >= 0) qglUniform1iARB(p->loc_Texture_FogMask, 4);
1099 if (p->loc_Texture_Pants >= 0) qglUniform1iARB(p->loc_Texture_Pants, 5);
1100 if (p->loc_Texture_Shirt >= 0) qglUniform1iARB(p->loc_Texture_Shirt, 6);
1101 if (p->loc_Texture_Lightmap >= 0) qglUniform1iARB(p->loc_Texture_Lightmap, 7);
1102 if (p->loc_Texture_Deluxemap >= 0) qglUniform1iARB(p->loc_Texture_Deluxemap, 8);
1103 if (p->loc_Texture_Glow >= 0) qglUniform1iARB(p->loc_Texture_Glow, 9);
1104 if (p->loc_Texture_Attenuation >= 0) qglUniform1iARB(p->loc_Texture_Attenuation, 10);
1105 if (p->loc_Texture_Refraction >= 0) qglUniform1iARB(p->loc_Texture_Refraction, 11);
1106 if (p->loc_Texture_Reflection >= 0) qglUniform1iARB(p->loc_Texture_Reflection, 12);
1108 qglUseProgramObjectARB(0);CHECKGLERROR
1109 if (developer.integer)
1110 Con_Printf("GLSL shader %s :%s compiled.\n", filename, permutationname);
1114 if (developer.integer)
1115 Con_Printf("GLSL shader %s :%s failed! source code line offset for above errors is %i.\n", permutationname, filename, -(vertstrings_count - 1));
1117 Con_Printf("GLSL shader %s :%s failed! some features may not work properly.\n", permutationname, filename);
1120 Mem_Free(shaderstring);
1123 void R_GLSL_Restart_f(void)
1126 for (i = 0;i < SHADERPERMUTATION_INDICES;i++)
1127 if (r_glsl_permutations[i].program)
1128 GL_Backend_FreeProgram(r_glsl_permutations[i].program);
1129 memset(r_glsl_permutations, 0, sizeof(r_glsl_permutations));
1132 void R_GLSL_DumpShader_f(void)
1136 qfile_t *file = FS_Open("glsl/default.glsl", "w", false, false);
1139 Con_Printf("failed to write to glsl/default.glsl\n");
1143 FS_Print(file, "// The engine may define the following macros:\n");
1144 FS_Print(file, "// #define VERTEX_SHADER\n// #define GEOMETRY_SHADER\n// #define FRAGMENT_SHADER\n");
1145 for (i = 0;shadermodeinfo[i][0];i++)
1146 FS_Printf(file, "// %s", shadermodeinfo[i][0]);
1147 for (i = 0;shaderpermutationinfo[i][0];i++)
1148 FS_Printf(file, "// %s", shaderpermutationinfo[i][0]);
1149 FS_Print(file, "\n");
1150 FS_Print(file, builtinshaderstring);
1153 Con_Printf("glsl/default.glsl written\n");
1156 extern rtexture_t *r_shadow_attenuationgradienttexture;
1157 extern rtexture_t *r_shadow_attenuation2dtexture;
1158 extern rtexture_t *r_shadow_attenuation3dtexture;
1159 int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, float ambientscale, float diffusescale, float specularscale, rsurfacepass_t rsurfacepass)
1161 // select a permutation of the lighting shader appropriate to this
1162 // combination of texture, entity, light source, and fogging, only use the
1163 // minimum features necessary to avoid wasting rendering time in the
1164 // fragment shader on features that are not being used
1165 const char *shaderfilename = NULL;
1166 unsigned int permutation = 0;
1167 unsigned int shadertype = 0;
1168 shadermode_t mode = 0;
1169 r_glsl_permutation = NULL;
1170 shaderfilename = "glsl/default.glsl";
1171 shadertype = SHADERTYPE_USES_VERTEXSHADER | SHADERTYPE_USES_FRAGMENTSHADER;
1172 // TODO: implement geometry-shader based shadow volumes someday
1173 if (r_glsl_offsetmapping.integer)
1175 permutation |= SHADERPERMUTATION_OFFSETMAPPING;
1176 if (r_glsl_offsetmapping_reliefmapping.integer)
1177 permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
1179 if (rsurfacepass == RSURFPASS_BACKGROUND)
1181 // distorted background
1182 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1183 mode = SHADERMODE_WATER;
1185 mode = SHADERMODE_REFRACTION;
1187 else if (rsurfacepass == RSURFPASS_RTLIGHT)
1190 mode = SHADERMODE_LIGHTSOURCE;
1191 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1192 permutation |= SHADERPERMUTATION_CUBEFILTER;
1193 if (diffusescale > 0)
1194 permutation |= SHADERPERMUTATION_DIFFUSE;
1195 if (specularscale > 0)
1196 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1197 if (r_refdef.fogenabled)
1198 permutation |= SHADERPERMUTATION_FOG;
1199 if (rsurface.texture->colormapping)
1200 permutation |= SHADERPERMUTATION_COLORMAPPING;
1201 if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
1202 permutation |= SHADERPERMUTATION_CONTRASTBOOST;
1203 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
1204 permutation |= SHADERPERMUTATION_REFLECTION;
1206 else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
1208 // bright unshaded geometry
1209 mode = SHADERMODE_LIGHTMAP;
1210 if (rsurface.texture->currentskinframe->glow)
1211 permutation |= SHADERPERMUTATION_GLOW;
1212 if (r_refdef.fogenabled)
1213 permutation |= SHADERPERMUTATION_FOG;
1214 if (rsurface.texture->colormapping)
1215 permutation |= SHADERPERMUTATION_COLORMAPPING;
1216 if (r_glsl_offsetmapping.integer)
1218 permutation |= SHADERPERMUTATION_OFFSETMAPPING;
1219 if (r_glsl_offsetmapping_reliefmapping.integer)
1220 permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
1222 if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
1223 permutation |= SHADERPERMUTATION_CONTRASTBOOST;
1224 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
1225 permutation |= SHADERPERMUTATION_REFLECTION;
1227 else if (modellighting)
1229 // directional model lighting
1230 mode = SHADERMODE_LIGHTDIRECTION;
1231 if (rsurface.texture->currentskinframe->glow)
1232 permutation |= SHADERPERMUTATION_GLOW;
1233 if (specularscale > 0)
1234 permutation |= SHADERPERMUTATION_SPECULAR;
1235 if (r_refdef.fogenabled)
1236 permutation |= SHADERPERMUTATION_FOG;
1237 if (rsurface.texture->colormapping)
1238 permutation |= SHADERPERMUTATION_COLORMAPPING;
1239 if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
1240 permutation |= SHADERPERMUTATION_CONTRASTBOOST;
1241 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
1242 permutation |= SHADERPERMUTATION_REFLECTION;
1247 if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping)
1249 // deluxemapping (light direction texture)
1250 if (rsurface.uselightmaptexture && r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping && r_refdef.worldmodel->brushq3.deluxemapping_modelspace)
1251 mode = SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE;
1253 mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1254 if (specularscale > 0)
1255 permutation |= SHADERPERMUTATION_SPECULAR;
1257 else if (r_glsl_deluxemapping.integer >= 2)
1259 // fake deluxemapping (uniform light direction in tangentspace)
1260 mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1261 if (specularscale > 0)
1262 permutation |= SHADERPERMUTATION_SPECULAR;
1266 // ordinary lightmapping
1267 mode = SHADERMODE_LIGHTMAP;
1269 if (rsurface.texture->currentskinframe->glow)
1270 permutation |= SHADERPERMUTATION_GLOW;
1271 if (r_refdef.fogenabled)
1272 permutation |= SHADERPERMUTATION_FOG;
1273 if (rsurface.texture->colormapping)
1274 permutation |= SHADERPERMUTATION_COLORMAPPING;
1275 if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
1276 permutation |= SHADERPERMUTATION_CONTRASTBOOST;
1277 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
1278 permutation |= SHADERPERMUTATION_REFLECTION;
1280 permutation |= mode * SHADERPERMUTATION_MODEBASE;
1281 if (!r_glsl_permutations[permutation].program)
1283 if (!r_glsl_permutations[permutation].compiled)
1284 R_GLSL_CompilePermutation(shaderfilename, permutation, shadertype);
1285 if (!r_glsl_permutations[permutation].program)
1287 // remove features until we find a valid permutation
1289 for (i = (SHADERPERMUTATION_MODEBASE >> 1);;i>>=1)
1293 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");
1294 Cvar_SetValueQuick(&r_glsl, 0);
1295 return 0; // no bit left to clear
1297 // reduce i more quickly whenever it would not remove any bits
1298 if (!(permutation & i))
1301 if (!r_glsl_permutations[permutation].compiled)
1302 R_GLSL_CompilePermutation(shaderfilename, permutation, shadertype);
1303 if (r_glsl_permutations[permutation].program)
1308 r_glsl_permutation = r_glsl_permutations + permutation;
1310 qglUseProgramObjectARB(r_glsl_permutation->program);CHECKGLERROR
1311 if (mode == SHADERMODE_LIGHTSOURCE)
1313 if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
1314 if (permutation & SHADERPERMUTATION_DIFFUSE)
1316 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightColor, lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);
1317 if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, ambientscale);
1318 if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, diffusescale);
1319 if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, specularscale);
1323 // ambient only is simpler
1324 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightColor, lightcolorbase[0] * ambientscale, lightcolorbase[1] * ambientscale, lightcolorbase[2] * ambientscale);
1325 if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, 1);
1326 if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, 0);
1327 if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, 0);
1330 else if (mode == SHADERMODE_LIGHTDIRECTION)
1332 if (r_glsl_permutation->loc_AmbientColor >= 0)
1333 qglUniform3fARB(r_glsl_permutation->loc_AmbientColor, rsurface.modellight_ambient[0] * ambientscale, rsurface.modellight_ambient[1] * ambientscale, rsurface.modellight_ambient[2] * ambientscale);
1334 if (r_glsl_permutation->loc_DiffuseColor >= 0)
1335 qglUniform3fARB(r_glsl_permutation->loc_DiffuseColor, rsurface.modellight_diffuse[0] * diffusescale, rsurface.modellight_diffuse[1] * diffusescale, rsurface.modellight_diffuse[2] * diffusescale);
1336 if (r_glsl_permutation->loc_SpecularColor >= 0)
1337 qglUniform3fARB(r_glsl_permutation->loc_SpecularColor, rsurface.modellight_diffuse[0] * specularscale, rsurface.modellight_diffuse[1] * specularscale, rsurface.modellight_diffuse[2] * specularscale);
1338 if (r_glsl_permutation->loc_LightDir >= 0)
1339 qglUniform3fARB(r_glsl_permutation->loc_LightDir, rsurface.modellight_lightdir[0], rsurface.modellight_lightdir[1], rsurface.modellight_lightdir[2]);
1343 if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, r_ambient.value * 2.0f / 128.0f);
1344 if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, r_refdef.lightmapintensity * 2.0f);
1345 if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, r_refdef.lightmapintensity * specularscale * 2.0f);
1347 if (r_glsl_permutation->loc_GlowScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_GlowScale, r_hdr_glowintensity.value);
1348 if (r_glsl_permutation->loc_ContrastBoostCoeff >= 0)
1350 // The formula used is actually:
1351 // color.rgb *= SceneBrightness;
1352 // color.rgb *= ContrastBoost / ((ContrastBoost - 1) * color.rgb + 1);
1353 // I simplify that to
1354 // color.rgb *= [[SceneBrightness * ContrastBoost]];
1355 // color.rgb /= [[(ContrastBoost - 1) / ContrastBoost]] * color.rgb + 1;
1357 // color.rgb = [[SceneBrightness * ContrastBoost]] * color.rgb / ([[(ContrastBoost - 1) * SceneBrightness]] * color.rgb + 1);
1358 // and do [[calculations]] here in the engine
1359 qglUniform1fARB(r_glsl_permutation->loc_ContrastBoostCoeff, (r_glsl_contrastboost.value - 1) * r_view.colorscale);
1360 if (r_glsl_permutation->loc_SceneBrightness >= 0) qglUniform1fARB(r_glsl_permutation->loc_SceneBrightness, r_view.colorscale * r_glsl_contrastboost.value);
1363 if (r_glsl_permutation->loc_SceneBrightness >= 0) qglUniform1fARB(r_glsl_permutation->loc_SceneBrightness, r_view.colorscale);
1364 if (r_glsl_permutation->loc_FogColor >= 0)
1366 // additive passes are only darkened by fog, not tinted
1367 if (rsurface.rtlight || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ADD))
1368 qglUniform3fARB(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1373 // color.rgb *= SceneBrightness;
1374 VectorScale(r_refdef.fogcolor, r_view.colorscale, fogvec);
1375 if(r_glsl_permutation->loc_ContrastBoostCoeff >= 0) // need to support contrast boost
1377 // color.rgb *= ContrastBoost / ((ContrastBoost - 1) * color.rgb + 1);
1378 fogvec[0] *= r_glsl_contrastboost.value / ((r_glsl_contrastboost.value - 1) * fogvec[0] + 1);
1379 fogvec[1] *= r_glsl_contrastboost.value / ((r_glsl_contrastboost.value - 1) * fogvec[1] + 1);
1380 fogvec[2] *= r_glsl_contrastboost.value / ((r_glsl_contrastboost.value - 1) * fogvec[2] + 1);
1382 qglUniform3fARB(r_glsl_permutation->loc_FogColor, fogvec[0], fogvec[1], fogvec[2]);
1385 qglUniform3fARB(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1387 if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_EyePosition, rsurface.modelorg[0], rsurface.modelorg[1], rsurface.modelorg[2]);
1388 if (r_glsl_permutation->loc_Color_Pants >= 0)
1390 if (rsurface.texture->currentskinframe->pants)
1391 qglUniform3fARB(r_glsl_permutation->loc_Color_Pants, rsurface.colormap_pantscolor[0], rsurface.colormap_pantscolor[1], rsurface.colormap_pantscolor[2]);
1393 qglUniform3fARB(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
1395 if (r_glsl_permutation->loc_Color_Shirt >= 0)
1397 if (rsurface.texture->currentskinframe->shirt)
1398 qglUniform3fARB(r_glsl_permutation->loc_Color_Shirt, rsurface.colormap_shirtcolor[0], rsurface.colormap_shirtcolor[1], rsurface.colormap_shirtcolor[2]);
1400 qglUniform3fARB(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
1402 if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1fARB(r_glsl_permutation->loc_FogRangeRecip, r_refdef.fograngerecip);
1403 if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularPower, rsurface.texture->specularpower);
1404 if (r_glsl_permutation->loc_OffsetMapping_Scale >= 0) qglUniform1fARB(r_glsl_permutation->loc_OffsetMapping_Scale, r_glsl_offsetmapping_scale.value);
1405 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);
1406 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]);
1407 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]);
1408 if (r_glsl_permutation->loc_RefractColor >= 0) qglUniform4fvARB(r_glsl_permutation->loc_RefractColor, 1, rsurface.texture->refractcolor4f);
1409 if (r_glsl_permutation->loc_ReflectColor >= 0) qglUniform4fvARB(r_glsl_permutation->loc_ReflectColor, 1, rsurface.texture->reflectcolor4f);
1410 if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1fARB(r_glsl_permutation->loc_ReflectFactor, rsurface.texture->reflectmax - rsurface.texture->reflectmin);
1411 if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1fARB(r_glsl_permutation->loc_ReflectOffset, rsurface.texture->reflectmin);
1416 #define SKINFRAME_HASH 1024
1420 int loadsequence; // incremented each level change
1421 memexpandablearray_t array;
1422 skinframe_t *hash[SKINFRAME_HASH];
1426 void R_SkinFrame_PrepareForPurge(void)
1428 r_skinframe.loadsequence++;
1429 // wrap it without hitting zero
1430 if (r_skinframe.loadsequence >= 200)
1431 r_skinframe.loadsequence = 1;
1434 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
1438 // mark the skinframe as used for the purging code
1439 skinframe->loadsequence = r_skinframe.loadsequence;
1442 void R_SkinFrame_Purge(void)
1446 for (i = 0;i < SKINFRAME_HASH;i++)
1448 for (s = r_skinframe.hash[i];s;s = s->next)
1450 if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
1452 if (s->base == r_texture_notexture) s->base = NULL;
1453 if (s->nmap == r_texture_blanknormalmap)s->nmap = NULL;
1454 if (s->merged == s->base) s->merged = NULL;
1455 if (s->stain ) R_FreeTexture(s->stain );s->stain = NULL;
1456 if (s->merged) R_FreeTexture(s->merged);s->merged = NULL;
1457 if (s->base ) R_FreeTexture(s->base );s->base = NULL;
1458 if (s->pants ) R_FreeTexture(s->pants );s->pants = NULL;
1459 if (s->shirt ) R_FreeTexture(s->shirt );s->shirt = NULL;
1460 if (s->nmap ) R_FreeTexture(s->nmap );s->nmap = NULL;
1461 if (s->gloss ) R_FreeTexture(s->gloss );s->gloss = NULL;
1462 if (s->glow ) R_FreeTexture(s->glow );s->glow = NULL;
1463 if (s->fog ) R_FreeTexture(s->fog );s->fog = NULL;
1464 s->loadsequence = 0;
1470 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qboolean add)
1474 char basename[MAX_QPATH];
1476 Image_StripImageExtension(name, basename, sizeof(basename));
1478 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
1479 for (item = r_skinframe.hash[hashindex];item;item = item->next)
1480 if (!strcmp(item->basename, basename) && item->textureflags == textureflags && item->comparewidth == comparewidth && item->compareheight == compareheight && item->comparecrc == comparecrc)
1486 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
1487 memset(item, 0, sizeof(*item));
1488 strlcpy(item->basename, basename, sizeof(item->basename));
1489 item->textureflags = textureflags;
1490 item->comparewidth = comparewidth;
1491 item->compareheight = compareheight;
1492 item->comparecrc = comparecrc;
1493 item->next = r_skinframe.hash[hashindex];
1494 r_skinframe.hash[hashindex] = item;
1496 R_SkinFrame_MarkUsed(item);
1500 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain)
1502 // FIXME: it should be possible to disable loading various layers using
1503 // cvars, to prevent wasted loading time and memory usage if the user does
1505 qboolean loadnormalmap = true;
1506 qboolean loadgloss = true;
1507 qboolean loadpantsandshirt = true;
1508 qboolean loadglow = true;
1510 unsigned char *pixels;
1511 unsigned char *bumppixels;
1512 unsigned char *basepixels = NULL;
1513 int basepixels_width;
1514 int basepixels_height;
1515 skinframe_t *skinframe;
1517 if (cls.state == ca_dedicated)
1520 // return an existing skinframe if already loaded
1521 // if loading of the first image fails, don't make a new skinframe as it
1522 // would cause all future lookups of this to be missing
1523 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
1524 if (skinframe && skinframe->base)
1527 basepixels = loadimagepixels(name, complain, 0, 0);
1528 if (basepixels == NULL)
1531 // we've got some pixels to store, so really allocate this new texture now
1533 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
1534 skinframe->stain = NULL;
1535 skinframe->merged = NULL;
1536 skinframe->base = r_texture_notexture;
1537 skinframe->pants = NULL;
1538 skinframe->shirt = NULL;
1539 skinframe->nmap = r_texture_blanknormalmap;
1540 skinframe->gloss = NULL;
1541 skinframe->glow = NULL;
1542 skinframe->fog = NULL;
1544 basepixels_width = image_width;
1545 basepixels_height = image_height;
1546 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);
1548 if (textureflags & TEXF_ALPHA)
1550 for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
1551 if (basepixels[j] < 255)
1553 if (j < basepixels_width * basepixels_height * 4)
1555 // has transparent pixels
1556 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
1557 for (j = 0;j < image_width * image_height * 4;j += 4)
1562 pixels[j+3] = basepixels[j+3];
1564 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);
1569 // _norm is the name used by tenebrae and has been adopted as standard
1572 if ((pixels = loadimagepixels(va("%s_norm", skinframe->basename), false, 0, 0)) != NULL)
1574 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);
1578 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixels(va("%s_bump", skinframe->basename), false, 0, 0)) != NULL)
1580 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
1581 Image_HeightmapToNormalmap(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
1582 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);
1584 Mem_Free(bumppixels);
1586 else if (r_shadow_bumpscale_basetexture.value > 0)
1588 pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
1589 Image_HeightmapToNormalmap(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
1590 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);
1594 // _luma is supported for tenebrae compatibility
1595 // (I think it's a very stupid name, but oh well)
1596 // _glow is the preferred name
1597 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;}
1598 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;}
1599 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;}
1600 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;}
1603 Mem_Free(basepixels);
1608 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)
1613 for (i = 0;i < width*height;i++)
1614 if (((unsigned char *)&palette[in[i]])[3] > 0)
1616 if (i == width*height)
1619 return R_LoadTexture2D (r_main_texturepool, name, width, height, in, TEXTYPE_PALETTE, textureflags, palette);
1622 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)
1625 unsigned char *temp1, *temp2;
1626 skinframe_t *skinframe;
1628 if (cls.state == ca_dedicated)
1631 // if already loaded just return it, otherwise make a new skinframe
1632 skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height*bitsperpixel/8) : 0, true);
1633 if (skinframe && skinframe->base)
1636 skinframe->stain = NULL;
1637 skinframe->merged = NULL;
1638 skinframe->base = r_texture_notexture;
1639 skinframe->pants = NULL;
1640 skinframe->shirt = NULL;
1641 skinframe->nmap = r_texture_blanknormalmap;
1642 skinframe->gloss = NULL;
1643 skinframe->glow = NULL;
1644 skinframe->fog = NULL;
1646 // if no data was provided, then clearly the caller wanted to get a blank skinframe
1650 if (bitsperpixel == 32)
1652 if (r_shadow_bumpscale_basetexture.value > 0)
1654 temp1 = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
1655 temp2 = temp1 + width * height * 4;
1656 Image_HeightmapToNormalmap(skindata, temp2, width, height, false, r_shadow_bumpscale_basetexture.value);
1657 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va("%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_RGBA, skinframe->textureflags | TEXF_ALPHA, NULL);
1660 skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_RGBA, skinframe->textureflags, NULL);
1661 if (textureflags & TEXF_ALPHA)
1663 for (i = 3;i < width * height * 4;i += 4)
1664 if (skindata[i] < 255)
1666 if (i < width * height * 4)
1668 unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
1669 memcpy(fogpixels, skindata, width * height * 4);
1670 for (i = 0;i < width * height * 4;i += 4)
1671 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
1672 skinframe->fog = R_LoadTexture2D(r_main_texturepool, va("%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_RGBA, skinframe->textureflags, NULL);
1673 Mem_Free(fogpixels);
1677 else if (bitsperpixel == 8)
1679 if (r_shadow_bumpscale_basetexture.value > 0)
1681 temp1 = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
1682 temp2 = temp1 + width * height * 4;
1683 if (bitsperpixel == 32)
1684 Image_HeightmapToNormalmap(skindata, temp2, width, height, false, r_shadow_bumpscale_basetexture.value);
1687 // use either a custom palette or the quake palette
1688 Image_Copy8bitRGBA(skindata, temp1, width * height, palette ? palette : palette_complete);
1689 Image_HeightmapToNormalmap(temp1, temp2, width, height, false, r_shadow_bumpscale_basetexture.value);
1691 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va("%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_RGBA, skinframe->textureflags | TEXF_ALPHA, NULL);
1694 // use either a custom palette, or the quake palette
1695 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
1696 if (!palette && loadglowtexture)
1697 skinframe->glow = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_glow", skinframe->basename), palette_onlyfullbrights, skinframe->textureflags, false); // glow
1698 if (!palette && loadpantsandshirt)
1700 skinframe->pants = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_pants", skinframe->basename), palette_pantsaswhite, skinframe->textureflags, false); // pants
1701 skinframe->shirt = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_shirt", skinframe->basename), palette_shirtaswhite, skinframe->textureflags, false); // shirt
1703 if (skinframe->pants || skinframe->shirt)
1704 skinframe->base = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_nospecial", skinframe->basename),loadglowtexture ? palette_nocolormapnofullbrights : palette_nocolormap, skinframe->textureflags, false); // no special colors
1705 if (textureflags & TEXF_ALPHA)
1707 // if not using a custom alphapalette, use the quake one
1709 alphapalette = palette_alpha;
1710 for (i = 0;i < width * height;i++)
1711 if (((unsigned char *)alphapalette)[skindata[i]*4+3] < 255)
1713 if (i < width * height)
1714 skinframe->fog = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_fog", skinframe->basename), alphapalette, skinframe->textureflags, true); // fog mask
1721 skinframe_t *R_SkinFrame_LoadMissing(void)
1723 skinframe_t *skinframe;
1725 if (cls.state == ca_dedicated)
1728 skinframe = R_SkinFrame_Find("missing", TEXF_PRECACHE, 0, 0, 0, true);
1729 skinframe->stain = NULL;
1730 skinframe->merged = NULL;
1731 skinframe->base = r_texture_notexture;
1732 skinframe->pants = NULL;
1733 skinframe->shirt = NULL;
1734 skinframe->nmap = r_texture_blanknormalmap;
1735 skinframe->gloss = NULL;
1736 skinframe->glow = NULL;
1737 skinframe->fog = NULL;
1742 void gl_main_start(void)
1747 r = (-1.0/256.0) * (FOGMASKTABLEWIDTH * FOGMASKTABLEWIDTH);
1748 for (x = 0;x < FOGMASKTABLEWIDTH;x++)
1750 alpha = 1 - exp(r / ((double)x*(double)x));
1751 if (x == FOGMASKTABLEWIDTH - 1)
1753 r_refdef.fogmasktable[x] = bound(0, alpha, 1);
1756 memset(r_qwskincache, 0, sizeof(r_qwskincache));
1757 memset(r_qwskincache_skinframe, 0, sizeof(r_qwskincache_skinframe));
1759 // set up r_skinframe loading system for textures
1760 memset(&r_skinframe, 0, sizeof(r_skinframe));
1761 r_skinframe.loadsequence = 1;
1762 Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
1764 r_main_texturepool = R_AllocTexturePool();
1765 R_BuildBlankTextures();
1767 if (gl_texturecubemap)
1770 R_BuildNormalizationCube();
1772 R_BuildFogTexture();
1773 memset(&r_bloomstate, 0, sizeof(r_bloomstate));
1774 memset(&r_waterstate, 0, sizeof(r_waterstate));
1775 memset(r_glsl_permutations, 0, sizeof(r_glsl_permutations));
1776 memset(&r_svbsp, 0, sizeof (r_svbsp));
1779 void gl_main_shutdown(void)
1781 memset(r_qwskincache, 0, sizeof(r_qwskincache));
1782 memset(r_qwskincache_skinframe, 0, sizeof(r_qwskincache_skinframe));
1784 // clear out the r_skinframe state
1785 Mem_ExpandableArray_FreeArray(&r_skinframe.array);
1786 memset(&r_skinframe, 0, sizeof(r_skinframe));
1789 Mem_Free(r_svbsp.nodes);
1790 memset(&r_svbsp, 0, sizeof (r_svbsp));
1791 R_FreeTexturePool(&r_main_texturepool);
1792 r_texture_blanknormalmap = NULL;
1793 r_texture_white = NULL;
1794 r_texture_grey128 = NULL;
1795 r_texture_black = NULL;
1796 r_texture_whitecube = NULL;
1797 r_texture_normalizationcube = NULL;
1798 memset(&r_bloomstate, 0, sizeof(r_bloomstate));
1799 memset(&r_waterstate, 0, sizeof(r_waterstate));
1803 extern void CL_ParseEntityLump(char *entitystring);
1804 void gl_main_newmap(void)
1806 // FIXME: move this code to client
1808 char *entities, entname[MAX_QPATH];
1811 strlcpy(entname, cl.worldmodel->name, sizeof(entname));
1812 l = (int)strlen(entname) - 4;
1813 if (l >= 0 && !strcmp(entname + l, ".bsp"))
1815 memcpy(entname + l, ".ent", 5);
1816 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
1818 CL_ParseEntityLump(entities);
1823 if (cl.worldmodel->brush.entities)
1824 CL_ParseEntityLump(cl.worldmodel->brush.entities);
1828 void GL_Main_Init(void)
1830 r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
1832 Cmd_AddCommand("r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
1833 Cmd_AddCommand("r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
1834 // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
1835 if (gamemode == GAME_NEHAHRA)
1837 Cvar_RegisterVariable (&gl_fogenable);
1838 Cvar_RegisterVariable (&gl_fogdensity);
1839 Cvar_RegisterVariable (&gl_fogred);
1840 Cvar_RegisterVariable (&gl_foggreen);
1841 Cvar_RegisterVariable (&gl_fogblue);
1842 Cvar_RegisterVariable (&gl_fogstart);
1843 Cvar_RegisterVariable (&gl_fogend);
1845 Cvar_RegisterVariable(&r_depthfirst);
1846 Cvar_RegisterVariable(&r_nearclip);
1847 Cvar_RegisterVariable(&r_showbboxes);
1848 Cvar_RegisterVariable(&r_showsurfaces);
1849 Cvar_RegisterVariable(&r_showtris);
1850 Cvar_RegisterVariable(&r_shownormals);
1851 Cvar_RegisterVariable(&r_showlighting);
1852 Cvar_RegisterVariable(&r_showshadowvolumes);
1853 Cvar_RegisterVariable(&r_showcollisionbrushes);
1854 Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
1855 Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
1856 Cvar_RegisterVariable(&r_showdisabledepthtest);
1857 Cvar_RegisterVariable(&r_drawportals);
1858 Cvar_RegisterVariable(&r_drawentities);
1859 Cvar_RegisterVariable(&r_cullentities_trace);
1860 Cvar_RegisterVariable(&r_cullentities_trace_samples);
1861 Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
1862 Cvar_RegisterVariable(&r_cullentities_trace_delay);
1863 Cvar_RegisterVariable(&r_drawviewmodel);
1864 Cvar_RegisterVariable(&r_speeds);
1865 Cvar_RegisterVariable(&r_fullbrights);
1866 Cvar_RegisterVariable(&r_wateralpha);
1867 Cvar_RegisterVariable(&r_dynamic);
1868 Cvar_RegisterVariable(&r_fullbright);
1869 Cvar_RegisterVariable(&r_shadows);
1870 Cvar_RegisterVariable(&r_shadows_throwdistance);
1871 Cvar_RegisterVariable(&r_q1bsp_skymasking);
1872 Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
1873 Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
1874 Cvar_RegisterVariable(&r_textureunits);
1875 Cvar_RegisterVariable(&r_glsl);
1876 Cvar_RegisterVariable(&r_glsl_offsetmapping);
1877 Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
1878 Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
1879 Cvar_RegisterVariable(&r_glsl_deluxemapping);
1880 Cvar_RegisterVariable(&r_water);
1881 Cvar_RegisterVariable(&r_water_resolutionmultiplier);
1882 Cvar_RegisterVariable(&r_water_clippingplanebias);
1883 Cvar_RegisterVariable(&r_water_refractdistort);
1884 Cvar_RegisterVariable(&r_water_reflectdistort);
1885 Cvar_RegisterVariable(&r_lerpsprites);
1886 Cvar_RegisterVariable(&r_lerpmodels);
1887 Cvar_RegisterVariable(&r_waterscroll);
1888 Cvar_RegisterVariable(&r_bloom);
1889 Cvar_RegisterVariable(&r_bloom_colorscale);
1890 Cvar_RegisterVariable(&r_bloom_brighten);
1891 Cvar_RegisterVariable(&r_bloom_blur);
1892 Cvar_RegisterVariable(&r_bloom_resolution);
1893 Cvar_RegisterVariable(&r_bloom_colorexponent);
1894 Cvar_RegisterVariable(&r_bloom_colorsubtract);
1895 Cvar_RegisterVariable(&r_hdr);
1896 Cvar_RegisterVariable(&r_hdr_scenebrightness);
1897 Cvar_RegisterVariable(&r_glsl_contrastboost);
1898 Cvar_RegisterVariable(&r_hdr_glowintensity);
1899 Cvar_RegisterVariable(&r_hdr_range);
1900 Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
1901 Cvar_RegisterVariable(&developer_texturelogging);
1902 Cvar_RegisterVariable(&gl_lightmaps);
1903 Cvar_RegisterVariable(&r_test);
1904 Cvar_RegisterVariable(&r_batchmode);
1905 if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
1906 Cvar_SetValue("r_fullbrights", 0);
1907 R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
1909 Cvar_RegisterVariable(&r_track_sprites);
1910 Cvar_RegisterVariable(&r_track_sprites_flags);
1911 Cvar_RegisterVariable(&r_track_sprites_scalew);
1912 Cvar_RegisterVariable(&r_track_sprites_scaleh);
1915 extern void R_Textures_Init(void);
1916 extern void GL_Draw_Init(void);
1917 extern void GL_Main_Init(void);
1918 extern void R_Shadow_Init(void);
1919 extern void R_Sky_Init(void);
1920 extern void GL_Surf_Init(void);
1921 extern void R_Light_Init(void);
1922 extern void R_Particles_Init(void);
1923 extern void R_Explosion_Init(void);
1924 extern void gl_backend_init(void);
1925 extern void Sbar_Init(void);
1926 extern void R_LightningBeams_Init(void);
1927 extern void Mod_RenderInit(void);
1929 void Render_Init(void)
1942 R_LightningBeams_Init();
1951 extern char *ENGINE_EXTENSIONS;
1954 VID_CheckExtensions();
1956 // LordHavoc: report supported extensions
1957 Con_DPrintf("\nQuakeC extensions for server and client: %s\nQuakeC extensions for menu: %s\n", vm_sv_extensions, vm_m_extensions );
1959 // clear to black (loading plaque will be seen over this)
1961 qglClearColor(0,0,0,1);CHECKGLERROR
1962 qglClear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
1965 int R_CullBox(const vec3_t mins, const vec3_t maxs)
1969 for (i = 0;i < r_view.numfrustumplanes;i++)
1971 // skip nearclip plane, it often culls portals when you are very close, and is almost never useful
1974 p = r_view.frustum + i;
1979 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
1983 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
1987 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
1991 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
1995 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
1999 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
2003 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
2007 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
2015 int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
2019 for (i = 0;i < numplanes;i++)
2026 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
2030 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
2034 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
2038 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
2042 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
2046 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
2050 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
2054 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
2062 //==================================================================================
2064 static void R_UpdateEntityLighting(entity_render_t *ent)
2066 vec3_t tempdiffusenormal;
2068 // fetch the lighting from the worldmodel data
2069 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));
2070 VectorClear(ent->modellight_diffuse);
2071 VectorClear(tempdiffusenormal);
2072 if ((ent->flags & RENDER_LIGHT) && r_refdef.worldmodel && r_refdef.worldmodel->brush.LightPoint)
2075 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2076 r_refdef.worldmodel->brush.LightPoint(r_refdef.worldmodel, org, ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal);
2079 VectorSet(ent->modellight_ambient, 1, 1, 1);
2081 // move the light direction into modelspace coordinates for lighting code
2082 Matrix4x4_Transform3x3(&ent->inversematrix, tempdiffusenormal, ent->modellight_lightdir);
2083 if(VectorLength2(ent->modellight_lightdir) > 0)
2085 VectorNormalize(ent->modellight_lightdir);
2089 VectorSet(ent->modellight_lightdir, 0, 0, 1); // have to set SOME valid vector here
2092 // scale ambient and directional light contributions according to rendering variables
2093 ent->modellight_ambient[0] *= ent->colormod[0] * r_refdef.lightmapintensity;
2094 ent->modellight_ambient[1] *= ent->colormod[1] * r_refdef.lightmapintensity;
2095 ent->modellight_ambient[2] *= ent->colormod[2] * r_refdef.lightmapintensity;
2096 ent->modellight_diffuse[0] *= ent->colormod[0] * r_refdef.lightmapintensity;
2097 ent->modellight_diffuse[1] *= ent->colormod[1] * r_refdef.lightmapintensity;
2098 ent->modellight_diffuse[2] *= ent->colormod[2] * r_refdef.lightmapintensity;
2101 static void R_View_UpdateEntityVisible (void)
2104 entity_render_t *ent;
2106 if (!r_drawentities.integer)
2109 renderimask = r_refdef.envmap ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL) : ((chase_active.integer || r_waterstate.renderingscene) ? RENDER_VIEWMODEL : RENDER_EXTERIORMODEL);
2110 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingVisibleLeafs)
2112 // worldmodel can check visibility
2113 for (i = 0;i < r_refdef.numentities;i++)
2115 ent = r_refdef.entities[i];
2116 r_viewcache.entityvisible[i] = !(ent->flags & renderimask) && ((ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)) || !R_CullBox(ent->mins, ent->maxs)) && ((ent->effects & EF_NODEPTHTEST) || (ent->flags & RENDER_VIEWMODEL) || r_refdef.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.worldmodel, r_viewcache.world_leafvisible, ent->mins, ent->maxs));
2119 if(r_cullentities_trace.integer)
2121 for (i = 0;i < r_refdef.numentities;i++)
2123 ent = r_refdef.entities[i];
2124 if(r_viewcache.entityvisible[i] && !(ent->effects & EF_NODEPTHTEST) && !(ent->flags & RENDER_VIEWMODEL) && !(ent->model && (ent->model->name[0] == '*')))
2126 if(Mod_CanSeeBox_Trace(r_cullentities_trace_samples.integer, r_cullentities_trace_enlarge.value, r_refdef.worldmodel, r_view.origin, ent->mins, ent->maxs))
2127 ent->last_trace_visibility = realtime;
2128 if(ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
2129 r_viewcache.entityvisible[i] = 0;
2136 // no worldmodel or it can't check visibility
2137 for (i = 0;i < r_refdef.numentities;i++)
2139 ent = r_refdef.entities[i];
2140 r_viewcache.entityvisible[i] = !(ent->flags & renderimask) && ((ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)) || !R_CullBox(ent->mins, ent->maxs));
2144 // update entity lighting (even on hidden entities for r_shadows)
2145 for (i = 0;i < r_refdef.numentities;i++)
2146 R_UpdateEntityLighting(r_refdef.entities[i]);
2149 // only used if skyrendermasked, and normally returns false
2150 int R_DrawBrushModelsSky (void)
2153 entity_render_t *ent;
2155 if (!r_drawentities.integer)
2159 for (i = 0;i < r_refdef.numentities;i++)
2161 if (!r_viewcache.entityvisible[i])
2163 ent = r_refdef.entities[i];
2164 if (!ent->model || !ent->model->DrawSky)
2166 ent->model->DrawSky(ent);
2172 static void R_DrawNoModel(entity_render_t *ent);
2173 static void R_DrawModels(void)
2176 entity_render_t *ent;
2178 if (!r_drawentities.integer)
2181 for (i = 0;i < r_refdef.numentities;i++)
2183 if (!r_viewcache.entityvisible[i])
2185 ent = r_refdef.entities[i];
2186 r_refdef.stats.entities++;
2187 if (ent->model && ent->model->Draw != NULL)
2188 ent->model->Draw(ent);
2194 static void R_DrawModelsDepth(void)
2197 entity_render_t *ent;
2199 if (!r_drawentities.integer)
2202 for (i = 0;i < r_refdef.numentities;i++)
2204 if (!r_viewcache.entityvisible[i])
2206 ent = r_refdef.entities[i];
2207 r_refdef.stats.entities++;
2208 if (ent->model && ent->model->DrawDepth != NULL)
2209 ent->model->DrawDepth(ent);
2213 static void R_DrawModelsDebug(void)
2216 entity_render_t *ent;
2218 if (!r_drawentities.integer)
2221 for (i = 0;i < r_refdef.numentities;i++)
2223 if (!r_viewcache.entityvisible[i])
2225 ent = r_refdef.entities[i];
2226 r_refdef.stats.entities++;
2227 if (ent->model && ent->model->DrawDebug != NULL)
2228 ent->model->DrawDebug(ent);
2232 static void R_DrawModelsAddWaterPlanes(void)
2235 entity_render_t *ent;
2237 if (!r_drawentities.integer)
2240 for (i = 0;i < r_refdef.numentities;i++)
2242 if (!r_viewcache.entityvisible[i])
2244 ent = r_refdef.entities[i];
2245 r_refdef.stats.entities++;
2246 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
2247 ent->model->DrawAddWaterPlanes(ent);
2251 static void R_View_SetFrustum(void)
2254 double slopex, slopey;
2256 // break apart the view matrix into vectors for various purposes
2257 Matrix4x4_ToVectors(&r_view.matrix, r_view.forward, r_view.left, r_view.up, r_view.origin);
2258 VectorNegate(r_view.left, r_view.right);
2261 r_view.frustum[0].normal[0] = 0 - 1.0 / r_view.frustum_x;
2262 r_view.frustum[0].normal[1] = 0 - 0;
2263 r_view.frustum[0].normal[2] = -1 - 0;
2264 r_view.frustum[1].normal[0] = 0 + 1.0 / r_view.frustum_x;
2265 r_view.frustum[1].normal[1] = 0 + 0;
2266 r_view.frustum[1].normal[2] = -1 + 0;
2267 r_view.frustum[2].normal[0] = 0 - 0;
2268 r_view.frustum[2].normal[1] = 0 - 1.0 / r_view.frustum_y;
2269 r_view.frustum[2].normal[2] = -1 - 0;
2270 r_view.frustum[3].normal[0] = 0 + 0;
2271 r_view.frustum[3].normal[1] = 0 + 1.0 / r_view.frustum_y;
2272 r_view.frustum[3].normal[2] = -1 + 0;
2276 zNear = r_refdef.nearclip;
2277 nudge = 1.0 - 1.0 / (1<<23);
2278 r_view.frustum[4].normal[0] = 0 - 0;
2279 r_view.frustum[4].normal[1] = 0 - 0;
2280 r_view.frustum[4].normal[2] = -1 - -nudge;
2281 r_view.frustum[4].dist = 0 - -2 * zNear * nudge;
2282 r_view.frustum[5].normal[0] = 0 + 0;
2283 r_view.frustum[5].normal[1] = 0 + 0;
2284 r_view.frustum[5].normal[2] = -1 + -nudge;
2285 r_view.frustum[5].dist = 0 + -2 * zNear * nudge;
2291 r_view.frustum[0].normal[0] = m[3] - m[0];
2292 r_view.frustum[0].normal[1] = m[7] - m[4];
2293 r_view.frustum[0].normal[2] = m[11] - m[8];
2294 r_view.frustum[0].dist = m[15] - m[12];
2296 r_view.frustum[1].normal[0] = m[3] + m[0];
2297 r_view.frustum[1].normal[1] = m[7] + m[4];
2298 r_view.frustum[1].normal[2] = m[11] + m[8];
2299 r_view.frustum[1].dist = m[15] + m[12];
2301 r_view.frustum[2].normal[0] = m[3] - m[1];
2302 r_view.frustum[2].normal[1] = m[7] - m[5];
2303 r_view.frustum[2].normal[2] = m[11] - m[9];
2304 r_view.frustum[2].dist = m[15] - m[13];
2306 r_view.frustum[3].normal[0] = m[3] + m[1];
2307 r_view.frustum[3].normal[1] = m[7] + m[5];
2308 r_view.frustum[3].normal[2] = m[11] + m[9];
2309 r_view.frustum[3].dist = m[15] + m[13];
2311 r_view.frustum[4].normal[0] = m[3] - m[2];
2312 r_view.frustum[4].normal[1] = m[7] - m[6];
2313 r_view.frustum[4].normal[2] = m[11] - m[10];
2314 r_view.frustum[4].dist = m[15] - m[14];
2316 r_view.frustum[5].normal[0] = m[3] + m[2];
2317 r_view.frustum[5].normal[1] = m[7] + m[6];
2318 r_view.frustum[5].normal[2] = m[11] + m[10];
2319 r_view.frustum[5].dist = m[15] + m[14];
2322 if (r_view.useperspective)
2324 slopex = 1.0 / r_view.frustum_x;
2325 slopey = 1.0 / r_view.frustum_y;
2326 VectorMA(r_view.forward, -slopex, r_view.left, r_view.frustum[0].normal);
2327 VectorMA(r_view.forward, slopex, r_view.left, r_view.frustum[1].normal);
2328 VectorMA(r_view.forward, -slopey, r_view.up , r_view.frustum[2].normal);
2329 VectorMA(r_view.forward, slopey, r_view.up , r_view.frustum[3].normal);
2330 VectorCopy(r_view.forward, r_view.frustum[4].normal);
2332 // Leaving those out was a mistake, those were in the old code, and they
2333 // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix
2334 // I couldn't reproduce it after adding those normalizations. --blub
2335 VectorNormalize(r_view.frustum[0].normal);
2336 VectorNormalize(r_view.frustum[1].normal);
2337 VectorNormalize(r_view.frustum[2].normal);
2338 VectorNormalize(r_view.frustum[3].normal);
2340 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
2341 VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, -1024 * slopex, r_view.left, -1024 * slopey, r_view.up, r_view.frustumcorner[0]);
2342 VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, 1024 * slopex, r_view.left, -1024 * slopey, r_view.up, r_view.frustumcorner[1]);
2343 VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, -1024 * slopex, r_view.left, 1024 * slopey, r_view.up, r_view.frustumcorner[2]);
2344 VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, 1024 * slopex, r_view.left, 1024 * slopey, r_view.up, r_view.frustumcorner[3]);
2346 r_view.frustum[0].dist = DotProduct (r_view.origin, r_view.frustum[0].normal);
2347 r_view.frustum[1].dist = DotProduct (r_view.origin, r_view.frustum[1].normal);
2348 r_view.frustum[2].dist = DotProduct (r_view.origin, r_view.frustum[2].normal);
2349 r_view.frustum[3].dist = DotProduct (r_view.origin, r_view.frustum[3].normal);
2350 r_view.frustum[4].dist = DotProduct (r_view.origin, r_view.frustum[4].normal) + r_refdef.nearclip;
2354 VectorScale(r_view.left, -r_view.ortho_x, r_view.frustum[0].normal);
2355 VectorScale(r_view.left, r_view.ortho_x, r_view.frustum[1].normal);
2356 VectorScale(r_view.up, -r_view.ortho_y, r_view.frustum[2].normal);
2357 VectorScale(r_view.up, r_view.ortho_y, r_view.frustum[3].normal);
2358 VectorCopy(r_view.forward, r_view.frustum[4].normal);
2359 r_view.frustum[0].dist = DotProduct (r_view.origin, r_view.frustum[0].normal) + r_view.ortho_x;
2360 r_view.frustum[1].dist = DotProduct (r_view.origin, r_view.frustum[1].normal) + r_view.ortho_x;
2361 r_view.frustum[2].dist = DotProduct (r_view.origin, r_view.frustum[2].normal) + r_view.ortho_y;
2362 r_view.frustum[3].dist = DotProduct (r_view.origin, r_view.frustum[3].normal) + r_view.ortho_y;
2363 r_view.frustum[4].dist = DotProduct (r_view.origin, r_view.frustum[4].normal) + r_refdef.nearclip;
2365 r_view.numfrustumplanes = 5;
2367 if (r_view.useclipplane)
2369 r_view.numfrustumplanes = 6;
2370 r_view.frustum[5] = r_view.clipplane;
2373 for (i = 0;i < r_view.numfrustumplanes;i++)
2374 PlaneClassify(r_view.frustum + i);
2376 // LordHavoc: note to all quake engine coders, Quake had a special case
2377 // for 90 degrees which assumed a square view (wrong), so I removed it,
2378 // Quake2 has it disabled as well.
2380 // rotate R_VIEWFORWARD right by FOV_X/2 degrees
2381 //RotatePointAroundVector( r_view.frustum[0].normal, r_view.up, r_view.forward, -(90 - r_refdef.fov_x / 2));
2382 //r_view.frustum[0].dist = DotProduct (r_view.origin, frustum[0].normal);
2383 //PlaneClassify(&frustum[0]);
2385 // rotate R_VIEWFORWARD left by FOV_X/2 degrees
2386 //RotatePointAroundVector( r_view.frustum[1].normal, r_view.up, r_view.forward, (90 - r_refdef.fov_x / 2));
2387 //r_view.frustum[1].dist = DotProduct (r_view.origin, frustum[1].normal);
2388 //PlaneClassify(&frustum[1]);
2390 // rotate R_VIEWFORWARD up by FOV_X/2 degrees
2391 //RotatePointAroundVector( r_view.frustum[2].normal, r_view.left, r_view.forward, -(90 - r_refdef.fov_y / 2));
2392 //r_view.frustum[2].dist = DotProduct (r_view.origin, frustum[2].normal);
2393 //PlaneClassify(&frustum[2]);
2395 // rotate R_VIEWFORWARD down by FOV_X/2 degrees
2396 //RotatePointAroundVector( r_view.frustum[3].normal, r_view.left, r_view.forward, (90 - r_refdef.fov_y / 2));
2397 //r_view.frustum[3].dist = DotProduct (r_view.origin, frustum[3].normal);
2398 //PlaneClassify(&frustum[3]);
2401 //VectorCopy(r_view.forward, r_view.frustum[4].normal);
2402 //r_view.frustum[4].dist = DotProduct (r_view.origin, frustum[4].normal) + r_nearclip.value;
2403 //PlaneClassify(&frustum[4]);
2406 void R_View_Update(void)
2408 R_View_SetFrustum();
2409 R_View_WorldVisibility(r_view.useclipplane);
2410 R_View_UpdateEntityVisible();
2413 void R_SetupView(void)
2415 if (!r_view.useperspective)
2416 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);
2417 else if (r_refdef.rtworldshadows || r_refdef.rtdlightshadows)
2418 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view.frustum_x, r_view.frustum_y, r_refdef.nearclip);
2420 GL_SetupView_Mode_Perspective(r_view.frustum_x, r_view.frustum_y, r_refdef.nearclip, r_refdef.farclip);
2422 GL_SetupView_Orientation_FromEntity(&r_view.matrix);
2424 if (r_view.useclipplane)
2426 // LordHavoc: couldn't figure out how to make this approach the
2427 vec_t dist = r_view.clipplane.dist - r_water_clippingplanebias.value;
2428 vec_t viewdist = DotProduct(r_view.origin, r_view.clipplane.normal);
2429 if (viewdist < r_view.clipplane.dist + r_water_clippingplanebias.value)
2430 dist = r_view.clipplane.dist;
2431 GL_SetupView_ApplyCustomNearClipPlane(r_view.clipplane.normal[0], r_view.clipplane.normal[1], r_view.clipplane.normal[2], dist);
2435 void R_ResetViewRendering2D(void)
2437 if (gl_support_fragment_shader)
2439 qglUseProgramObjectARB(0);CHECKGLERROR
2444 // GL is weird because it's bottom to top, r_view.y is top to bottom
2445 qglViewport(r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
2446 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
2447 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2448 GL_Color(1, 1, 1, 1);
2449 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2450 GL_BlendFunc(GL_ONE, GL_ZERO);
2451 GL_AlphaTest(false);
2452 GL_ScissorTest(false);
2453 GL_DepthMask(false);
2454 GL_DepthRange(0, 1);
2455 GL_DepthTest(false);
2456 R_Mesh_Matrix(&identitymatrix);
2457 R_Mesh_ResetTextureState();
2458 GL_PolygonOffset(0, 0);
2459 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
2460 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2461 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
2462 qglStencilMask(~0);CHECKGLERROR
2463 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
2464 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
2465 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
2468 void R_ResetViewRendering3D(void)
2470 if (gl_support_fragment_shader)
2472 qglUseProgramObjectARB(0);CHECKGLERROR
2477 // GL is weird because it's bottom to top, r_view.y is top to bottom
2478 qglViewport(r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
2480 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2481 GL_Color(1, 1, 1, 1);
2482 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2483 GL_BlendFunc(GL_ONE, GL_ZERO);
2484 GL_AlphaTest(false);
2485 GL_ScissorTest(true);
2487 GL_DepthRange(0, 1);
2489 R_Mesh_Matrix(&identitymatrix);
2490 R_Mesh_ResetTextureState();
2491 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
2492 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
2493 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2494 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
2495 qglStencilMask(~0);CHECKGLERROR
2496 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
2497 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
2498 GL_CullFace(r_view.cullface_back);
2502 R_Bloom_SetupShader(
2504 "// written by Forest 'LordHavoc' Hale\n"
2506 "// common definitions between vertex shader and fragment shader:\n"
2508 "#ifdef __GLSL_CG_DATA_TYPES\n"
2509 "#define myhalf half\n"
2510 "#define myhvec2 hvec2\n"
2511 "#define myhvec3 hvec3\n"
2512 "#define myhvec4 hvec4\n"
2514 "#define myhalf float\n"
2515 "#define myhvec2 vec2\n"
2516 "#define myhvec3 vec3\n"
2517 "#define myhvec4 vec4\n"
2520 "varying vec2 ScreenTexCoord;\n"
2521 "varying vec2 BloomTexCoord;\n"
2526 "// vertex shader specific:\n"
2527 "#ifdef VERTEX_SHADER\n"
2531 " ScreenTexCoord = vec2(gl_MultiTexCoord0);\n"
2532 " BloomTexCoord = vec2(gl_MultiTexCoord1);\n"
2533 " // transform vertex to camera space, using ftransform to match non-VS\n"
2535 " gl_Position = ftransform();\n"
2538 "#endif // VERTEX_SHADER\n"
2543 "// fragment shader specific:\n"
2544 "#ifdef FRAGMENT_SHADER\n"
2549 " myhvec3 color = myhvec3(texture2D(Texture_Screen, ScreenTexCoord));\n"
2550 " for (x = -BLUR_X;x <= BLUR_X;x++)
2551 " color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
2552 " color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
2553 " color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
2554 " color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
2556 " gl_FragColor = vec4(color);\n"
2559 "#endif // FRAGMENT_SHADER\n"
2562 void R_RenderScene(qboolean addwaterplanes);
2564 static void R_Water_StartFrame(void)
2567 int waterwidth, waterheight, texturewidth, textureheight;
2568 r_waterstate_waterplane_t *p;
2570 // set waterwidth and waterheight to the water resolution that will be
2571 // used (often less than the screen resolution for faster rendering)
2572 waterwidth = (int)bound(1, r_view.width * r_water_resolutionmultiplier.value, r_view.width);
2573 waterheight = (int)bound(1, r_view.height * r_water_resolutionmultiplier.value, r_view.height);
2575 // calculate desired texture sizes
2576 // can't use water if the card does not support the texture size
2577 if (!r_water.integer || !r_glsl.integer || !gl_support_fragment_shader || waterwidth > gl_max_texture_size || waterheight > gl_max_texture_size)
2578 texturewidth = textureheight = waterwidth = waterheight = 0;
2579 else if (gl_support_arb_texture_non_power_of_two)
2581 texturewidth = waterwidth;
2582 textureheight = waterheight;
2586 for (texturewidth = 1;texturewidth < waterwidth ;texturewidth *= 2);
2587 for (textureheight = 1;textureheight < waterheight;textureheight *= 2);
2590 // allocate textures as needed
2591 if (r_waterstate.waterwidth != waterwidth || r_waterstate.waterheight != waterheight || r_waterstate.texturewidth != texturewidth || r_waterstate.textureheight != textureheight)
2593 r_waterstate.maxwaterplanes = MAX_WATERPLANES;
2594 for (i = 0, p = r_waterstate.waterplanes;i < r_waterstate.maxwaterplanes;i++, p++)
2596 if (p->texture_refraction)
2597 R_FreeTexture(p->texture_refraction);
2598 p->texture_refraction = NULL;
2599 if (p->texture_reflection)
2600 R_FreeTexture(p->texture_reflection);
2601 p->texture_reflection = NULL;
2603 memset(&r_waterstate, 0, sizeof(r_waterstate));
2604 r_waterstate.waterwidth = waterwidth;
2605 r_waterstate.waterheight = waterheight;
2606 r_waterstate.texturewidth = texturewidth;
2607 r_waterstate.textureheight = textureheight;
2610 if (r_waterstate.waterwidth)
2612 r_waterstate.enabled = true;
2614 // set up variables that will be used in shader setup
2615 r_waterstate.screenscale[0] = 0.5f * (float)waterwidth / (float)texturewidth;
2616 r_waterstate.screenscale[1] = 0.5f * (float)waterheight / (float)textureheight;
2617 r_waterstate.screencenter[0] = 0.5f * (float)waterwidth / (float)texturewidth;
2618 r_waterstate.screencenter[1] = 0.5f * (float)waterheight / (float)textureheight;
2621 r_waterstate.maxwaterplanes = MAX_WATERPLANES;
2622 r_waterstate.numwaterplanes = 0;
2625 static void R_Water_AddWaterPlane(msurface_t *surface)
2627 int triangleindex, planeindex;
2633 r_waterstate_waterplane_t *p;
2634 // just use the first triangle with a valid normal for any decisions
2635 VectorClear(normal);
2636 VectorClear(center);
2637 for (triangleindex = 0, e = rsurface.modelelement3i + surface->num_firsttriangle * 3;triangleindex < surface->num_triangles;triangleindex++, e += 3)
2639 Matrix4x4_Transform(&rsurface.matrix, rsurface.modelvertex3f + e[0]*3, vert[0]);
2640 Matrix4x4_Transform(&rsurface.matrix, rsurface.modelvertex3f + e[1]*3, vert[1]);
2641 Matrix4x4_Transform(&rsurface.matrix, rsurface.modelvertex3f + e[2]*3, vert[2]);
2642 TriangleNormal(vert[0], vert[1], vert[2], normal);
2643 if (VectorLength2(normal) >= 0.001)
2646 // now find the center of this surface
2647 for (triangleindex = 0, e = rsurface.modelelement3i + surface->num_firsttriangle * 3;triangleindex < surface->num_triangles*3;triangleindex++, e++)
2649 Matrix4x4_Transform(&rsurface.matrix, rsurface.modelvertex3f + e[0]*3, vert[0]);
2650 VectorAdd(center, vert[0], center);
2652 f = 1.0 / surface->num_triangles*3;
2653 VectorScale(center, f, center);
2655 // find a matching plane if there is one
2656 for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++)
2657 if (fabs(PlaneDiff(vert[0], &p->plane)) < 1 && fabs(PlaneDiff(vert[1], &p->plane)) < 1 && fabs(PlaneDiff(vert[2], &p->plane)) < 1)
2659 if (planeindex >= r_waterstate.maxwaterplanes)
2660 return; // nothing we can do, out of planes
2662 // if this triangle does not fit any known plane rendered this frame, add one
2663 if (planeindex >= r_waterstate.numwaterplanes)
2665 // store the new plane
2666 r_waterstate.numwaterplanes++;
2667 VectorCopy(normal, p->plane.normal);
2668 VectorNormalize(p->plane.normal);
2669 p->plane.dist = DotProduct(vert[0], p->plane.normal);
2670 PlaneClassify(&p->plane);
2671 // flip the plane if it does not face the viewer
2672 if (PlaneDiff(r_view.origin, &p->plane) < 0)
2674 VectorNegate(p->plane.normal, p->plane.normal);
2675 p->plane.dist *= -1;
2676 PlaneClassify(&p->plane);
2678 // clear materialflags and pvs
2679 p->materialflags = 0;
2680 p->pvsvalid = false;
2682 // merge this surface's materialflags into the waterplane
2683 p->materialflags |= surface->texture->currentframe->currentmaterialflags;
2684 // merge this surface's PVS into the waterplane
2685 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.worldmodel && r_refdef.worldmodel->brush.FatPVS)
2687 r_refdef.worldmodel->brush.FatPVS(r_refdef.worldmodel, r_view.origin, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
2692 static void R_Water_ProcessPlanes(void)
2694 r_view_t originalview;
2696 r_waterstate_waterplane_t *p;
2698 originalview = r_view;
2700 // make sure enough textures are allocated
2701 for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++)
2703 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
2705 if (!p->texture_refraction)
2706 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);
2707 if (!p->texture_refraction)
2711 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
2713 if (!p->texture_reflection)
2714 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);
2715 if (!p->texture_reflection)
2721 for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++)
2723 r_view.showdebug = false;
2724 r_view.width = r_waterstate.waterwidth;
2725 r_view.height = r_waterstate.waterheight;
2726 r_view.useclipplane = true;
2727 r_waterstate.renderingscene = true;
2729 // render the normal view scene and copy into texture
2730 // (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)
2731 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
2733 r_view.clipplane = p->plane;
2734 VectorNegate(r_view.clipplane.normal, r_view.clipplane.normal);
2735 r_view.clipplane.dist = -r_view.clipplane.dist;
2736 PlaneClassify(&r_view.clipplane);
2738 R_RenderScene(false);
2740 // copy view into the screen texture
2741 R_Mesh_TexBind(0, R_GetTexture(p->texture_refraction));
2742 GL_ActiveTexture(0);
2744 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
2747 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
2749 // render reflected scene and copy into texture
2750 Matrix4x4_Reflect(&r_view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
2751 r_view.clipplane = p->plane;
2752 // reverse the cullface settings for this render
2753 r_view.cullface_front = GL_FRONT;
2754 r_view.cullface_back = GL_BACK;
2755 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.num_pvsclusterbytes)
2757 r_view.usecustompvs = true;
2759 memcpy(r_viewcache.world_pvsbits, p->pvsbits, r_refdef.worldmodel->brush.num_pvsclusterbytes);
2761 memset(r_viewcache.world_pvsbits, 0xFF, r_refdef.worldmodel->brush.num_pvsclusterbytes);
2764 R_ResetViewRendering3D();
2766 if (r_timereport_active)
2767 R_TimeReport("viewclear");
2769 R_RenderScene(false);
2771 R_Mesh_TexBind(0, R_GetTexture(p->texture_reflection));
2772 GL_ActiveTexture(0);
2774 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
2776 R_ResetViewRendering3D();
2778 if (r_timereport_active)
2779 R_TimeReport("viewclear");
2782 r_view = originalview;
2783 r_view.clear = true;
2784 r_waterstate.renderingscene = false;
2788 r_view = originalview;
2789 r_waterstate.renderingscene = false;
2790 Cvar_SetValueQuick(&r_water, 0);
2791 Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed! Turned off r_water.\n");
2795 void R_Bloom_StartFrame(void)
2797 int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight;
2799 // set bloomwidth and bloomheight to the bloom resolution that will be
2800 // used (often less than the screen resolution for faster rendering)
2801 r_bloomstate.bloomwidth = bound(1, r_bloom_resolution.integer, r_view.width);
2802 r_bloomstate.bloomheight = r_bloomstate.bloomwidth * r_view.height / r_view.width;
2803 r_bloomstate.bloomheight = bound(1, r_bloomstate.bloomheight, r_view.height);
2805 // calculate desired texture sizes
2806 if (gl_support_arb_texture_non_power_of_two)
2808 screentexturewidth = r_view.width;
2809 screentextureheight = r_view.height;
2810 bloomtexturewidth = r_bloomstate.bloomwidth;
2811 bloomtextureheight = r_bloomstate.bloomheight;
2815 for (screentexturewidth = 1;screentexturewidth < vid.width ;screentexturewidth *= 2);
2816 for (screentextureheight = 1;screentextureheight < vid.height ;screentextureheight *= 2);
2817 for (bloomtexturewidth = 1;bloomtexturewidth < r_bloomstate.bloomwidth ;bloomtexturewidth *= 2);
2818 for (bloomtextureheight = 1;bloomtextureheight < r_bloomstate.bloomheight;bloomtextureheight *= 2);
2823 screentexturewidth = screentextureheight = 0;
2825 else if (r_bloom.integer)
2830 screentexturewidth = screentextureheight = 0;
2831 bloomtexturewidth = bloomtextureheight = 0;
2834 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)
2836 // can't use bloom if the parameters are too weird
2837 // can't use bloom if the card does not support the texture size
2838 if (r_bloomstate.texture_screen)
2839 R_FreeTexture(r_bloomstate.texture_screen);
2840 if (r_bloomstate.texture_bloom)
2841 R_FreeTexture(r_bloomstate.texture_bloom);
2842 memset(&r_bloomstate, 0, sizeof(r_bloomstate));
2846 r_bloomstate.enabled = true;
2847 r_bloomstate.hdr = r_hdr.integer != 0;
2849 // allocate textures as needed
2850 if (r_bloomstate.screentexturewidth != screentexturewidth || r_bloomstate.screentextureheight != screentextureheight)
2852 if (r_bloomstate.texture_screen)
2853 R_FreeTexture(r_bloomstate.texture_screen);
2854 r_bloomstate.texture_screen = NULL;
2855 r_bloomstate.screentexturewidth = screentexturewidth;
2856 r_bloomstate.screentextureheight = screentextureheight;
2857 if (r_bloomstate.screentexturewidth && r_bloomstate.screentextureheight)
2858 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);
2860 if (r_bloomstate.bloomtexturewidth != bloomtexturewidth || r_bloomstate.bloomtextureheight != bloomtextureheight)
2862 if (r_bloomstate.texture_bloom)
2863 R_FreeTexture(r_bloomstate.texture_bloom);
2864 r_bloomstate.texture_bloom = NULL;
2865 r_bloomstate.bloomtexturewidth = bloomtexturewidth;
2866 r_bloomstate.bloomtextureheight = bloomtextureheight;
2867 if (r_bloomstate.bloomtexturewidth && r_bloomstate.bloomtextureheight)
2868 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);
2871 // set up a texcoord array for the full resolution screen image
2872 // (we have to keep this around to copy back during final render)
2873 r_bloomstate.screentexcoord2f[0] = 0;
2874 r_bloomstate.screentexcoord2f[1] = (float)r_view.height / (float)r_bloomstate.screentextureheight;
2875 r_bloomstate.screentexcoord2f[2] = (float)r_view.width / (float)r_bloomstate.screentexturewidth;
2876 r_bloomstate.screentexcoord2f[3] = (float)r_view.height / (float)r_bloomstate.screentextureheight;
2877 r_bloomstate.screentexcoord2f[4] = (float)r_view.width / (float)r_bloomstate.screentexturewidth;
2878 r_bloomstate.screentexcoord2f[5] = 0;
2879 r_bloomstate.screentexcoord2f[6] = 0;
2880 r_bloomstate.screentexcoord2f[7] = 0;
2882 // set up a texcoord array for the reduced resolution bloom image
2883 // (which will be additive blended over the screen image)
2884 r_bloomstate.bloomtexcoord2f[0] = 0;
2885 r_bloomstate.bloomtexcoord2f[1] = (float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
2886 r_bloomstate.bloomtexcoord2f[2] = (float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
2887 r_bloomstate.bloomtexcoord2f[3] = (float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
2888 r_bloomstate.bloomtexcoord2f[4] = (float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
2889 r_bloomstate.bloomtexcoord2f[5] = 0;
2890 r_bloomstate.bloomtexcoord2f[6] = 0;
2891 r_bloomstate.bloomtexcoord2f[7] = 0;
2894 void R_Bloom_CopyScreenTexture(float colorscale)
2896 r_refdef.stats.bloom++;
2898 R_ResetViewRendering2D();
2899 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
2900 R_Mesh_ColorPointer(NULL, 0, 0);
2901 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
2902 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
2904 // copy view into the screen texture
2905 GL_ActiveTexture(0);
2907 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
2908 r_refdef.stats.bloom_copypixels += r_view.width * r_view.height;
2910 // now scale it down to the bloom texture size
2912 qglViewport(r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
2913 GL_BlendFunc(GL_ONE, GL_ZERO);
2914 GL_Color(colorscale, colorscale, colorscale, 1);
2915 // TODO: optimize with multitexture or GLSL
2916 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2917 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2919 // we now have a bloom image in the framebuffer
2920 // copy it into the bloom image texture for later processing
2921 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2922 GL_ActiveTexture(0);
2924 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
2925 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2928 void R_Bloom_CopyHDRTexture(void)
2930 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2931 GL_ActiveTexture(0);
2933 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
2934 r_refdef.stats.bloom_copypixels += r_view.width * r_view.height;
2937 void R_Bloom_MakeTexture(void)
2940 float xoffset, yoffset, r, brighten;
2942 r_refdef.stats.bloom++;
2944 R_ResetViewRendering2D();
2945 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
2946 R_Mesh_ColorPointer(NULL, 0, 0);
2948 // we have a bloom image in the framebuffer
2950 qglViewport(r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
2952 for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
2955 r = bound(0, r_bloom_colorexponent.value / x, 1);
2956 GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
2957 GL_Color(r, r, r, 1);
2958 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2959 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
2960 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2961 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2963 // copy the vertically blurred bloom view to a texture
2964 GL_ActiveTexture(0);
2966 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
2967 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2970 range = r_bloom_blur.integer * r_bloomstate.bloomwidth / 320;
2971 brighten = r_bloom_brighten.value;
2973 brighten *= r_hdr_range.value;
2974 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2975 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.offsettexcoord2f, 0, 0);
2977 for (dir = 0;dir < 2;dir++)
2979 // blend on at multiple vertical offsets to achieve a vertical blur
2980 // TODO: do offset blends using GLSL
2981 GL_BlendFunc(GL_ONE, GL_ZERO);
2982 for (x = -range;x <= range;x++)
2984 if (!dir){xoffset = 0;yoffset = x;}
2985 else {xoffset = x;yoffset = 0;}
2986 xoffset /= (float)r_bloomstate.bloomtexturewidth;
2987 yoffset /= (float)r_bloomstate.bloomtextureheight;
2988 // compute a texcoord array with the specified x and y offset
2989 r_bloomstate.offsettexcoord2f[0] = xoffset+0;
2990 r_bloomstate.offsettexcoord2f[1] = yoffset+(float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
2991 r_bloomstate.offsettexcoord2f[2] = xoffset+(float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
2992 r_bloomstate.offsettexcoord2f[3] = yoffset+(float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
2993 r_bloomstate.offsettexcoord2f[4] = xoffset+(float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
2994 r_bloomstate.offsettexcoord2f[5] = yoffset+0;
2995 r_bloomstate.offsettexcoord2f[6] = xoffset+0;
2996 r_bloomstate.offsettexcoord2f[7] = yoffset+0;
2997 // this r value looks like a 'dot' particle, fading sharply to
2998 // black at the edges
2999 // (probably not realistic but looks good enough)
3000 //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
3001 //r = (dir ? 1.0f : brighten)/(range*2+1);
3002 r = (dir ? 1.0f : brighten)/(range*2+1)*(1 - x*x/(float)(range*range));
3003 GL_Color(r, r, r, 1);
3004 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3005 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
3006 GL_BlendFunc(GL_ONE, GL_ONE);
3009 // copy the vertically blurred bloom view to a texture
3010 GL_ActiveTexture(0);
3012 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
3013 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
3016 // apply subtract last
3017 // (just like it would be in a GLSL shader)
3018 if (r_bloom_colorsubtract.value > 0 && gl_support_ext_blend_subtract)
3020 GL_BlendFunc(GL_ONE, GL_ZERO);
3021 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
3022 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
3023 GL_Color(1, 1, 1, 1);
3024 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3025 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
3027 GL_BlendFunc(GL_ONE, GL_ONE);
3028 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
3029 R_Mesh_TexBind(0, R_GetTexture(r_texture_white));
3030 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
3031 GL_Color(r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, 1);
3032 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3033 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
3034 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
3036 // copy the darkened bloom view to a texture
3037 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
3038 GL_ActiveTexture(0);
3040 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
3041 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
3045 void R_HDR_RenderBloomTexture(void)
3047 int oldwidth, oldheight;
3049 oldwidth = r_view.width;
3050 oldheight = r_view.height;
3051 r_view.width = r_bloomstate.bloomwidth;
3052 r_view.height = r_bloomstate.bloomheight;
3054 // TODO: support GL_EXT_framebuffer_object rather than reusing the framebuffer? it might improve SLI performance.
3055 // TODO: add exposure compensation features
3056 // TODO: add fp16 framebuffer support
3058 r_view.showdebug = false;
3059 r_view.colorscale = r_bloom_colorscale.value * r_hdr_scenebrightness.value;
3061 r_view.colorscale /= r_hdr_range.value;
3062 r_waterstate.numwaterplanes = 0;
3063 R_RenderScene(r_waterstate.enabled);
3064 r_view.showdebug = true;
3066 R_ResetViewRendering2D();
3068 R_Bloom_CopyHDRTexture();
3069 R_Bloom_MakeTexture();
3071 R_ResetViewRendering3D();
3074 if (r_timereport_active)
3075 R_TimeReport("viewclear");
3077 // restore the view settings
3078 r_view.width = oldwidth;
3079 r_view.height = oldheight;
3082 static void R_BlendView(void)
3084 if (r_bloomstate.enabled && r_bloomstate.hdr)
3086 // render high dynamic range bloom effect
3087 // the bloom texture was made earlier this render, so we just need to
3088 // blend it onto the screen...
3089 R_ResetViewRendering2D();
3090 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
3091 R_Mesh_ColorPointer(NULL, 0, 0);
3092 GL_Color(1, 1, 1, 1);
3093 GL_BlendFunc(GL_ONE, GL_ONE);
3094 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
3095 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
3096 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3097 r_refdef.stats.bloom_drawpixels += r_view.width * r_view.height;
3099 else if (r_bloomstate.enabled)
3101 // render simple bloom effect
3102 // copy the screen and shrink it and darken it for the bloom process
3103 R_Bloom_CopyScreenTexture(r_bloom_colorscale.value);
3104 // make the bloom texture
3105 R_Bloom_MakeTexture();
3106 // put the original screen image back in place and blend the bloom
3108 R_ResetViewRendering2D();
3109 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
3110 R_Mesh_ColorPointer(NULL, 0, 0);
3111 GL_Color(1, 1, 1, 1);
3112 GL_BlendFunc(GL_ONE, GL_ZERO);
3113 // do both in one pass if possible
3114 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
3115 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
3116 if (r_textureunits.integer >= 2 && gl_combine.integer)
3118 R_Mesh_TexCombine(1, GL_ADD, GL_ADD, 1, 1);
3119 R_Mesh_TexBind(1, R_GetTexture(r_bloomstate.texture_screen));
3120 R_Mesh_TexCoordPointer(1, 2, r_bloomstate.screentexcoord2f, 0, 0);
3124 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3125 r_refdef.stats.bloom_drawpixels += r_view.width * r_view.height;
3126 // now blend on the bloom texture
3127 GL_BlendFunc(GL_ONE, GL_ONE);
3128 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
3129 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
3131 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3132 r_refdef.stats.bloom_drawpixels += r_view.width * r_view.height;
3134 if (r_refdef.viewblend[3] >= (1.0f / 256.0f))
3136 // apply a color tint to the whole view
3137 R_ResetViewRendering2D();
3138 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
3139 R_Mesh_ColorPointer(NULL, 0, 0);
3140 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3141 GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
3142 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3146 void R_RenderScene(qboolean addwaterplanes);
3148 matrix4x4_t r_waterscrollmatrix;
3150 void R_UpdateVariables(void)
3154 r_refdef.farclip = 4096;
3155 if (r_refdef.worldmodel)
3156 r_refdef.farclip += VectorDistance(r_refdef.worldmodel->normalmins, r_refdef.worldmodel->normalmaxs);
3157 r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
3159 if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
3160 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
3161 r_refdef.polygonfactor = 0;
3162 r_refdef.polygonoffset = 0;
3163 r_refdef.shadowpolygonfactor = r_refdef.polygonfactor + r_shadow_polygonfactor.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
3164 r_refdef.shadowpolygonoffset = r_refdef.polygonoffset + r_shadow_polygonoffset.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
3166 r_refdef.rtworld = r_shadow_realtime_world.integer;
3167 r_refdef.rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
3168 r_refdef.rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer && r_dynamic.integer;
3169 r_refdef.rtdlightshadows = r_refdef.rtdlight && r_shadow_realtime_dlight_shadows.integer && gl_stencil;
3170 r_refdef.lightmapintensity = r_refdef.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
3171 if (r_showsurfaces.integer)
3173 r_refdef.rtworld = false;
3174 r_refdef.rtworldshadows = false;
3175 r_refdef.rtdlight = false;
3176 r_refdef.rtdlightshadows = false;
3177 r_refdef.lightmapintensity = 0;
3180 if (gamemode == GAME_NEHAHRA)
3182 if (gl_fogenable.integer)
3184 r_refdef.oldgl_fogenable = true;
3185 r_refdef.fog_density = gl_fogdensity.value;
3186 r_refdef.fog_red = gl_fogred.value;
3187 r_refdef.fog_green = gl_foggreen.value;
3188 r_refdef.fog_blue = gl_fogblue.value;
3190 else if (r_refdef.oldgl_fogenable)
3192 r_refdef.oldgl_fogenable = false;
3193 r_refdef.fog_density = 0;