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.
23 #include "cl_dyntexture.h"
28 mempool_t *r_main_mempool;
29 rtexturepool_t *r_main_texturepool;
31 static int r_frame = 0; ///< used only by R_GetCurrentTexture
38 cvar_t r_motionblur = {CVAR_SAVE, "r_motionblur", "0", "motionblur value scale - 0.5 recommended"};
39 cvar_t r_damageblur = {CVAR_SAVE, "r_damageblur", "0", "motionblur based on damage"};
40 cvar_t r_motionblur_vmin = {CVAR_SAVE, "r_motionblur_vmin", "300", "minimum influence from velocity"};
41 cvar_t r_motionblur_vmax = {CVAR_SAVE, "r_motionblur_vmax", "600", "maximum influence from velocity"};
42 cvar_t r_motionblur_bmin = {CVAR_SAVE, "r_motionblur_bmin", "0.5", "velocity at which there is no blur yet (may be negative to always have some blur)"};
43 cvar_t r_motionblur_vcoeff = {CVAR_SAVE, "r_motionblur_vcoeff", "0.05", "sliding average reaction time for velocity"};
44 cvar_t r_motionblur_maxblur = {CVAR_SAVE, "r_motionblur_maxblur", "0.88", "cap for motionblur alpha value"};
45 cvar_t r_motionblur_randomize = {CVAR_SAVE, "r_motionblur_randomize", "0.1", "randomizing coefficient to workaround ghosting"};
47 cvar_t r_animcache = {CVAR_SAVE, "r_animcache", "1", "cache animation frames to save CPU usage, primarily optimizes shadows and reflections"};
49 cvar_t r_depthfirst = {CVAR_SAVE, "r_depthfirst", "0", "renders a depth-only version of the scene before normal rendering begins to eliminate overdraw, values: 0 = off, 1 = world depth, 2 = world and model depth"};
50 cvar_t r_useinfinitefarclip = {CVAR_SAVE, "r_useinfinitefarclip", "1", "enables use of a special kind of projection matrix that has an extremely large farclip"};
51 cvar_t r_nearclip = {0, "r_nearclip", "1", "distance from camera of nearclip plane" };
52 cvar_t r_showbboxes = {0, "r_showbboxes", "0", "shows bounding boxes of server entities, value controls opacity scaling (1 = 10%, 10 = 100%)"};
53 cvar_t r_showsurfaces = {0, "r_showsurfaces", "0", "1 shows surfaces as different colors, or a value of 2 shows triangle draw order (for analyzing whether meshes are optimized for vertex cache)"};
54 cvar_t r_showtris = {0, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"};
55 cvar_t r_shownormals = {0, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"};
56 cvar_t r_showlighting = {0, "r_showlighting", "0", "shows areas lit by lights, useful for finding out why some areas of a map render slowly (bright orange = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"};
57 cvar_t r_showshadowvolumes = {0, "r_showshadowvolumes", "0", "shows areas shadowed by lights, useful for finding out why some areas of a map render slowly (bright blue = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"};
58 cvar_t r_showcollisionbrushes = {0, "r_showcollisionbrushes", "0", "draws collision brushes in quake3 maps (mode 1), mode 2 disables rendering of world (trippy!)"};
59 cvar_t r_showcollisionbrushes_polygonfactor = {0, "r_showcollisionbrushes_polygonfactor", "-1", "expands outward the brush polygons a little bit, used to make collision brushes appear infront of walls"};
60 cvar_t r_showcollisionbrushes_polygonoffset = {0, "r_showcollisionbrushes_polygonoffset", "0", "nudges brush polygon depth in hardware depth units, used to make collision brushes appear infront of walls"};
61 cvar_t r_showdisabledepthtest = {0, "r_showdisabledepthtest", "0", "disables depth testing on r_show* cvars, allowing you to see what hidden geometry the graphics card is processing"};
62 cvar_t r_drawportals = {0, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"};
63 cvar_t r_drawentities = {0, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"};
64 cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1", "draw your weapon model"};
65 cvar_t r_cullentities_trace = {0, "r_cullentities_trace", "1", "probabistically cull invisible entities"};
66 cvar_t r_cullentities_trace_samples = {0, "r_cullentities_trace_samples", "2", "number of samples to test for entity culling"};
67 cvar_t r_cullentities_trace_enlarge = {0, "r_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
68 cvar_t r_cullentities_trace_delay = {0, "r_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
69 cvar_t r_speeds = {0, "r_speeds","0", "displays rendering statistics and per-subsystem timings"};
70 cvar_t r_fullbright = {0, "r_fullbright","0", "makes map very bright and renders faster"};
71 cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1", "opacity of water polygons"};
72 cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1", "enables dynamic lights (rocket glow and such)"};
73 cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1", "enables glowing pixels in quake textures (changes need r_restart to take effect)"};
74 cvar_t r_shadows = {CVAR_SAVE, "r_shadows", "0", "casts fake stencil shadows from models onto the world (rtlights are unaffected by this); when set to 2, always cast the shadows in the direction set by r_shadows_throwdirection, otherwise use the model lighting."};
75 cvar_t r_shadows_darken = {CVAR_SAVE, "r_shadows_darken", "0.5", "how much shadowed areas will be darkened"};
76 cvar_t r_shadows_throwdistance = {CVAR_SAVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"};
77 cvar_t r_shadows_throwdirection = {CVAR_SAVE, "r_shadows_throwdirection", "0 0 -1", "override throwing direction for r_shadows 2"};
78 cvar_t r_shadows_drawafterrtlightning = {CVAR_SAVE, "r_shadows_drawafterrtlightning", "0", "draw fake shadows AFTER realtime lightning is drawn. May be useful for simulating fast sunlight on large outdoor maps with only one noshadow rtlight. The price is less realistic appearance of dynamic light shadows."};
79 cvar_t r_shadows_castfrombmodels = {CVAR_SAVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"};
80 cvar_t r_q1bsp_skymasking = {0, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
81 cvar_t r_polygonoffset_submodel_factor = {0, "r_polygonoffset_submodel_factor", "0", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
82 cvar_t r_polygonoffset_submodel_offset = {0, "r_polygonoffset_submodel_offset", "2", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
83 cvar_t r_fog_exp2 = {0, "r_fog_exp2", "0", "uses GL_EXP2 fog (as in Nehahra) rather than realistic GL_EXP fog"};
84 cvar_t r_drawfog = {CVAR_SAVE, "r_drawfog", "1", "allows one to disable fog rendering"};
86 cvar_t gl_fogenable = {0, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"};
87 cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"};
88 cvar_t gl_fogred = {0, "gl_fogred","0.3", "nehahra fog color red value (for Nehahra compatibility only)"};
89 cvar_t gl_foggreen = {0, "gl_foggreen","0.3", "nehahra fog color green value (for Nehahra compatibility only)"};
90 cvar_t gl_fogblue = {0, "gl_fogblue","0.3", "nehahra fog color blue value (for Nehahra compatibility only)"};
91 cvar_t gl_fogstart = {0, "gl_fogstart", "0", "nehahra fog start distance (for Nehahra compatibility only)"};
92 cvar_t gl_fogend = {0, "gl_fogend","0", "nehahra fog end distance (for Nehahra compatibility only)"};
93 cvar_t gl_skyclip = {0, "gl_skyclip", "4608", "nehahra farclip distance - the real fog end (for Nehahra compatibility only)"};
95 cvar_t r_textureunits = {0, "r_textureunits", "32", "number of hardware texture units reported by driver (note: setting this to 1 turns off gl_combine)"};
97 cvar_t r_glsl = {CVAR_SAVE, "r_glsl", "1", "enables use of OpenGL 2.0 pixel shaders for lighting"};
98 cvar_t r_glsl_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)"};
99 cvar_t r_glsl_offsetmapping = {CVAR_SAVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
100 cvar_t r_glsl_offsetmapping_reliefmapping = {CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
101 cvar_t r_glsl_offsetmapping_scale = {CVAR_SAVE, "r_glsl_offsetmapping_scale", "0.04", "how deep the offset mapping effect is"};
102 cvar_t r_glsl_postprocess = {CVAR_SAVE, "r_glsl_postprocess", "0", "use a GLSL postprocessing shader"};
103 cvar_t r_glsl_postprocess_uservec1 = {CVAR_SAVE, "r_glsl_postprocess_uservec1", "0 0 0 0", "a 4-component vector to pass as uservec1 to the postprocessing shader (only useful if default.glsl has been customized)"};
104 cvar_t r_glsl_postprocess_uservec2 = {CVAR_SAVE, "r_glsl_postprocess_uservec2", "0 0 0 0", "a 4-component vector to pass as uservec2 to the postprocessing shader (only useful if default.glsl has been customized)"};
105 cvar_t r_glsl_postprocess_uservec3 = {CVAR_SAVE, "r_glsl_postprocess_uservec3", "0 0 0 0", "a 4-component vector to pass as uservec3 to the postprocessing shader (only useful if default.glsl has been customized)"};
106 cvar_t r_glsl_postprocess_uservec4 = {CVAR_SAVE, "r_glsl_postprocess_uservec4", "0 0 0 0", "a 4-component vector to pass as uservec4 to the postprocessing shader (only useful if default.glsl has been customized)"};
107 cvar_t r_glsl_usegeneric = {CVAR_SAVE, "r_glsl_usegeneric", "1", "use shaders for rendering simple geometry (rather than conventional fixed-function rendering for this purpose)"};
109 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)"};
110 cvar_t r_water_clippingplanebias = {CVAR_SAVE, "r_water_clippingplanebias", "1", "a rather technical setting which avoids black pixels around water edges"};
111 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"};
112 cvar_t r_water_refractdistort = {CVAR_SAVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
113 cvar_t r_water_reflectdistort = {CVAR_SAVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"};
115 cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "1", "enables animation smoothing on sprites"};
116 cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
117 cvar_t r_lerplightstyles = {CVAR_SAVE, "r_lerplightstyles", "0", "enable animation smoothing on flickering lights"};
118 cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
120 cvar_t r_bloom = {CVAR_SAVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"};
121 cvar_t r_bloom_colorscale = {CVAR_SAVE, "r_bloom_colorscale", "1", "how bright the glow is"};
122 cvar_t r_bloom_brighten = {CVAR_SAVE, "r_bloom_brighten", "2", "how bright the glow is, after subtract/power"};
123 cvar_t r_bloom_blur = {CVAR_SAVE, "r_bloom_blur", "4", "how large the glow is"};
124 cvar_t r_bloom_resolution = {CVAR_SAVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"};
125 cvar_t r_bloom_colorexponent = {CVAR_SAVE, "r_bloom_colorexponent", "1", "how exagerated the glow is"};
126 cvar_t r_bloom_colorsubtract = {CVAR_SAVE, "r_bloom_colorsubtract", "0.125", "reduces bloom colors by a certain amount"};
128 cvar_t r_hdr = {CVAR_SAVE, "r_hdr", "0", "enables High Dynamic Range bloom effect (higher quality version of r_bloom)"};
129 cvar_t r_hdr_scenebrightness = {CVAR_SAVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
130 cvar_t r_hdr_glowintensity = {CVAR_SAVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
131 cvar_t r_hdr_range = {CVAR_SAVE, "r_hdr_range", "4", "how much dynamic range to render bloom with (equivilant to multiplying r_bloom_brighten by this value and dividing r_bloom_colorscale by this value)"};
133 cvar_t r_smoothnormals_areaweighting = {0, "r_smoothnormals_areaweighting", "1", "uses significantly faster (and supposedly higher quality) area-weighted vertex normals and tangent vectors rather than summing normalized triangle normals and tangents"};
135 cvar_t developer_texturelogging = {0, "developer_texturelogging", "0", "produces a textures.log file containing names of skins and map textures the engine tried to load"};
137 cvar_t gl_lightmaps = {0, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers)"};
139 cvar_t r_test = {0, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
140 cvar_t r_batchmode = {0, "r_batchmode", "1", "selects method of rendering multiple surfaces with one driver call (values are 0, 1, 2, etc...)"};
141 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"};
142 cvar_t r_track_sprites_flags = {CVAR_SAVE, "r_track_sprites_flags", "1", "1: Rotate sprites accodringly, 2: Make it a continuous rotation"};
143 cvar_t r_track_sprites_scalew = {CVAR_SAVE, "r_track_sprites_scalew", "1", "width scaling of tracked sprites"};
144 cvar_t r_track_sprites_scaleh = {CVAR_SAVE, "r_track_sprites_scaleh", "1", "height scaling of tracked sprites"};
145 cvar_t r_glsl_saturation = {CVAR_SAVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"};
147 extern cvar_t v_glslgamma;
149 extern qboolean v_flipped_state;
151 static struct r_bloomstate_s
156 int bloomwidth, bloomheight;
158 int screentexturewidth, screentextureheight;
159 rtexture_t *texture_screen; /// \note also used for motion blur if enabled!
161 int bloomtexturewidth, bloomtextureheight;
162 rtexture_t *texture_bloom;
164 // arrays for rendering the screen passes
165 float screentexcoord2f[8];
166 float bloomtexcoord2f[8];
167 float offsettexcoord2f[8];
171 r_waterstate_t r_waterstate;
173 /// shadow volume bsp struct with automatically growing nodes buffer
176 rtexture_t *r_texture_blanknormalmap;
177 rtexture_t *r_texture_white;
178 rtexture_t *r_texture_grey128;
179 rtexture_t *r_texture_black;
180 rtexture_t *r_texture_notexture;
181 rtexture_t *r_texture_whitecube;
182 rtexture_t *r_texture_normalizationcube;
183 rtexture_t *r_texture_fogattenuation;
184 rtexture_t *r_texture_gammaramps;
185 unsigned int r_texture_gammaramps_serial;
186 //rtexture_t *r_texture_fogintensity;
188 unsigned int r_queries[R_MAX_OCCLUSION_QUERIES];
189 unsigned int r_numqueries;
190 unsigned int r_maxqueries;
192 char r_qwskincache[MAX_SCOREBOARD][MAX_QPATH];
193 skinframe_t *r_qwskincache_skinframe[MAX_SCOREBOARD];
195 /// vertex coordinates for a quad that covers the screen exactly
196 const static float r_screenvertex3f[12] =
204 extern void R_DrawModelShadows(void);
206 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
209 for (i = 0;i < verts;i++)
220 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
223 for (i = 0;i < verts;i++)
233 // FIXME: move this to client?
236 if (gamemode == GAME_NEHAHRA)
238 Cvar_Set("gl_fogenable", "0");
239 Cvar_Set("gl_fogdensity", "0.2");
240 Cvar_Set("gl_fogred", "0.3");
241 Cvar_Set("gl_foggreen", "0.3");
242 Cvar_Set("gl_fogblue", "0.3");
244 r_refdef.fog_density = 0;
245 r_refdef.fog_red = 0;
246 r_refdef.fog_green = 0;
247 r_refdef.fog_blue = 0;
248 r_refdef.fog_alpha = 1;
249 r_refdef.fog_start = 0;
250 r_refdef.fog_end = 0;
253 float FogForDistance(vec_t dist)
255 unsigned int fogmasktableindex = (unsigned int)(dist * r_refdef.fogmasktabledistmultiplier);
256 return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
259 float FogPoint_World(const vec3_t p)
261 return FogForDistance(VectorDistance((p), r_refdef.view.origin));
264 float FogPoint_Model(const vec3_t p)
266 return FogForDistance(VectorDistance((p), rsurface.modelorg) * Matrix4x4_ScaleFromMatrix(&rsurface.matrix));
269 static void R_BuildBlankTextures(void)
271 unsigned char data[4];
272 data[2] = 128; // normal X
273 data[1] = 128; // normal Y
274 data[0] = 255; // normal Z
275 data[3] = 128; // height
276 r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_PERSISTENT, NULL);
281 r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_PERSISTENT, NULL);
286 r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_PERSISTENT, NULL);
291 r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_PERSISTENT, NULL);
294 static void R_BuildNoTexture(void)
297 unsigned char pix[16][16][4];
298 // this makes a light grey/dark grey checkerboard texture
299 for (y = 0;y < 16;y++)
301 for (x = 0;x < 16;x++)
303 if ((y < 8) ^ (x < 8))
319 r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_PERSISTENT, NULL);
322 static void R_BuildWhiteCube(void)
324 unsigned char data[6*1*1*4];
325 memset(data, 255, sizeof(data));
326 r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_PERSISTENT, NULL);
329 static void R_BuildNormalizationCube(void)
333 vec_t s, t, intensity;
335 unsigned char data[6][NORMSIZE][NORMSIZE][4];
336 for (side = 0;side < 6;side++)
338 for (y = 0;y < NORMSIZE;y++)
340 for (x = 0;x < NORMSIZE;x++)
342 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
343 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
378 intensity = 127.0f / sqrt(DotProduct(v, v));
379 data[side][y][x][2] = (unsigned char)(128.0f + intensity * v[0]);
380 data[side][y][x][1] = (unsigned char)(128.0f + intensity * v[1]);
381 data[side][y][x][0] = (unsigned char)(128.0f + intensity * v[2]);
382 data[side][y][x][3] = 255;
386 r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, &data[0][0][0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_CLAMP | TEXF_PERSISTENT, NULL);
389 static void R_BuildFogTexture(void)
393 unsigned char data1[FOGWIDTH][4];
394 //unsigned char data2[FOGWIDTH][4];
397 r_refdef.fogmasktable_start = r_refdef.fog_start;
398 r_refdef.fogmasktable_alpha = r_refdef.fog_alpha;
399 r_refdef.fogmasktable_range = r_refdef.fogrange;
400 r_refdef.fogmasktable_density = r_refdef.fog_density;
402 r = r_refdef.fogmasktable_range / FOGMASKTABLEWIDTH;
403 for (x = 0;x < FOGMASKTABLEWIDTH;x++)
405 d = (x * r - r_refdef.fogmasktable_start);
406 if(developer.integer >= 100)
407 Con_Printf("%f ", d);
409 if (r_fog_exp2.integer)
410 alpha = exp(-r_refdef.fogmasktable_density * r_refdef.fogmasktable_density * 0.0001 * d * d);
412 alpha = exp(-r_refdef.fogmasktable_density * 0.004 * d);
413 if(developer.integer >= 100)
414 Con_Printf(" : %f ", alpha);
415 alpha = 1 - (1 - alpha) * r_refdef.fogmasktable_alpha;
416 if(developer.integer >= 100)
417 Con_Printf(" = %f\n", alpha);
418 r_refdef.fogmasktable[x] = bound(0, alpha, 1);
421 for (x = 0;x < FOGWIDTH;x++)
423 b = (int)(r_refdef.fogmasktable[x * (FOGMASKTABLEWIDTH - 1) / (FOGWIDTH - 1)] * 255);
428 //data2[x][0] = 255 - b;
429 //data2[x][1] = 255 - b;
430 //data2[x][2] = 255 - b;
433 if (r_texture_fogattenuation)
435 R_UpdateTexture(r_texture_fogattenuation, &data1[0][0], 0, 0, FOGWIDTH, 1);
436 //R_UpdateTexture(r_texture_fogattenuation, &data2[0][0], 0, 0, FOGWIDTH, 1);
440 r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, NULL);
441 //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
445 static const char *builtinshaderstring =
446 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
447 "// written by Forest 'LordHavoc' Hale\n"
448 "#ifdef USESHADOWMAPRECT\n"
449 "#extension GL_ARB_texture_rectangle : enable\n"
451 "#ifdef USESHADOWMAPCUBE\n"
452 "#extension GL_EXT_gpu_shader4 : enable\n"
455 "// common definitions between vertex shader and fragment shader:\n"
457 "//#ifdef __GLSL_CG_DATA_TYPES\n"
458 "//# define myhalf half\n"
459 "//# define myhalf2 half2\n"
460 "//# define myhalf3 half3\n"
461 "//# define myhalf4 half4\n"
463 "# define myhalf float\n"
464 "# define myhalf2 vec2\n"
465 "# define myhalf3 vec3\n"
466 "# define myhalf4 vec4\n"
469 "#ifdef MODE_DEPTH_OR_SHADOW\n"
471 "# ifdef VERTEX_SHADER\n"
474 " gl_Position = ftransform();\n"
479 "#ifdef MODE_SHOWDEPTH\n"
480 "# ifdef VERTEX_SHADER\n"
483 " gl_Position = ftransform();\n"
484 " gl_FrontColor = vec4(gl_Position.z, gl_Position.z, gl_Position.z, 1.0);\n"
487 "# ifdef FRAGMENT_SHADER\n"
490 " gl_FragColor = gl_Color;\n"
494 "#else // !MODE_SHOWDEPTH\n"
496 "#ifdef MODE_POSTPROCESS\n"
497 "# ifdef VERTEX_SHADER\n"
500 " gl_FrontColor = gl_Color;\n"
501 " gl_Position = ftransform();\n"
502 " gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;\n"
504 " gl_TexCoord[1] = gl_TextureMatrix[1] * gl_MultiTexCoord1;\n"
508 "# ifdef FRAGMENT_SHADER\n"
510 "uniform sampler2D Texture_First;\n"
512 "uniform sampler2D Texture_Second;\n"
514 "#ifdef USEGAMMARAMPS\n"
515 "uniform sampler2D Texture_GammaRamps;\n"
517 "#ifdef USESATURATION\n"
518 "uniform float Saturation;\n"
520 "#ifdef USEVIEWTINT\n"
521 "uniform vec4 TintColor;\n"
523 "//uncomment these if you want to use them:\n"
524 "uniform vec4 UserVec1;\n"
525 "// uniform vec4 UserVec2;\n"
526 "// uniform vec4 UserVec3;\n"
527 "// uniform vec4 UserVec4;\n"
528 "// uniform float ClientTime;\n"
529 "uniform vec2 PixelSize;\n"
532 " gl_FragColor = texture2D(Texture_First, gl_TexCoord[0].xy);\n"
534 " gl_FragColor += texture2D(Texture_Second, gl_TexCoord[1].xy);\n"
536 "#ifdef USEVIEWTINT\n"
537 " gl_FragColor = mix(gl_FragColor, TintColor, TintColor.a);\n"
540 "#ifdef USEPOSTPROCESSING\n"
541 "// do r_glsl_dumpshader, edit glsl/default.glsl, and replace this by your own postprocessing if you want\n"
542 "// this code does a blur with the radius specified in the first component of r_glsl_postprocess_uservec1 and blends it using the second component\n"
543 " gl_FragColor += texture2D(Texture_First, gl_TexCoord[0].xy + PixelSize*UserVec1.x*vec2(-0.987688, -0.156434)) * UserVec1.y;\n"
544 " gl_FragColor += texture2D(Texture_First, gl_TexCoord[0].xy + PixelSize*UserVec1.x*vec2(-0.156434, -0.891007)) * UserVec1.y;\n"
545 " gl_FragColor += texture2D(Texture_First, gl_TexCoord[0].xy + PixelSize*UserVec1.x*vec2( 0.891007, -0.453990)) * UserVec1.y;\n"
546 " gl_FragColor += texture2D(Texture_First, gl_TexCoord[0].xy + PixelSize*UserVec1.x*vec2( 0.707107, 0.707107)) * UserVec1.y;\n"
547 " gl_FragColor += texture2D(Texture_First, gl_TexCoord[0].xy + PixelSize*UserVec1.x*vec2(-0.453990, 0.891007)) * UserVec1.y;\n"
548 " gl_FragColor /= (1 + 5 * UserVec1.y);\n"
551 "#ifdef USESATURATION\n"
552 " //apply saturation BEFORE gamma ramps, so v_glslgamma value does not matter\n"
553 " myhalf y = dot(gl_FragColor.rgb, vec3(0.299, 0.587, 0.114));\n"
554 " //gl_FragColor = vec3(y) + (gl_FragColor.rgb - vec3(y)) * Saturation;\n"
555 " gl_FragColor.rgb = mix(vec3(y), gl_FragColor.rgb, Saturation);\n" // TODO: test this on ATI
558 "#ifdef USEGAMMARAMPS\n"
559 " gl_FragColor.r = texture2D(Texture_GammaRamps, vec2(gl_FragColor.r, 0)).r;\n"
560 " gl_FragColor.g = texture2D(Texture_GammaRamps, vec2(gl_FragColor.g, 0)).g;\n"
561 " gl_FragColor.b = texture2D(Texture_GammaRamps, vec2(gl_FragColor.b, 0)).b;\n"
568 "#ifdef MODE_GENERIC\n"
569 "# ifdef VERTEX_SHADER\n"
572 " gl_FrontColor = gl_Color;\n"
573 "# ifdef USEDIFFUSE\n"
574 " gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;\n"
576 "# ifdef USESPECULAR\n"
577 " gl_TexCoord[1] = gl_TextureMatrix[1] * gl_MultiTexCoord1;\n"
579 " gl_Position = ftransform();\n"
582 "# ifdef FRAGMENT_SHADER\n"
584 "# ifdef USEDIFFUSE\n"
585 "uniform sampler2D Texture_First;\n"
587 "# ifdef USESPECULAR\n"
588 "uniform sampler2D Texture_Second;\n"
593 " gl_FragColor = gl_Color;\n"
594 "# ifdef USEDIFFUSE\n"
595 " gl_FragColor *= texture2D(Texture_First, gl_TexCoord[0].xy);\n"
598 "# ifdef USESPECULAR\n"
599 " vec4 tex2 = texture2D(Texture_Second, gl_TexCoord[1].xy);\n"
601 "# ifdef USECOLORMAPPING\n"
602 " gl_FragColor *= tex2;\n"
605 " gl_FragColor += tex2;\n"
607 "# ifdef USEVERTEXTEXTUREBLEND\n"
608 " gl_FragColor = mix(gl_FragColor, tex2, tex2.a);\n"
613 "#else // !MODE_GENERIC\n"
615 "varying vec2 TexCoord;\n"
616 "#ifdef USEVERTEXTEXTUREBLEND\n"
617 "varying vec2 TexCoord2;\n"
619 "varying vec2 TexCoordLightmap;\n"
621 "#ifdef MODE_LIGHTSOURCE\n"
622 "varying vec3 CubeVector;\n"
625 "#ifdef MODE_LIGHTSOURCE\n"
626 "varying vec3 LightVector;\n"
628 "#ifdef MODE_LIGHTDIRECTION\n"
629 "varying vec3 LightVector;\n"
632 "varying vec3 EyeVector;\n"
634 "varying vec3 EyeVectorModelSpace;\n"
637 "varying vec3 VectorS; // direction of S texcoord (sometimes crudely called tangent)\n"
638 "varying vec3 VectorT; // direction of T texcoord (sometimes crudely called binormal)\n"
639 "varying vec3 VectorR; // direction of R texcoord (surface normal)\n"
641 "#ifdef MODE_WATER\n"
642 "varying vec4 ModelViewProjectionPosition;\n"
644 "#ifdef MODE_REFRACTION\n"
645 "varying vec4 ModelViewProjectionPosition;\n"
647 "#ifdef USEREFLECTION\n"
648 "varying vec4 ModelViewProjectionPosition;\n"
655 "// vertex shader specific:\n"
656 "#ifdef VERTEX_SHADER\n"
658 "uniform vec3 LightPosition;\n"
659 "uniform vec3 EyePosition;\n"
660 "uniform vec3 LightDir;\n"
662 "// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3), this would require sending a 4 component texcoord1 with W as 1 or -1 according to which side the texcoord2 should be on\n"
666 " gl_FrontColor = gl_Color;\n"
667 " // copy the surface texcoord\n"
668 " TexCoord = vec2(gl_TextureMatrix[0] * gl_MultiTexCoord0);\n"
669 "#ifdef USEVERTEXTEXTUREBLEND\n"
670 " TexCoord2 = vec2(gl_TextureMatrix[1] * gl_MultiTexCoord0);\n"
672 "#ifndef MODE_LIGHTSOURCE\n"
673 "# ifndef MODE_LIGHTDIRECTION\n"
674 " TexCoordLightmap = vec2(gl_MultiTexCoord4);\n"
678 "#ifdef MODE_LIGHTSOURCE\n"
679 " // transform vertex position into light attenuation/cubemap space\n"
680 " // (-1 to +1 across the light box)\n"
681 " CubeVector = vec3(gl_TextureMatrix[3] * gl_Vertex);\n"
683 " // transform unnormalized light direction into tangent space\n"
684 " // (we use unnormalized to ensure that it interpolates correctly and then\n"
685 " // normalize it per pixel)\n"
686 " vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n"
687 " LightVector.x = dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
688 " LightVector.y = dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
689 " LightVector.z = dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n"
692 "#ifdef MODE_LIGHTDIRECTION\n"
693 " LightVector.x = dot(LightDir, gl_MultiTexCoord1.xyz);\n"
694 " LightVector.y = dot(LightDir, gl_MultiTexCoord2.xyz);\n"
695 " LightVector.z = dot(LightDir, gl_MultiTexCoord3.xyz);\n"
698 " // transform unnormalized eye direction into tangent space\n"
700 " vec3 EyeVectorModelSpace;\n"
702 " EyeVectorModelSpace = EyePosition - gl_Vertex.xyz;\n"
703 " EyeVector.x = dot(EyeVectorModelSpace, gl_MultiTexCoord1.xyz);\n"
704 " EyeVector.y = dot(EyeVectorModelSpace, gl_MultiTexCoord2.xyz);\n"
705 " EyeVector.z = dot(EyeVectorModelSpace, gl_MultiTexCoord3.xyz);\n"
707 "#ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
708 " VectorS = gl_MultiTexCoord1.xyz;\n"
709 " VectorT = gl_MultiTexCoord2.xyz;\n"
710 " VectorR = gl_MultiTexCoord3.xyz;\n"
713 "//#if defined(MODE_WATER) || defined(MODE_REFRACTION) || defined(USEREFLECTION)\n"
714 "// ModelViewProjectionPosition = gl_Vertex * gl_ModelViewProjectionMatrix;\n"
715 "// //ModelViewProjectionPosition_svector = (gl_Vertex + vec4(gl_MultiTexCoord1.xyz, 0)) * gl_ModelViewProjectionMatrix - ModelViewProjectionPosition;\n"
716 "// //ModelViewProjectionPosition_tvector = (gl_Vertex + vec4(gl_MultiTexCoord2.xyz, 0)) * gl_ModelViewProjectionMatrix - ModelViewProjectionPosition;\n"
719 "// transform vertex to camera space, using ftransform to match non-VS\n"
721 " gl_Position = ftransform();\n"
723 "#ifdef MODE_WATER\n"
724 " ModelViewProjectionPosition = gl_Position;\n"
726 "#ifdef MODE_REFRACTION\n"
727 " ModelViewProjectionPosition = gl_Position;\n"
729 "#ifdef USEREFLECTION\n"
730 " ModelViewProjectionPosition = gl_Position;\n"
734 "#endif // VERTEX_SHADER\n"
739 "// fragment shader specific:\n"
740 "#ifdef FRAGMENT_SHADER\n"
742 "// 13 textures, we can only use up to 16 on DX9-class hardware\n"
743 "uniform sampler2D Texture_Normal;\n"
744 "uniform sampler2D Texture_Color;\n"
745 "uniform sampler2D Texture_Gloss;\n"
746 "uniform sampler2D Texture_Glow;\n"
747 "uniform sampler2D Texture_SecondaryNormal;\n"
748 "uniform sampler2D Texture_SecondaryColor;\n"
749 "uniform sampler2D Texture_SecondaryGloss;\n"
750 "uniform sampler2D Texture_SecondaryGlow;\n"
751 "uniform sampler2D Texture_Pants;\n"
752 "uniform sampler2D Texture_Shirt;\n"
753 "uniform sampler2D Texture_FogMask;\n"
754 "uniform sampler2D Texture_Lightmap;\n"
755 "uniform sampler2D Texture_Deluxemap;\n"
756 "uniform sampler2D Texture_Refraction;\n"
757 "uniform sampler2D Texture_Reflection;\n"
758 "uniform sampler2D Texture_Attenuation;\n"
759 "uniform samplerCube Texture_Cube;\n"
761 "#define showshadowmap 0\n"
762 "#define useshadowsamplerrect 0\n"
763 "#define useshadowsampler2d 0\n"
764 "#define useshadowsamplercube 1\n"
766 "#ifdef USESHADOWMAPRECT\n"
767 "# if useshadowsamplerrect\n"
768 "uniform sampler2DRectShadow Texture_ShadowMapRect;\n"
770 "uniform sampler2DRect Texture_ShadowMapRect;\n"
774 "#ifdef USESHADOWMAP2D\n"
775 "# if useshadowsampler2d\n"
776 "uniform sampler2DShadow Texture_ShadowMap2D;\n"
778 "uniform sampler2D Texture_ShadowMap2D;\n"
782 "#ifdef USESHADOWMAPCUBE\n"
783 "# if useshadowsamplercube\n"
784 "uniform samplerCubeShadow Texture_ShadowMapCube;\n"
786 "uniform samplerCube Texture_ShadowMapCube;\n"
790 "uniform myhalf3 LightColor;\n"
791 "uniform myhalf3 AmbientColor;\n"
792 "uniform myhalf3 DiffuseColor;\n"
793 "uniform myhalf3 SpecularColor;\n"
794 "uniform myhalf3 Color_Pants;\n"
795 "uniform myhalf3 Color_Shirt;\n"
796 "uniform myhalf3 FogColor;\n"
798 "uniform myhalf4 TintColor;\n"
801 "//#ifdef MODE_WATER\n"
802 "uniform vec4 DistortScaleRefractReflect;\n"
803 "uniform vec4 ScreenScaleRefractReflect;\n"
804 "uniform vec4 ScreenCenterRefractReflect;\n"
805 "uniform myhalf4 RefractColor;\n"
806 "uniform myhalf4 ReflectColor;\n"
807 "uniform myhalf ReflectFactor;\n"
808 "uniform myhalf ReflectOffset;\n"
810 "//# ifdef MODE_REFRACTION\n"
811 "//uniform vec4 DistortScaleRefractReflect;\n"
812 "//uniform vec4 ScreenScaleRefractReflect;\n"
813 "//uniform vec4 ScreenCenterRefractReflect;\n"
814 "//uniform myhalf4 RefractColor;\n"
815 "//# ifdef USEREFLECTION\n"
816 "//uniform myhalf4 ReflectColor;\n"
819 "//# ifdef USEREFLECTION\n"
820 "//uniform vec4 DistortScaleRefractReflect;\n"
821 "//uniform vec4 ScreenScaleRefractReflect;\n"
822 "//uniform vec4 ScreenCenterRefractReflect;\n"
823 "//uniform myhalf4 ReflectColor;\n"
828 "uniform myhalf GlowScale;\n"
829 "uniform myhalf SceneBrightness;\n"
831 "uniform float OffsetMapping_Scale;\n"
832 "uniform float OffsetMapping_Bias;\n"
833 "uniform float FogRangeRecip;\n"
835 "uniform myhalf AmbientScale;\n"
836 "uniform myhalf DiffuseScale;\n"
837 "uniform myhalf SpecularScale;\n"
838 "uniform myhalf SpecularPower;\n"
840 "#ifdef USEOFFSETMAPPING\n"
841 "vec2 OffsetMapping(vec2 TexCoord)\n"
843 "#ifdef USEOFFSETMAPPING_RELIEFMAPPING\n"
844 " // 14 sample relief mapping: linear search and then binary search\n"
845 " // this basically steps forward a small amount repeatedly until it finds\n"
846 " // itself inside solid, then jitters forward and back using decreasing\n"
847 " // amounts to find the impact\n"
848 " //vec3 OffsetVector = vec3(EyeVector.xy * ((1.0 / EyeVector.z) * OffsetMapping_Scale) * vec2(-1, 1), -1);\n"
849 " //vec3 OffsetVector = vec3(normalize(EyeVector.xy) * OffsetMapping_Scale * vec2(-1, 1), -1);\n"
850 " vec3 OffsetVector = vec3(normalize(EyeVector).xy * OffsetMapping_Scale * vec2(-1, 1), -1);\n"
851 " vec3 RT = vec3(TexCoord, 1);\n"
852 " OffsetVector *= 0.1;\n"
853 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
854 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
855 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
856 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
857 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
858 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
859 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
860 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
861 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
862 " RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) - 0.5);\n"
863 " RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) * 0.5 - 0.25);\n"
864 " RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) * 0.25 - 0.125);\n"
865 " RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) * 0.125 - 0.0625);\n"
866 " RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) * 0.0625 - 0.03125);\n"
869 " // 3 sample offset mapping (only 3 samples because of ATI Radeon 9500-9800/X300 limits)\n"
870 " // this basically moves forward the full distance, and then backs up based\n"
871 " // on height of samples\n"
872 " //vec2 OffsetVector = vec2(EyeVector.xy * ((1.0 / EyeVector.z) * OffsetMapping_Scale) * vec2(-1, 1));\n"
873 " //vec2 OffsetVector = vec2(normalize(EyeVector.xy) * OffsetMapping_Scale * vec2(-1, 1));\n"
874 " vec2 OffsetVector = vec2(normalize(EyeVector).xy * OffsetMapping_Scale * vec2(-1, 1));\n"
875 " TexCoord += OffsetVector;\n"
876 " OffsetVector *= 0.333;\n"
877 " TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
878 " TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
879 " TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
880 " return TexCoord;\n"
883 "#endif // USEOFFSETMAPPING\n"
885 "#if defined(USESHADOWMAPRECT) || defined(USESHADOWMAP2D) || defined(USESHADOWMAPCUBE)\n"
886 "//float ShadowMap_TextureSize = 1024.0;\n"
887 "//float ShadowMap_BorderSize = 6.0;\n"
888 "//float ShadowMap_NearClip = 0.0001;\n"
889 "//float ShadowMap_FarClip = 1.0;\n"
890 "//float ShadowMap_Bias = ShadowMap_NearClip * 64.0 / ShadowMap_TextureSize;\n"
891 "//vec2 ShadowMap_TextureScale = vec2(0.5, 0.25);\n"
892 "//vec4 ShadowMap_Parameters = vec3(1.0 - ShadowMap_BorderSize / ShadowMap_TextureSize, 1.0 - ShadowMap_BorderSize / ShadowMap_TextureSize, -(ShadowMap_FarClip + ShadowMap_NearClip) / (ShadowMap_FarClip - ShadowMap_NearClip), -2.0 * ShadowMap_NearClip * ShadowMap_FarClip / (ShadowMap_FarClip - ShadowMap_NearClip));\n"
893 "uniform float ShadowMap_Bias;\n"
894 "uniform vec2 ShadowMap_TextureScale;\n"
895 "uniform vec4 ShadowMap_Parameters;\n"
898 "#if defined(USESHADOWMAPRECT) || defined(USESHADOWMAP2D)\n"
899 "vec3 GetShadowMapTC2D(vec3 dir)\n"
901 " vec3 adir = abs(dir);\n"
906 " if (adir.x > adir.y)\n"
908 " if (adir.x > adir.z)\n"
910 " d = 0.5 / adir.x;\n"
911 " if (dir.x >= 0.0)\n"
914 " tc = vec3(-dir.z, -dir.y, -dir.x);\n"
915 " offset = vec3(0.5, 0.5, 0.5);\n"
920 " tc = vec3( dir.z, -dir.y, dir.x);\n"
921 " offset = vec3(1.5, 0.5, 0.5);\n"
926 " d = 0.5 / adir.z;\n"
927 " if (dir.z >= 0.0)\n"
930 " tc = vec3( dir.x, -dir.y, -dir.z);\n"
931 " offset = vec3(0.5, 2.5, 0.5);\n"
936 " tc = vec3(-dir.x, -dir.y, dir.z);\n"
937 " offset = vec3(1.5, 2.5, 0.5);\n"
943 " if (adir.y > adir.z)\n"
945 " d = 0.5 / adir.y;\n"
946 " if (dir.y >= 0.0)\n"
949 " tc = vec3( dir.x, dir.z, -dir.y);\n"
950 " offset = vec3(0.5, 1.5, 0.5);\n"
955 " tc = vec3( dir.x, -dir.z, dir.y);\n"
956 " offset = vec3(1.5, 1.5, 0.5);\n"
961 " d = 0.5 / adir.z;\n"
962 " if (dir.z >= 0.0)\n"
965 " tc = vec3(dir.x, -dir.y, -dir.z);\n"
966 " offset = vec3(0.5, 2.5, 0.5);\n"
971 " tc = vec3(-dir.x, -dir.y, dir.z);\n"
972 " offset = vec3(1.5, 2.5, 0.5);\n"
976 " tc = tc * ShadowMap_Parameters.xyz * d + offset;\n"
977 " tc.xy *= ShadowMap_TextureScale;\n"
978 " tc.z += ShadowMap_Parameters.w * d - ShadowMap_Bias * d;\n"
980 " // experimental method by eihrul, needs overhaul\n"
981 " vec3 ma = vec3(0.0, 0.0, 1.0);\n"
982 " if (adir.x > adir.y)\n"
984 " if (adir.x > adir.z)\n"
985 " ma = vec3(1.0, 0.0, 0.0);\n"
987 " else if (adir.y > adir.z)\n"
988 " ma = vec3(0.0, 1.0, 0.0);\n"
990 " tc.xy = dir.xy - ma.xy*(dir.xy - dir.z);\n"
991 " tc.xy = (tc.xy/dot(ma, dir))*0.5 + 0.5;\n"
992 " tc.z = dot(ma, adir);\n"
993 " tc.xy = (tc.xy * tcscale + offset) * vec2(0.5, 0.25);\n"
998 "#endif // defined(USESHADOWMAPRECT) || defined(USESHADOWMAP2D)\n"
1000 "#ifdef USESHADOWMAPCUBE\n"
1001 "vec4 GetShadowMapTCCube(vec3 dir)\n"
1003 " vec3 adir = abs(dir);\n"
1004 " float sidedist = max(adir.x, max(adir.y, adir.z));\n"
1005 " return vec4(dir, 0.5 - 0.5 * (ShadowMap_Parameters.z - (-ShadowMap_Bias + ShadowMap_Parameters.w) / sidedist));\n"
1009 "#if !showshadowmap\n"
1010 "# ifdef USESHADOWMAPRECT\n"
1011 "float ShadowMapCompare(vec3 dir)\n"
1013 " vec3 shadowmaptc = GetShadowMapTC2D(dir);\n"
1015 "# if useshadowsamplerrect\n"
1016 " f = shadow2DRect(Texture_ShadowMapRect, shadowmaptc).a;\n"
1018 " f = step(shadowmaptc.z, texture2DRect(Texture_ShadowMapRect, shadowmaptc.xy).r);\n"
1024 "# ifdef USESHADOWMAP2D\n"
1025 "float ShadowMapCompare(vec3 dir)\n"
1027 " vec3 shadowmaptc = GetShadowMapTC2D(dir);\n"
1029 "# if useshadowsampler2d\n"
1030 " f = shadow2D(Texture_ShadowMap2D, shadowmaptc).a;\n"
1032 " f = step(shadowmaptc.z, texture2D(Texture_ShadowMap2D, shadowmaptc.xy).r);\n"
1038 "# ifdef USESHADOWMAPCUBE\n"
1039 "float ShadowMapCompare(vec3 dir)\n"
1041 " // apply depth texture cubemap as light filter\n"
1042 " vec4 shadowmaptc = GetShadowMapTCCube(dir);\n"
1044 "# if useshadowsamplercube\n"
1045 " f = shadowCube(Texture_ShadowMapCube, shadowmaptc).a;\n"
1047 " f = step(shadowmaptc.w, textureCube(Texture_ShadowMapCube, shadowmaptc.xyz).r);\n"
1055 "#ifdef MODE_WATER\n"
1060 "#ifdef USEOFFSETMAPPING\n"
1061 " // apply offsetmapping\n"
1062 " vec2 TexCoordOffset = OffsetMapping(TexCoord);\n"
1063 "#define TexCoord TexCoordOffset\n"
1066 " vec4 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect * (1.0 / ModelViewProjectionPosition.w);\n"
1067 " //vec4 ScreenTexCoord = (ModelViewProjectionPosition.xyxy + normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
1068 " vec4 SafeScreenTexCoord = ModelViewProjectionPosition.xyxy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
1069 " vec4 ScreenTexCoord = SafeScreenTexCoord + vec2(normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5))).xyxy * DistortScaleRefractReflect;\n"
1070 " // FIXME temporary hack to detect the case that the reflection\n"
1071 " // gets blackened at edges due to leaving the area that contains actual\n"
1073 " // Remove this 'ack once we have a better way to stop this thing from\n"
1075 " float f = min(1, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(0.05, 0.05))) / 0.02);\n"
1076 " f *= min(1, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(0.05, -0.05))) / 0.02);\n"
1077 " f *= min(1, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(-0.05, 0.05))) / 0.02);\n"
1078 " f *= min(1, length(texture2D(Texture_Refraction, ScreenTexCoord.xy + vec2(-0.05, -0.05))) / 0.02);\n"
1079 " ScreenTexCoord.xy = mix(SafeScreenTexCoord.xy, ScreenTexCoord.xy, f);\n"
1080 " f = min(1, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(0.05, 0.05))) / 0.02);\n"
1081 " f *= min(1, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(0.05, -0.05))) / 0.02);\n"
1082 " f *= min(1, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(-0.05, 0.05))) / 0.02);\n"
1083 " f *= min(1, length(texture2D(Texture_Reflection, ScreenTexCoord.zw + vec2(-0.05, -0.05))) / 0.02);\n"
1084 " ScreenTexCoord.zw = mix(SafeScreenTexCoord.zw, ScreenTexCoord.zw, f);\n"
1085 " // END OF UGLY UGLY UGLY HACK\n"
1086 " float Fresnel = pow(min(1.0, 1.0 - float(normalize(EyeVector).z)), 2.0) * ReflectFactor + ReflectOffset;\n"
1087 " gl_FragColor = mix(texture2D(Texture_Refraction, ScreenTexCoord.xy) * RefractColor, texture2D(Texture_Reflection, ScreenTexCoord.zw) * ReflectColor, Fresnel);\n"
1090 "#else // !MODE_WATER\n"
1091 "#ifdef MODE_REFRACTION\n"
1093 "// refraction pass\n"
1096 "#ifdef USEOFFSETMAPPING\n"
1097 " // apply offsetmapping\n"
1098 " vec2 TexCoordOffset = OffsetMapping(TexCoord);\n"
1099 "#define TexCoord TexCoordOffset\n"
1102 " vec2 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect.xy * (1.0 / ModelViewProjectionPosition.w);\n"
1103 " //vec2 ScreenTexCoord = (ModelViewProjectionPosition.xy + normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5)).xy * DistortScaleRefractReflect.xy * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy;\n"
1104 " vec2 ScreenTexCoord = ModelViewProjectionPosition.xy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy + vec2(normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5))).xy * DistortScaleRefractReflect.xy;\n"
1105 " gl_FragColor = texture2D(Texture_Refraction, ScreenTexCoord) * RefractColor;\n"
1108 "#else // !MODE_REFRACTION\n"
1111 "#ifdef USEOFFSETMAPPING\n"
1112 " // apply offsetmapping\n"
1113 " vec2 TexCoordOffset = OffsetMapping(TexCoord);\n"
1114 "#define TexCoord TexCoordOffset\n"
1117 " // combine the diffuse textures (base, pants, shirt)\n"
1118 " myhalf4 color = myhalf4(texture2D(Texture_Color, TexCoord));\n"
1119 "#ifdef USECOLORMAPPING\n"
1120 " color.rgb += myhalf3(texture2D(Texture_Pants, TexCoord)) * Color_Pants + myhalf3(texture2D(Texture_Shirt, TexCoord)) * Color_Shirt;\n"
1122 "#ifdef USEVERTEXTEXTUREBLEND\n"
1123 " myhalf terrainblend = clamp(myhalf(gl_Color.a) * color.a * 2.0 - 0.5, myhalf(0.0), myhalf(1.0));\n"
1124 " //myhalf terrainblend = min(myhalf(gl_Color.a) * color.a * 2.0, myhalf(1.0));\n"
1125 " //myhalf terrainblend = myhalf(gl_Color.a) * color.a > 0.5;\n"
1126 " color.rgb = mix(myhalf3(texture2D(Texture_SecondaryColor, TexCoord2)), color.rgb, terrainblend);\n"
1128 " //color = mix(myhalf4(1, 0, 0, 1), color, terrainblend);\n"
1131 "#ifdef USEDIFFUSE\n"
1132 " // get the surface normal and the gloss color\n"
1133 "# ifdef USEVERTEXTEXTUREBLEND\n"
1134 " myhalf3 surfacenormal = normalize(mix(myhalf3(texture2D(Texture_SecondaryNormal, TexCoord2)), myhalf3(texture2D(Texture_Normal, TexCoord)), terrainblend) - myhalf3(0.5, 0.5, 0.5));\n"
1135 "# ifdef USESPECULAR\n"
1136 " myhalf3 glosscolor = mix(myhalf3(texture2D(Texture_SecondaryGloss, TexCoord2)), myhalf3(texture2D(Texture_Gloss, TexCoord)), terrainblend);\n"
1139 " myhalf3 surfacenormal = normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5, 0.5, 0.5));\n"
1140 "# ifdef USESPECULAR\n"
1141 " myhalf3 glosscolor = myhalf3(texture2D(Texture_Gloss, TexCoord));\n"
1148 "#ifdef MODE_LIGHTSOURCE\n"
1149 " // light source\n"
1151 " // calculate surface normal, light normal, and specular normal\n"
1152 " // compute color intensity for the two textures (colormap and glossmap)\n"
1153 " // scale by light color and attenuation as efficiently as possible\n"
1154 " // (do as much scalar math as possible rather than vector math)\n"
1155 "# ifdef USEDIFFUSE\n"
1156 " // get the light normal\n"
1157 " myhalf3 diffusenormal = myhalf3(normalize(LightVector));\n"
1159 "# ifdef USESPECULAR\n"
1160 "# ifndef USEEXACTSPECULARMATH\n"
1161 " myhalf3 specularnormal = normalize(diffusenormal + myhalf3(normalize(EyeVector)));\n"
1164 " // calculate directional shading\n"
1165 "# ifdef USEEXACTSPECULARMATH\n"
1166 " color.rgb = myhalf(texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0))) * (color.rgb * (AmbientScale + DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0))) + (SpecularScale * pow(myhalf(max(float(dot(reflect(diffusenormal, surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower)) * glosscolor);\n"
1168 " color.rgb = myhalf(texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0))) * (color.rgb * (AmbientScale + DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0))) + (SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower)) * glosscolor);\n"
1171 "# ifdef USEDIFFUSE\n"
1172 " // calculate directional shading\n"
1173 " color.rgb = color.rgb * (myhalf(texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0))) * (AmbientScale + DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0))));\n"
1175 " // calculate directionless shading\n"
1176 " color.rgb = color.rgb * myhalf(texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0)));\n"
1180 "#if defined(USESHADOWMAPRECT) || defined(USESHADOWMAPCUBE) || defined(USESHADOWMAP2D)\n"
1181 "#if !showshadowmap\n"
1182 " color.rgb *= ShadowMapCompare(CubeVector);\n"
1186 "# ifdef USECUBEFILTER\n"
1187 " // apply light cubemap filter\n"
1188 " //color.rgb *= normalize(CubeVector) * 0.5 + 0.5;//vec3(textureCube(Texture_Cube, CubeVector));\n"
1189 " color.rgb *= myhalf3(textureCube(Texture_Cube, CubeVector));\n"
1191 "#endif // MODE_LIGHTSOURCE\n"
1196 "#ifdef MODE_LIGHTDIRECTION\n"
1197 " // directional model lighting\n"
1198 "# ifdef USEDIFFUSE\n"
1199 " // get the light normal\n"
1200 " myhalf3 diffusenormal = myhalf3(normalize(LightVector));\n"
1202 "# ifdef USESPECULAR\n"
1203 " // calculate directional shading\n"
1204 " color.rgb *= AmbientColor + DiffuseColor * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0));\n"
1205 "# ifdef USEEXACTSPECULARMATH\n"
1206 " color.rgb += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularColor * pow(myhalf(max(float(dot(reflect(diffusenormal, surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower);\n"
1208 " myhalf3 specularnormal = normalize(diffusenormal + myhalf3(normalize(EyeVector)));\n"
1209 " color.rgb += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularColor * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
1212 "# ifdef USEDIFFUSE\n"
1214 " // calculate directional shading\n"
1215 " color.rgb *= AmbientColor + DiffuseColor * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0));\n"
1217 " color.rgb *= AmbientColor;\n"
1220 "#endif // MODE_LIGHTDIRECTION\n"
1225 "#ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
1226 " // deluxemap lightmapping using light vectors in modelspace (evil q3map2)\n"
1228 " // get the light normal\n"
1229 " myhalf3 diffusenormal_modelspace = myhalf3(texture2D(Texture_Deluxemap, TexCoordLightmap)) * 2.0 + myhalf3(-1.0, -1.0, -1.0);\n"
1230 " myhalf3 diffusenormal;\n"
1231 " diffusenormal.x = dot(diffusenormal_modelspace, myhalf3(VectorS));\n"
1232 " diffusenormal.y = dot(diffusenormal_modelspace, myhalf3(VectorT));\n"
1233 " diffusenormal.z = dot(diffusenormal_modelspace, myhalf3(VectorR));\n"
1234 " // calculate directional shading (and undoing the existing angle attenuation on the lightmap by the division)\n"
1235 " // note that q3map2 is too stupid to calculate proper surface normals when q3map_nonplanar\n"
1236 " // is used (the lightmap and deluxemap coords correspond to virtually random coordinates\n"
1237 " // on that luxel, and NOT to its center, because recursive triangle subdivision is used\n"
1238 " // to map the luxels to coordinates on the draw surfaces), which also causes\n"
1239 " // deluxemaps to be wrong because light contributions from the wrong side of the surface\n"
1240 " // are added up. To prevent divisions by zero or strong exaggerations, a max()\n"
1241 " // nudge is done here at expense of some additional fps. This is ONLY needed for\n"
1242 " // deluxemaps, tangentspace deluxemap avoid this problem by design.\n"
1243 " myhalf3 tempcolor = color.rgb * (DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal) / max(0.25, diffusenormal.z)), 0.0)));\n"
1244 " // 0.25 supports up to 75.5 degrees normal/deluxe angle\n"
1245 "# ifdef USESPECULAR\n"
1246 "# ifdef USEEXACTSPECULARMATH\n"
1247 " tempcolor += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(reflect(normalize(diffusenormal), surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower);\n"
1249 " myhalf3 specularnormal = myhalf3(normalize(diffusenormal + myhalf3(normalize(EyeVector))));\n"
1250 " tempcolor += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
1254 " // apply lightmap color\n"
1255 " color.rgb = color.rgb * AmbientScale + tempcolor * myhalf3(texture2D(Texture_Lightmap, TexCoordLightmap));\n"
1256 "#endif // MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
1261 "#ifdef MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n"
1262 " // deluxemap lightmapping using light vectors in tangentspace (hmap2 -light)\n"
1264 " // get the light normal\n"
1265 " myhalf3 diffusenormal = myhalf3(texture2D(Texture_Deluxemap, TexCoordLightmap)) * 2.0 + myhalf3(-1.0, -1.0, -1.0);\n"
1266 " // calculate directional shading (and undoing the existing angle attenuation on the lightmap by the division)\n"
1267 " myhalf3 tempcolor = color.rgb * (DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal) / diffusenormal.z), 0.0)));\n"
1268 "# ifdef USESPECULAR\n"
1269 "# ifdef USEEXACTSPECULARMATH\n"
1270 " tempcolor += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(reflect(diffusenormal, surfacenormal), normalize(EyeVector)))*-1.0, 0.0)), SpecularPower);\n"
1272 " myhalf3 specularnormal = myhalf3(normalize(diffusenormal + myhalf3(normalize(EyeVector))));\n"
1273 " tempcolor += myhalf3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
1277 " // apply lightmap color\n"
1278 " color.rgb = color.rgb * AmbientScale + tempcolor * myhalf3(texture2D(Texture_Lightmap, TexCoordLightmap));\n"
1279 "#endif // MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n"
1284 "#ifdef MODE_LIGHTMAP\n"
1285 " // apply lightmap color\n"
1286 " color.rgb = color.rgb * myhalf3(texture2D(Texture_Lightmap, TexCoordLightmap)) * DiffuseScale + color.rgb * AmbientScale;\n"
1287 "#endif // MODE_LIGHTMAP\n"
1292 "#ifdef MODE_VERTEXCOLOR\n"
1293 " // apply lightmap color\n"
1294 " color.rgb = color.rgb * myhalf3(gl_Color.rgb) * DiffuseScale + color.rgb * AmbientScale;\n"
1295 "#endif // MODE_VERTEXCOLOR\n"
1300 "#ifdef MODE_FLATCOLOR\n"
1301 "#endif // MODE_FLATCOLOR\n"
1309 " color *= TintColor;\n"
1312 "#ifdef USEVERTEXTEXTUREBLEND\n"
1313 " color.rgb += mix(myhalf3(texture2D(Texture_SecondaryGlow, TexCoord2)), myhalf3(texture2D(Texture_Glow, TexCoord)), terrainblend);\n"
1315 " color.rgb += myhalf3(texture2D(Texture_Glow, TexCoord)) * GlowScale;\n"
1319 " color.rgb *= SceneBrightness;\n"
1321 " // apply fog after Contrastboost/SceneBrightness because its color is already modified appropriately\n"
1323 " color.rgb = mix(FogColor, color.rgb, myhalf(texture2D(Texture_FogMask, myhalf2(length(EyeVectorModelSpace)*FogRangeRecip, 0.0))));\n"
1326 " // reflection must come last because it already contains exactly the correct fog (the reflection render preserves camera distance from the plane, it only flips the side) and ContrastBoost/SceneBrightness\n"
1327 "#ifdef USEREFLECTION\n"
1328 " vec4 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect * (1.0 / ModelViewProjectionPosition.w);\n"
1329 " //vec4 ScreenTexCoord = (ModelViewProjectionPosition.xyxy + normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
1330 " vec4 ScreenTexCoord = ModelViewProjectionPosition.xyxy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect + vec3(normalize(myhalf3(texture2D(Texture_Normal, TexCoord)) - myhalf3(0.5))).xyxy * DistortScaleRefractReflect;\n"
1331 " color.rgb = mix(color.rgb, myhalf3(texture2D(Texture_Reflection, ScreenTexCoord.zw)) * ReflectColor.rgb, ReflectColor.a);\n"
1334 " gl_FragColor = vec4(color);\n"
1336 "#if showshadowmap\n"
1337 "# ifdef USESHADOWMAPRECT\n"
1338 "# if useshadowsamplerrect\n"
1339 " gl_FragColor = shadow2DRect(Texture_ShadowMapRect, GetShadowMapTC2D(CubeVector).xyz);\n"
1341 " gl_FragColor = texture2DRect(Texture_ShadowMapRect, GetShadowMapTC2D(CubeVector).xy);\n"
1345 "# ifdef USESHADOWMAP2D\n"
1346 "# if useshadowsampler2d\n"
1347 " gl_FragColor = shadow2D(Texture_ShadowMap2D, GetShadowMapTC2D(CubeVector).xyz);\n"
1349 " gl_FragColor = texture2D(Texture_ShadowMap2D, GetShadowMapTC2D(CubeVector).xy);\n"
1353 "# ifdef USESHADOWMAPCUBE\n"
1354 "# if useshadowsamplercube\n"
1355 " gl_FragColor = shadowCube(Texture_ShadowMapCube, GetShadowMapTCCube(CubeVector));\n"
1357 " gl_FragColor = textureCube(Texture_ShadowMapCube, GetShadowMapTCCube(CubeVector).xyz);\n"
1362 "#endif // !MODE_REFRACTION\n"
1363 "#endif // !MODE_WATER\n"
1365 "#endif // FRAGMENT_SHADER\n"
1367 "#endif // !MODE_GENERIC\n"
1368 "#endif // !MODE_POSTPROCESS\n"
1369 "#endif // !MODE_SHOWDEPTH\n"
1370 "#endif // !MODE_DEPTH_OR_SHADOW\n"
1373 typedef struct shaderpermutationinfo_s
1375 const char *pretext;
1378 shaderpermutationinfo_t;
1380 typedef struct shadermodeinfo_s
1382 const char *vertexfilename;
1383 const char *geometryfilename;
1384 const char *fragmentfilename;
1385 const char *pretext;
1390 typedef enum shaderpermutation_e
1392 SHADERPERMUTATION_DIFFUSE = 1<<0, ///< (lightsource) whether to use directional shading
1393 SHADERPERMUTATION_VERTEXTEXTUREBLEND = 1<<1, ///< indicates this is a two-layer material blend based on vertex alpha (q3bsp)
1394 SHADERPERMUTATION_VIEWTINT = 1<<1, ///< view tint (postprocessing only)
1395 SHADERPERMUTATION_COLORMAPPING = 1<<2, ///< indicates this is a colormapped skin
1396 SHADERPERMUTATION_SATURATION = 1<<2, ///< saturation (postprocessing only)
1397 SHADERPERMUTATION_FOG = 1<<3, ///< tint the color by fog color or black if using additive blend mode
1398 SHADERPERMUTATION_GAMMARAMPS = 1<<3, ///< gamma (postprocessing only)
1399 SHADERPERMUTATION_CUBEFILTER = 1<<4, ///< (lightsource) use cubemap light filter
1400 SHADERPERMUTATION_GLOW = 1<<5, ///< (lightmap) blend in an additive glow texture
1401 SHADERPERMUTATION_BLOOM = 1<<5, ///< bloom (postprocessing only)
1402 SHADERPERMUTATION_SPECULAR = 1<<6, ///< (lightsource or deluxemapping) render specular effects
1403 SHADERPERMUTATION_POSTPROCESSING = 1<<6, ///< user defined postprocessing (postprocessing only)
1404 SHADERPERMUTATION_EXACTSPECULARMATH = 1<<7, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
1405 SHADERPERMUTATION_REFLECTION = 1<<8, ///< normalmap-perturbed reflection of the scene infront of the surface, preformed as an overlay on the surface
1406 SHADERPERMUTATION_OFFSETMAPPING = 1<<9, ///< adjust texcoords to roughly simulate a displacement mapped surface
1407 SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING = 1<<10, ///< adjust texcoords to accurately simulate a displacement mapped surface (requires OFFSETMAPPING to also be set!)
1408 SHADERPERMUTATION_SHADOWMAPRECT = 1<<11, ///< (lightsource) use shadowmap rectangle texture as light filter
1409 SHADERPERMUTATION_SHADOWMAPCUBE = 1<<12, ///< (lightsource) use shadowmap cubemap texture as light filter
1410 SHADERPERMUTATION_SHADOWMAP2D = 1<<13, ///< (lightsource) use shadowmap rectangle texture as light filter
1411 SHADERPERMUTATION_LIMIT = 1<<14, ///< size of permutations array
1412 SHADERPERMUTATION_COUNT = 14 ///< size of shaderpermutationinfo array
1414 shaderpermutation_t;
1416 // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
1417 shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
1419 {"#define USEDIFFUSE\n", " diffuse"},
1420 {"#define USEVERTEXTEXTUREBLEND\n#define USEVIEWTINT\n", " vertextextureblend/tint"},
1421 {"#define USECOLORMAPPING\n#define USESATURATION\n", " colormapping/saturation"},
1422 {"#define USEFOG\n#define USEGAMMARAMPS\n", " fog/gammaramps"},
1423 {"#define USECUBEFILTER\n", " cubefilter"},
1424 {"#define USEGLOW\n#define USEBLOOM\n", " glow/bloom"},
1425 {"#define USESPECULAR\n#define USEPOSTPROCESSING", " specular/postprocessing"},
1426 {"#define USEEXACTSPECULARMATH\n", " exactspecularmath"},
1427 {"#define USEREFLECTION\n", " reflection"},
1428 {"#define USEOFFSETMAPPING\n", " offsetmapping"},
1429 {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
1430 {"#define USESHADOWMAPRECT\n", " shadowmaprect"},
1431 {"#define USESHADOWMAPCUBE\n", " shadowmapcube"},
1432 {"#define USESHADOWMAP2D\n", " shadowmap2d"},
1435 /// this enum is multiplied by SHADERPERMUTATION_MODEBASE
1436 typedef enum shadermode_e
1438 SHADERMODE_GENERIC, ///< (particles/HUD/etc) vertex color, optionally multiplied by one texture
1439 SHADERMODE_POSTPROCESS, ///< postprocessing shader (r_glsl_postprocess)
1440 SHADERMODE_DEPTH_OR_SHADOW, ///< (depthfirst/shadows) vertex shader only
1441 SHADERMODE_FLATCOLOR, ///< (lightmap) modulate texture by uniform color (q1bsp, q3bsp)
1442 SHADERMODE_VERTEXCOLOR, ///< (lightmap) modulate texture by vertex colors (q3bsp)
1443 SHADERMODE_LIGHTMAP, ///< (lightmap) modulate texture by lightmap texture (q1bsp, q3bsp)
1444 SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE, ///< (lightmap) use directional pixel shading from texture containing modelspace light directions (q3bsp deluxemap)
1445 SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE, ///< (lightmap) use directional pixel shading from texture containing tangentspace light directions (q1bsp deluxemap)
1446 SHADERMODE_LIGHTDIRECTION, ///< (lightmap) use directional pixel shading from fixed light direction (q3bsp)
1447 SHADERMODE_LIGHTSOURCE, ///< (lightsource) use directional pixel shading from light source (rtlight)
1448 SHADERMODE_REFRACTION, ///< refract background (the material is rendered normally after this pass)
1449 SHADERMODE_WATER, ///< refract background and reflection (the material is rendered normally after this pass)
1450 SHADERMODE_SHOWDEPTH, ///< (debugging) renders depth as color
1455 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
1456 shadermodeinfo_t shadermodeinfo[SHADERMODE_COUNT] =
1458 {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_GENERIC\n", " generic"},
1459 {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_POSTPROCESS\n", " postprocess"},
1460 {"glsl/default.glsl", NULL, NULL , "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
1461 {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_FLATCOLOR\n", " flatcolor"},
1462 {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
1463 {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTMAP\n", " lightmap"},
1464 {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
1465 {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
1466 {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
1467 {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_LIGHTSOURCE\n", " lightsource"},
1468 {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_REFRACTION\n", " refraction"},
1469 {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_WATER\n", " water"},
1470 {"glsl/default.glsl", NULL, "glsl/default.glsl", "#define MODE_SHOWDEPTH\n", " showdepth"},
1473 typedef struct r_glsl_permutation_s
1475 /// indicates if we have tried compiling this permutation already
1477 /// 0 if compilation failed
1479 /// locations of detected uniforms in program object, or -1 if not found
1480 int loc_Texture_First;
1481 int loc_Texture_Second;
1482 int loc_Texture_GammaRamps;
1483 int loc_Texture_Normal;
1484 int loc_Texture_Color;
1485 int loc_Texture_Gloss;
1486 int loc_Texture_Glow;
1487 int loc_Texture_SecondaryNormal;
1488 int loc_Texture_SecondaryColor;
1489 int loc_Texture_SecondaryGloss;
1490 int loc_Texture_SecondaryGlow;
1491 int loc_Texture_Pants;
1492 int loc_Texture_Shirt;
1493 int loc_Texture_FogMask;
1494 int loc_Texture_Lightmap;
1495 int loc_Texture_Deluxemap;
1496 int loc_Texture_Attenuation;
1497 int loc_Texture_Cube;
1498 int loc_Texture_Refraction;
1499 int loc_Texture_Reflection;
1500 int loc_Texture_ShadowMapRect;
1501 int loc_Texture_ShadowMapCube;
1502 int loc_Texture_ShadowMap2D;
1504 int loc_LightPosition;
1505 int loc_EyePosition;
1506 int loc_Color_Pants;
1507 int loc_Color_Shirt;
1508 int loc_FogRangeRecip;
1509 int loc_AmbientScale;
1510 int loc_DiffuseScale;
1511 int loc_SpecularScale;
1512 int loc_SpecularPower;
1514 int loc_SceneBrightness; // or: Scenebrightness * ContrastBoost
1515 int loc_OffsetMapping_Scale;
1517 int loc_AmbientColor;
1518 int loc_DiffuseColor;
1519 int loc_SpecularColor;
1521 int loc_ContrastBoostCoeff; ///< 1 - 1/ContrastBoost
1522 int loc_GammaCoeff; ///< 1 / gamma
1523 int loc_DistortScaleRefractReflect;
1524 int loc_ScreenScaleRefractReflect;
1525 int loc_ScreenCenterRefractReflect;
1526 int loc_RefractColor;
1527 int loc_ReflectColor;
1528 int loc_ReflectFactor;
1529 int loc_ReflectOffset;
1537 int loc_ShadowMap_Bias;
1538 int loc_ShadowMap_TextureScale;
1539 int loc_ShadowMap_Parameters;
1541 r_glsl_permutation_t;
1543 /// information about each possible shader permutation
1544 r_glsl_permutation_t r_glsl_permutations[SHADERMODE_COUNT][SHADERPERMUTATION_LIMIT];
1545 /// currently selected permutation
1546 r_glsl_permutation_t *r_glsl_permutation;
1548 static char *R_GLSL_GetText(const char *filename, qboolean printfromdisknotice)
1551 if (!filename || !filename[0])
1553 shaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL);
1556 if (printfromdisknotice)
1557 Con_DPrint("from disk... ");
1558 return shaderstring;
1560 else if (!strcmp(filename, "glsl/default.glsl"))
1562 shaderstring = (char *) Mem_Alloc(r_main_mempool, strlen(builtinshaderstring) + 1);
1563 memcpy(shaderstring, builtinshaderstring, strlen(builtinshaderstring) + 1);
1565 return shaderstring;
1568 static void R_GLSL_CompilePermutation(unsigned int mode, unsigned int permutation)
1571 shadermodeinfo_t *modeinfo = shadermodeinfo + mode;
1572 r_glsl_permutation_t *p = &r_glsl_permutations[mode][permutation];
1573 int vertstrings_count = 0;
1574 int geomstrings_count = 0;
1575 int fragstrings_count = 0;
1576 char *vertexstring, *geometrystring, *fragmentstring;
1577 const char *vertstrings_list[32+3];
1578 const char *geomstrings_list[32+3];
1579 const char *fragstrings_list[32+3];
1580 char permutationname[256];
1587 permutationname[0] = 0;
1588 vertexstring = R_GLSL_GetText(modeinfo->vertexfilename, true);
1589 geometrystring = R_GLSL_GetText(modeinfo->geometryfilename, false);
1590 fragmentstring = R_GLSL_GetText(modeinfo->fragmentfilename, false);
1592 strlcat(permutationname, shadermodeinfo[mode].vertexfilename, sizeof(permutationname));
1594 // the first pretext is which type of shader to compile as
1595 // (later these will all be bound together as a program object)
1596 vertstrings_list[vertstrings_count++] = "#define VERTEX_SHADER\n";
1597 geomstrings_list[geomstrings_count++] = "#define GEOMETRY_SHADER\n";
1598 fragstrings_list[fragstrings_count++] = "#define FRAGMENT_SHADER\n";
1600 // the second pretext is the mode (for example a light source)
1601 vertstrings_list[vertstrings_count++] = shadermodeinfo[mode].pretext;
1602 geomstrings_list[geomstrings_count++] = shadermodeinfo[mode].pretext;
1603 fragstrings_list[fragstrings_count++] = shadermodeinfo[mode].pretext;
1604 strlcat(permutationname, modeinfo->name, sizeof(permutationname));
1606 // now add all the permutation pretexts
1607 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1609 if (permutation & (1<<i))
1611 vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i].pretext;
1612 geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i].pretext;
1613 fragstrings_list[fragstrings_count++] = shaderpermutationinfo[i].pretext;
1614 strlcat(permutationname, shaderpermutationinfo[i].name, sizeof(permutationname));
1618 // keep line numbers correct
1619 vertstrings_list[vertstrings_count++] = "\n";
1620 geomstrings_list[geomstrings_count++] = "\n";
1621 fragstrings_list[fragstrings_count++] = "\n";
1625 // now append the shader text itself
1626 vertstrings_list[vertstrings_count++] = vertexstring;
1627 geomstrings_list[geomstrings_count++] = geometrystring;
1628 fragstrings_list[fragstrings_count++] = fragmentstring;
1630 // if any sources were NULL, clear the respective list
1632 vertstrings_count = 0;
1633 if (!geometrystring)
1634 geomstrings_count = 0;
1635 if (!fragmentstring)
1636 fragstrings_count = 0;
1638 // compile the shader program
1639 if (vertstrings_count + geomstrings_count + fragstrings_count)
1640 p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
1644 qglUseProgramObjectARB(p->program);CHECKGLERROR
1645 // look up all the uniform variable names we care about, so we don't
1646 // have to look them up every time we set them
1647 p->loc_Texture_First = qglGetUniformLocationARB(p->program, "Texture_First");
1648 p->loc_Texture_Second = qglGetUniformLocationARB(p->program, "Texture_Second");
1649 p->loc_Texture_GammaRamps = qglGetUniformLocationARB(p->program, "Texture_GammaRamps");
1650 p->loc_Texture_Normal = qglGetUniformLocationARB(p->program, "Texture_Normal");
1651 p->loc_Texture_Color = qglGetUniformLocationARB(p->program, "Texture_Color");
1652 p->loc_Texture_Gloss = qglGetUniformLocationARB(p->program, "Texture_Gloss");
1653 p->loc_Texture_Glow = qglGetUniformLocationARB(p->program, "Texture_Glow");
1654 p->loc_Texture_SecondaryNormal = qglGetUniformLocationARB(p->program, "Texture_SecondaryNormal");
1655 p->loc_Texture_SecondaryColor = qglGetUniformLocationARB(p->program, "Texture_SecondaryColor");
1656 p->loc_Texture_SecondaryGloss = qglGetUniformLocationARB(p->program, "Texture_SecondaryGloss");
1657 p->loc_Texture_SecondaryGlow = qglGetUniformLocationARB(p->program, "Texture_SecondaryGlow");
1658 p->loc_Texture_FogMask = qglGetUniformLocationARB(p->program, "Texture_FogMask");
1659 p->loc_Texture_Pants = qglGetUniformLocationARB(p->program, "Texture_Pants");
1660 p->loc_Texture_Shirt = qglGetUniformLocationARB(p->program, "Texture_Shirt");
1661 p->loc_Texture_Lightmap = qglGetUniformLocationARB(p->program, "Texture_Lightmap");
1662 p->loc_Texture_Deluxemap = qglGetUniformLocationARB(p->program, "Texture_Deluxemap");
1663 p->loc_Texture_Refraction = qglGetUniformLocationARB(p->program, "Texture_Refraction");
1664 p->loc_Texture_Reflection = qglGetUniformLocationARB(p->program, "Texture_Reflection");
1665 p->loc_Texture_Attenuation = qglGetUniformLocationARB(p->program, "Texture_Attenuation");
1666 p->loc_Texture_Cube = qglGetUniformLocationARB(p->program, "Texture_Cube");
1667 p->loc_Texture_ShadowMapRect = qglGetUniformLocationARB(p->program, "Texture_ShadowMapRect");
1668 p->loc_Texture_ShadowMapCube = qglGetUniformLocationARB(p->program, "Texture_ShadowMapCube");
1669 p->loc_Texture_ShadowMap2D = qglGetUniformLocationARB(p->program, "Texture_ShadowMap2D");
1670 p->loc_FogColor = qglGetUniformLocationARB(p->program, "FogColor");
1671 p->loc_LightPosition = qglGetUniformLocationARB(p->program, "LightPosition");
1672 p->loc_EyePosition = qglGetUniformLocationARB(p->program, "EyePosition");
1673 p->loc_Color_Pants = qglGetUniformLocationARB(p->program, "Color_Pants");
1674 p->loc_Color_Shirt = qglGetUniformLocationARB(p->program, "Color_Shirt");
1675 p->loc_FogRangeRecip = qglGetUniformLocationARB(p->program, "FogRangeRecip");
1676 p->loc_AmbientScale = qglGetUniformLocationARB(p->program, "AmbientScale");
1677 p->loc_DiffuseScale = qglGetUniformLocationARB(p->program, "DiffuseScale");
1678 p->loc_SpecularPower = qglGetUniformLocationARB(p->program, "SpecularPower");
1679 p->loc_SpecularScale = qglGetUniformLocationARB(p->program, "SpecularScale");
1680 p->loc_GlowScale = qglGetUniformLocationARB(p->program, "GlowScale");
1681 p->loc_SceneBrightness = qglGetUniformLocationARB(p->program, "SceneBrightness");
1682 p->loc_OffsetMapping_Scale = qglGetUniformLocationARB(p->program, "OffsetMapping_Scale");
1683 p->loc_TintColor = qglGetUniformLocationARB(p->program, "TintColor");
1684 p->loc_AmbientColor = qglGetUniformLocationARB(p->program, "AmbientColor");
1685 p->loc_DiffuseColor = qglGetUniformLocationARB(p->program, "DiffuseColor");
1686 p->loc_SpecularColor = qglGetUniformLocationARB(p->program, "SpecularColor");
1687 p->loc_LightDir = qglGetUniformLocationARB(p->program, "LightDir");
1688 p->loc_ContrastBoostCoeff = qglGetUniformLocationARB(p->program, "ContrastBoostCoeff");
1689 p->loc_DistortScaleRefractReflect = qglGetUniformLocationARB(p->program, "DistortScaleRefractReflect");
1690 p->loc_ScreenScaleRefractReflect = qglGetUniformLocationARB(p->program, "ScreenScaleRefractReflect");
1691 p->loc_ScreenCenterRefractReflect = qglGetUniformLocationARB(p->program, "ScreenCenterRefractReflect");
1692 p->loc_RefractColor = qglGetUniformLocationARB(p->program, "RefractColor");
1693 p->loc_ReflectColor = qglGetUniformLocationARB(p->program, "ReflectColor");
1694 p->loc_ReflectFactor = qglGetUniformLocationARB(p->program, "ReflectFactor");
1695 p->loc_ReflectOffset = qglGetUniformLocationARB(p->program, "ReflectOffset");
1696 p->loc_GammaCoeff = qglGetUniformLocationARB(p->program, "GammaCoeff");
1697 p->loc_UserVec1 = qglGetUniformLocationARB(p->program, "UserVec1");
1698 p->loc_UserVec2 = qglGetUniformLocationARB(p->program, "UserVec2");
1699 p->loc_UserVec3 = qglGetUniformLocationARB(p->program, "UserVec3");
1700 p->loc_UserVec4 = qglGetUniformLocationARB(p->program, "UserVec4");
1701 p->loc_ClientTime = qglGetUniformLocationARB(p->program, "ClientTime");
1702 p->loc_PixelSize = qglGetUniformLocationARB(p->program, "PixelSize");
1703 p->loc_Saturation = qglGetUniformLocationARB(p->program, "Saturation");
1704 p->loc_ShadowMap_Bias = qglGetUniformLocationARB(p->program, "ShadowMap_Bias");
1705 p->loc_ShadowMap_TextureScale = qglGetUniformLocationARB(p->program, "ShadowMap_TextureScale");
1706 p->loc_ShadowMap_Parameters = qglGetUniformLocationARB(p->program, "ShadowMap_Parameters");
1707 // initialize the samplers to refer to the texture units we use
1708 if (p->loc_Texture_First >= 0) qglUniform1iARB(p->loc_Texture_First , GL20TU_FIRST);
1709 if (p->loc_Texture_Second >= 0) qglUniform1iARB(p->loc_Texture_Second , GL20TU_SECOND);
1710 if (p->loc_Texture_GammaRamps >= 0) qglUniform1iARB(p->loc_Texture_GammaRamps , GL20TU_GAMMARAMPS);
1711 if (p->loc_Texture_Normal >= 0) qglUniform1iARB(p->loc_Texture_Normal , GL20TU_NORMAL);
1712 if (p->loc_Texture_Color >= 0) qglUniform1iARB(p->loc_Texture_Color , GL20TU_COLOR);
1713 if (p->loc_Texture_Gloss >= 0) qglUniform1iARB(p->loc_Texture_Gloss , GL20TU_GLOSS);
1714 if (p->loc_Texture_Glow >= 0) qglUniform1iARB(p->loc_Texture_Glow , GL20TU_GLOW);
1715 if (p->loc_Texture_SecondaryNormal >= 0) qglUniform1iARB(p->loc_Texture_SecondaryNormal, GL20TU_SECONDARY_NORMAL);
1716 if (p->loc_Texture_SecondaryColor >= 0) qglUniform1iARB(p->loc_Texture_SecondaryColor , GL20TU_SECONDARY_COLOR);
1717 if (p->loc_Texture_SecondaryGloss >= 0) qglUniform1iARB(p->loc_Texture_SecondaryGloss , GL20TU_SECONDARY_GLOSS);
1718 if (p->loc_Texture_SecondaryGlow >= 0) qglUniform1iARB(p->loc_Texture_SecondaryGlow , GL20TU_SECONDARY_GLOW);
1719 if (p->loc_Texture_Pants >= 0) qglUniform1iARB(p->loc_Texture_Pants , GL20TU_PANTS);
1720 if (p->loc_Texture_Shirt >= 0) qglUniform1iARB(p->loc_Texture_Shirt , GL20TU_SHIRT);
1721 if (p->loc_Texture_FogMask >= 0) qglUniform1iARB(p->loc_Texture_FogMask , GL20TU_FOGMASK);
1722 if (p->loc_Texture_Lightmap >= 0) qglUniform1iARB(p->loc_Texture_Lightmap , GL20TU_LIGHTMAP);
1723 if (p->loc_Texture_Deluxemap >= 0) qglUniform1iARB(p->loc_Texture_Deluxemap , GL20TU_DELUXEMAP);
1724 if (p->loc_Texture_Attenuation >= 0) qglUniform1iARB(p->loc_Texture_Attenuation , GL20TU_ATTENUATION);
1725 if (p->loc_Texture_Cube >= 0) qglUniform1iARB(p->loc_Texture_Cube , GL20TU_CUBE);
1726 if (p->loc_Texture_Refraction >= 0) qglUniform1iARB(p->loc_Texture_Refraction , GL20TU_REFRACTION);
1727 if (p->loc_Texture_Reflection >= 0) qglUniform1iARB(p->loc_Texture_Reflection , GL20TU_REFLECTION);
1728 if (p->loc_Texture_ShadowMapRect >= 0) qglUniform1iARB(p->loc_Texture_ShadowMapRect , GL20TU_SHADOWMAPRECT);
1729 if (p->loc_Texture_ShadowMapCube >= 0) qglUniform1iARB(p->loc_Texture_ShadowMapCube , GL20TU_SHADOWMAPCUBE);
1730 if (p->loc_Texture_ShadowMap2D >= 0) qglUniform1iARB(p->loc_Texture_ShadowMap2D , GL20TU_SHADOWMAP2D);
1732 if (developer.integer)
1733 Con_Printf("GLSL shader %s compiled.\n", permutationname);
1736 Con_Printf("GLSL shader %s failed! some features may not work properly.\n", permutationname);
1740 Mem_Free(vertexstring);
1742 Mem_Free(geometrystring);
1744 Mem_Free(fragmentstring);
1747 void R_GLSL_Restart_f(void)
1750 unsigned int permutation;
1751 for (mode = 0;mode < SHADERMODE_COUNT;mode++)
1752 for (permutation = 0;permutation < SHADERPERMUTATION_LIMIT;permutation++)
1753 if (r_glsl_permutations[mode][permutation].program)
1754 GL_Backend_FreeProgram(r_glsl_permutations[mode][permutation].program);
1755 memset(r_glsl_permutations, 0, sizeof(r_glsl_permutations));
1758 void R_GLSL_DumpShader_f(void)
1762 qfile_t *file = FS_OpenRealFile("glsl/default.glsl", "w", false);
1765 Con_Printf("failed to write to glsl/default.glsl\n");
1769 FS_Print(file, "/* The engine may define the following macros:\n");
1770 FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
1771 for (i = 0;i < SHADERMODE_COUNT;i++)
1772 FS_Print(file, shadermodeinfo[i].pretext);
1773 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1774 FS_Print(file, shaderpermutationinfo[i].pretext);
1775 FS_Print(file, "*/\n");
1776 FS_Print(file, builtinshaderstring);
1779 Con_Printf("glsl/default.glsl written\n");
1782 void R_SetupShader_SetPermutation(unsigned int mode, unsigned int permutation)
1784 r_glsl_permutation_t *perm = &r_glsl_permutations[mode][permutation];
1785 if (r_glsl_permutation != perm)
1787 r_glsl_permutation = perm;
1788 if (!r_glsl_permutation->program)
1790 if (!r_glsl_permutation->compiled)
1791 R_GLSL_CompilePermutation(mode, permutation);
1792 if (!r_glsl_permutation->program)
1794 // remove features until we find a valid permutation
1796 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1798 // reduce i more quickly whenever it would not remove any bits
1799 int j = 1<<(SHADERPERMUTATION_COUNT-1-i);
1800 if (!(permutation & j))
1803 r_glsl_permutation = &r_glsl_permutations[mode][permutation];
1804 if (!r_glsl_permutation->compiled)
1805 R_GLSL_CompilePermutation(mode, permutation);
1806 if (r_glsl_permutation->program)
1809 if (i >= SHADERPERMUTATION_COUNT)
1811 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");
1812 Cvar_SetValueQuick(&r_glsl, 0);
1813 R_GLSL_Restart_f(); // unload shaders
1814 return; // no bit left to clear
1819 qglUseProgramObjectARB(r_glsl_permutation->program);CHECKGLERROR
1823 void R_SetupGenericShader(qboolean usetexture)
1825 if (gl_support_fragment_shader)
1827 if (r_glsl.integer && r_glsl_usegeneric.integer)
1828 R_SetupShader_SetPermutation(SHADERMODE_GENERIC, usetexture ? SHADERPERMUTATION_DIFFUSE : 0);
1829 else if (r_glsl_permutation)
1831 r_glsl_permutation = NULL;
1832 qglUseProgramObjectARB(0);CHECKGLERROR
1837 void R_SetupGenericTwoTextureShader(int texturemode)
1839 if (gl_support_fragment_shader)
1841 if (r_glsl.integer && r_glsl_usegeneric.integer)
1842 R_SetupShader_SetPermutation(SHADERMODE_GENERIC, SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_SPECULAR | (r_shadow_glossexact.integer ? SHADERPERMUTATION_EXACTSPECULARMATH : 0) | (texturemode == GL_MODULATE ? SHADERPERMUTATION_COLORMAPPING : (texturemode == GL_ADD ? SHADERPERMUTATION_GLOW : (texturemode == GL_DECAL ? SHADERPERMUTATION_VERTEXTEXTUREBLEND : 0))));
1843 else if (r_glsl_permutation)
1845 r_glsl_permutation = NULL;
1846 qglUseProgramObjectARB(0);CHECKGLERROR
1849 if (!r_glsl_permutation)
1851 if (texturemode == GL_DECAL && gl_combine.integer)
1852 texturemode = GL_INTERPOLATE_ARB;
1853 R_Mesh_TexCombine(1, texturemode, texturemode, 1, 1);
1857 void R_SetupDepthOrShadowShader(void)
1859 if (gl_support_fragment_shader)
1861 if (r_glsl.integer && r_glsl_usegeneric.integer)
1862 R_SetupShader_SetPermutation(SHADERMODE_DEPTH_OR_SHADOW, 0);
1863 else if (r_glsl_permutation)
1865 r_glsl_permutation = NULL;
1866 qglUseProgramObjectARB(0);CHECKGLERROR
1871 void R_SetupShowDepthShader(void)
1873 if (gl_support_fragment_shader)
1875 if (r_glsl.integer && r_glsl_usegeneric.integer)
1876 R_SetupShader_SetPermutation(SHADERMODE_SHOWDEPTH, 0);
1877 else if (r_glsl_permutation)
1879 r_glsl_permutation = NULL;
1880 qglUseProgramObjectARB(0);CHECKGLERROR
1885 extern rtexture_t *r_shadow_attenuationgradienttexture;
1886 extern rtexture_t *r_shadow_attenuation2dtexture;
1887 extern rtexture_t *r_shadow_attenuation3dtexture;
1888 extern qboolean r_shadow_usingshadowmaprect;
1889 extern qboolean r_shadow_usingshadowmapcube;
1890 extern qboolean r_shadow_usingshadowmap2d;
1891 extern float r_shadow_shadowmap_bias;
1892 extern float r_shadow_shadowmap_texturescale[2];
1893 extern float r_shadow_shadowmap_parameters[4];
1894 void R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, float ambientscale, float diffusescale, float specularscale, rsurfacepass_t rsurfacepass)
1896 // select a permutation of the lighting shader appropriate to this
1897 // combination of texture, entity, light source, and fogging, only use the
1898 // minimum features necessary to avoid wasting rendering time in the
1899 // fragment shader on features that are not being used
1900 unsigned int permutation = 0;
1901 unsigned int mode = 0;
1902 // TODO: implement geometry-shader based shadow volumes someday
1903 if (r_glsl_offsetmapping.integer)
1905 permutation |= SHADERPERMUTATION_OFFSETMAPPING;
1906 if (r_glsl_offsetmapping_reliefmapping.integer)
1907 permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
1909 if (rsurfacepass == RSURFPASS_BACKGROUND)
1911 // distorted background
1912 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1913 mode = SHADERMODE_WATER;
1915 mode = SHADERMODE_REFRACTION;
1917 else if (rsurfacepass == RSURFPASS_RTLIGHT)
1920 mode = SHADERMODE_LIGHTSOURCE;
1921 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1922 permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1923 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1924 permutation |= SHADERPERMUTATION_CUBEFILTER;
1925 if (diffusescale > 0)
1926 permutation |= SHADERPERMUTATION_DIFFUSE;
1927 if (specularscale > 0)
1928 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1929 if (r_refdef.fogenabled)
1930 permutation |= SHADERPERMUTATION_FOG;
1931 if (rsurface.texture->colormapping)
1932 permutation |= SHADERPERMUTATION_COLORMAPPING;
1933 if (r_shadow_usingshadowmaprect)
1934 permutation |= SHADERPERMUTATION_SHADOWMAPRECT;
1935 if (r_shadow_usingshadowmapcube)
1936 permutation |= SHADERPERMUTATION_SHADOWMAPCUBE;
1937 if (r_shadow_usingshadowmap2d)
1938 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1940 else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
1942 // unshaded geometry (fullbright or ambient model lighting)
1943 mode = SHADERMODE_FLATCOLOR;
1944 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1945 permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1946 if (rsurface.texture->currentskinframe->glow && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1947 permutation |= SHADERPERMUTATION_GLOW;
1948 if (r_refdef.fogenabled)
1949 permutation |= SHADERPERMUTATION_FOG;
1950 if (rsurface.texture->colormapping)
1951 permutation |= SHADERPERMUTATION_COLORMAPPING;
1952 if (r_glsl_offsetmapping.integer)
1954 permutation |= SHADERPERMUTATION_OFFSETMAPPING;
1955 if (r_glsl_offsetmapping_reliefmapping.integer)
1956 permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
1958 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
1959 permutation |= SHADERPERMUTATION_REFLECTION;
1961 else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT_DIRECTIONAL)
1963 // directional model lighting
1964 mode = SHADERMODE_LIGHTDIRECTION;
1965 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1966 permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1967 if (rsurface.texture->currentskinframe->glow && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1968 permutation |= SHADERPERMUTATION_GLOW;
1969 permutation |= SHADERPERMUTATION_DIFFUSE;
1970 if (specularscale > 0)
1971 permutation |= SHADERPERMUTATION_SPECULAR;
1972 if (r_refdef.fogenabled)
1973 permutation |= SHADERPERMUTATION_FOG;
1974 if (rsurface.texture->colormapping)
1975 permutation |= SHADERPERMUTATION_COLORMAPPING;
1976 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
1977 permutation |= SHADERPERMUTATION_REFLECTION;
1979 else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
1981 // ambient model lighting
1982 mode = SHADERMODE_LIGHTDIRECTION;
1983 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1984 permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1985 if (rsurface.texture->currentskinframe->glow && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1986 permutation |= SHADERPERMUTATION_GLOW;
1987 if (r_refdef.fogenabled)
1988 permutation |= SHADERPERMUTATION_FOG;
1989 if (rsurface.texture->colormapping)
1990 permutation |= SHADERPERMUTATION_COLORMAPPING;
1991 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
1992 permutation |= SHADERPERMUTATION_REFLECTION;
1997 if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping)
1999 // deluxemapping (light direction texture)
2000 if (rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping && r_refdef.scene.worldmodel->brushq3.deluxemapping_modelspace)
2001 mode = SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE;
2003 mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
2004 permutation |= SHADERPERMUTATION_DIFFUSE;
2005 if (specularscale > 0)
2006 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
2008 else if (r_glsl_deluxemapping.integer >= 2)
2010 // fake deluxemapping (uniform light direction in tangentspace)
2011 mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
2012 permutation |= SHADERPERMUTATION_DIFFUSE;
2013 if (specularscale > 0)
2014 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
2016 else if (rsurface.uselightmaptexture)
2018 // ordinary lightmapping (q1bsp, q3bsp)
2019 mode = SHADERMODE_LIGHTMAP;
2023 // ordinary vertex coloring (q3bsp)
2024 mode = SHADERMODE_VERTEXCOLOR;
2026 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
2027 permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
2028 if (rsurface.texture->currentskinframe->glow && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
2029 permutation |= SHADERPERMUTATION_GLOW;
2030 if (r_refdef.fogenabled)
2031 permutation |= SHADERPERMUTATION_FOG;
2032 if (rsurface.texture->colormapping)
2033 permutation |= SHADERPERMUTATION_COLORMAPPING;
2034 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
2035 permutation |= SHADERPERMUTATION_REFLECTION;
2037 if(permutation & SHADERPERMUTATION_SPECULAR)
2038 if(r_shadow_glossexact.integer)
2039 permutation |= SHADERPERMUTATION_EXACTSPECULARMATH;
2040 R_SetupShader_SetPermutation(mode, permutation);
2041 if (mode == SHADERMODE_LIGHTSOURCE)
2043 if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
2044 if (permutation & SHADERPERMUTATION_DIFFUSE)
2046 if (r_glsl_permutation->loc_TintColor >= 0) qglUniform4fARB(r_glsl_permutation->loc_TintColor, lightcolorbase[0], lightcolorbase[1], lightcolorbase[2], rsurface.texture->lightmapcolor[3]);
2047 if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, ambientscale);
2048 if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, diffusescale);
2049 if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, specularscale);
2053 // ambient only is simpler
2054 if (r_glsl_permutation->loc_TintColor >= 0) qglUniform4fARB(r_glsl_permutation->loc_TintColor, lightcolorbase[0] * ambientscale, lightcolorbase[1] * ambientscale, lightcolorbase[2] * ambientscale, rsurface.texture->lightmapcolor[3]);
2055 if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, 1);
2056 if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, 0);
2057 if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, 0);
2059 // additive passes are only darkened by fog, not tinted
2060 if (r_glsl_permutation->loc_FogColor >= 0)
2061 qglUniform3fARB(r_glsl_permutation->loc_FogColor, 0, 0, 0);
2062 if (r_glsl_permutation->loc_ShadowMap_Bias >= 0) qglUniform1fARB(r_glsl_permutation->loc_ShadowMap_Bias, r_shadow_shadowmap_bias);
2063 if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform2fARB(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_shadowmap_texturescale[0], r_shadow_shadowmap_texturescale[1]);
2064 if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4fARB(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_shadowmap_parameters[0], r_shadow_shadowmap_parameters[1], r_shadow_shadowmap_parameters[2], r_shadow_shadowmap_parameters[3]);
2068 if (mode == SHADERMODE_LIGHTDIRECTION)
2070 if (r_glsl_permutation->loc_AmbientColor >= 0) qglUniform3fARB(r_glsl_permutation->loc_AmbientColor , rsurface.modellight_ambient[0] * ambientscale * 0.5f, rsurface.modellight_ambient[1] * ambientscale * 0.5f, rsurface.modellight_ambient[2] * ambientscale * 0.5f);
2071 if (r_glsl_permutation->loc_DiffuseColor >= 0) qglUniform3fARB(r_glsl_permutation->loc_DiffuseColor , rsurface.modellight_diffuse[0] * diffusescale * 0.5f, rsurface.modellight_diffuse[1] * diffusescale * 0.5f, rsurface.modellight_diffuse[2] * diffusescale * 0.5f);
2072 if (r_glsl_permutation->loc_SpecularColor >= 0) qglUniform3fARB(r_glsl_permutation->loc_SpecularColor, rsurface.modellight_diffuse[0] * specularscale * 0.5f, rsurface.modellight_diffuse[1] * specularscale * 0.5f, rsurface.modellight_diffuse[2] * specularscale * 0.5f);
2073 if (r_glsl_permutation->loc_LightDir >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightDir, rsurface.modellight_lightdir[0], rsurface.modellight_lightdir[1], rsurface.modellight_lightdir[2]);
2077 if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, r_refdef.scene.ambient * 1.0f / 128.0f);
2078 if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, r_refdef.lightmapintensity);
2079 if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, r_refdef.lightmapintensity * specularscale);
2081 if (r_glsl_permutation->loc_TintColor >= 0) qglUniform4fARB(r_glsl_permutation->loc_TintColor, rsurface.texture->lightmapcolor[0], rsurface.texture->lightmapcolor[1], rsurface.texture->lightmapcolor[2], rsurface.texture->lightmapcolor[3]);
2082 if (r_glsl_permutation->loc_GlowScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_GlowScale, r_hdr_glowintensity.value);
2083 // additive passes are only darkened by fog, not tinted
2084 if (r_glsl_permutation->loc_FogColor >= 0)
2086 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ADD)
2087 qglUniform3fARB(r_glsl_permutation->loc_FogColor, 0, 0, 0);
2089 qglUniform3fARB(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
2091 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);
2092 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]);
2093 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]);
2094 if (r_glsl_permutation->loc_RefractColor >= 0) qglUniform4fvARB(r_glsl_permutation->loc_RefractColor, 1, rsurface.texture->refractcolor4f);
2095 if (r_glsl_permutation->loc_ReflectColor >= 0) qglUniform4fvARB(r_glsl_permutation->loc_ReflectColor, 1, rsurface.texture->reflectcolor4f);
2096 if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1fARB(r_glsl_permutation->loc_ReflectFactor, rsurface.texture->reflectmax - rsurface.texture->reflectmin);
2097 if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1fARB(r_glsl_permutation->loc_ReflectOffset, rsurface.texture->reflectmin);
2099 if (r_glsl_permutation->loc_SceneBrightness >= 0) qglUniform1fARB(r_glsl_permutation->loc_SceneBrightness, r_refdef.view.colorscale);
2100 if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_EyePosition, rsurface.modelorg[0], rsurface.modelorg[1], rsurface.modelorg[2]);
2101 if (r_glsl_permutation->loc_Color_Pants >= 0)
2103 if (rsurface.texture->currentskinframe->pants)
2104 qglUniform3fARB(r_glsl_permutation->loc_Color_Pants, rsurface.colormap_pantscolor[0], rsurface.colormap_pantscolor[1], rsurface.colormap_pantscolor[2]);
2106 qglUniform3fARB(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
2108 if (r_glsl_permutation->loc_Color_Shirt >= 0)
2110 if (rsurface.texture->currentskinframe->shirt)
2111 qglUniform3fARB(r_glsl_permutation->loc_Color_Shirt, rsurface.colormap_shirtcolor[0], rsurface.colormap_shirtcolor[1], rsurface.colormap_shirtcolor[2]);
2113 qglUniform3fARB(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
2115 if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1fARB(r_glsl_permutation->loc_FogRangeRecip, r_refdef.fograngerecip * Matrix4x4_ScaleFromMatrix(&rsurface.matrix));
2116 if(permutation & SHADERPERMUTATION_EXACTSPECULARMATH)
2118 if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularPower, rsurface.texture->specularpower * 0.25);
2122 if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularPower, rsurface.texture->specularpower);
2124 if (r_glsl_permutation->loc_OffsetMapping_Scale >= 0) qglUniform1fARB(r_glsl_permutation->loc_OffsetMapping_Scale, r_glsl_offsetmapping_scale.value);
2128 #define SKINFRAME_HASH 1024
2132 int loadsequence; // incremented each level change
2133 memexpandablearray_t array;
2134 skinframe_t *hash[SKINFRAME_HASH];
2137 r_skinframe_t r_skinframe;
2139 void R_SkinFrame_PrepareForPurge(void)
2141 r_skinframe.loadsequence++;
2142 // wrap it without hitting zero
2143 if (r_skinframe.loadsequence >= 200)
2144 r_skinframe.loadsequence = 1;
2147 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
2151 // mark the skinframe as used for the purging code
2152 skinframe->loadsequence = r_skinframe.loadsequence;
2155 void R_SkinFrame_Purge(void)
2159 for (i = 0;i < SKINFRAME_HASH;i++)
2161 for (s = r_skinframe.hash[i];s;s = s->next)
2163 if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
2165 if (s->merged == s->base)
2167 // FIXME: maybe pass a pointer to the pointer to R_PurgeTexture and reset it to NULL inside? [11/29/2007 Black]
2168 R_PurgeTexture(s->stain );s->stain = NULL;
2169 R_PurgeTexture(s->merged);s->merged = NULL;
2170 R_PurgeTexture(s->base );s->base = NULL;
2171 R_PurgeTexture(s->pants );s->pants = NULL;
2172 R_PurgeTexture(s->shirt );s->shirt = NULL;
2173 R_PurgeTexture(s->nmap );s->nmap = NULL;
2174 R_PurgeTexture(s->gloss );s->gloss = NULL;
2175 R_PurgeTexture(s->glow );s->glow = NULL;
2176 R_PurgeTexture(s->fog );s->fog = NULL;
2177 s->loadsequence = 0;
2183 skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name ) {
2185 char basename[MAX_QPATH];
2187 Image_StripImageExtension(name, basename, sizeof(basename));
2189 if( last == NULL ) {
2191 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2192 item = r_skinframe.hash[hashindex];
2197 // linearly search through the hash bucket
2198 for( ; item ; item = item->next ) {
2199 if( !strcmp( item->basename, basename ) ) {
2206 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qboolean add)
2210 char basename[MAX_QPATH];
2212 Image_StripImageExtension(name, basename, sizeof(basename));
2214 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2215 for (item = r_skinframe.hash[hashindex];item;item = item->next)
2216 if (!strcmp(item->basename, basename) && item->textureflags == textureflags && item->comparewidth == comparewidth && item->compareheight == compareheight && item->comparecrc == comparecrc)
2220 rtexture_t *dyntexture;
2221 // check whether its a dynamic texture
2222 dyntexture = CL_GetDynTexture( basename );
2223 if (!add && !dyntexture)
2225 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
2226 memset(item, 0, sizeof(*item));
2227 strlcpy(item->basename, basename, sizeof(item->basename));
2228 item->base = dyntexture; // either NULL or dyntexture handle
2229 item->textureflags = textureflags;
2230 item->comparewidth = comparewidth;
2231 item->compareheight = compareheight;
2232 item->comparecrc = comparecrc;
2233 item->next = r_skinframe.hash[hashindex];
2234 r_skinframe.hash[hashindex] = item;
2236 else if( item->base == NULL )
2238 rtexture_t *dyntexture;
2239 // check whether its a dynamic texture
2240 // this only needs to be done because Purge doesnt delete skinframes - only sets the texture pointers to NULL and we need to restore it before returing.. [11/29/2007 Black]
2241 dyntexture = CL_GetDynTexture( basename );
2242 item->base = dyntexture; // either NULL or dyntexture handle
2245 R_SkinFrame_MarkUsed(item);
2249 #define R_SKINFRAME_LOAD_AVERAGE_COLORS(cnt, getpixel) \
2251 unsigned long long avgcolor[5], wsum; \
2259 for(pix = 0; pix < cnt; ++pix) \
2262 for(comp = 0; comp < 3; ++comp) \
2264 if(w) /* ignore perfectly black pixels because that is better for model skins */ \
2267 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2269 for(comp = 0; comp < 3; ++comp) \
2270 avgcolor[comp] += getpixel * w; \
2273 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2274 avgcolor[4] += getpixel; \
2276 if(avgcolor[3] == 0) /* no pixels seen? even worse */ \
2278 skinframe->avgcolor[0] = avgcolor[2] / (255.0 * avgcolor[3]); \
2279 skinframe->avgcolor[1] = avgcolor[1] / (255.0 * avgcolor[3]); \
2280 skinframe->avgcolor[2] = avgcolor[0] / (255.0 * avgcolor[3]); \
2281 skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \
2284 skinframe_t *R_SkinFrame_LoadExternal_CheckAlpha(const char *name, int textureflags, qboolean complain, qboolean *has_alpha)
2286 // FIXME: it should be possible to disable loading various layers using
2287 // cvars, to prevent wasted loading time and memory usage if the user does
2289 qboolean loadnormalmap = true;
2290 qboolean loadgloss = true;
2291 qboolean loadpantsandshirt = true;
2292 qboolean loadglow = true;
2294 unsigned char *pixels;
2295 unsigned char *bumppixels;
2296 unsigned char *basepixels = NULL;
2297 int basepixels_width;
2298 int basepixels_height;
2299 skinframe_t *skinframe;
2303 if (cls.state == ca_dedicated)
2306 // return an existing skinframe if already loaded
2307 // if loading of the first image fails, don't make a new skinframe as it
2308 // would cause all future lookups of this to be missing
2309 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
2310 if (skinframe && skinframe->base)
2313 basepixels = loadimagepixelsbgra(name, complain, true);
2314 if (basepixels == NULL)
2317 if (developer_loading.integer)
2318 Con_Printf("loading skin \"%s\"\n", name);
2320 // we've got some pixels to store, so really allocate this new texture now
2322 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
2323 skinframe->stain = NULL;
2324 skinframe->merged = NULL;
2325 skinframe->base = r_texture_notexture;
2326 skinframe->pants = NULL;
2327 skinframe->shirt = NULL;
2328 skinframe->nmap = r_texture_blanknormalmap;
2329 skinframe->gloss = NULL;
2330 skinframe->glow = NULL;
2331 skinframe->fog = NULL;
2333 basepixels_width = image_width;
2334 basepixels_height = image_height;
2335 skinframe->base = R_LoadTexture2D (r_main_texturepool, skinframe->basename, basepixels_width, basepixels_height, basepixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL);
2337 if (textureflags & TEXF_ALPHA)
2339 for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
2340 if (basepixels[j] < 255)
2342 if (j < basepixels_width * basepixels_height * 4)
2344 // has transparent pixels
2346 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2347 for (j = 0;j < image_width * image_height * 4;j += 4)
2352 pixels[j+3] = basepixels[j+3];
2354 skinframe->fog = R_LoadTexture2D (r_main_texturepool, va("%s_mask", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL);
2359 R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
2360 //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2362 // _norm is the name used by tenebrae and has been adopted as standard
2365 if ((pixels = loadimagepixelsbgra(va("%s_norm", skinframe->basename), false, false)) != NULL)
2367 skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va("%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | skinframe->textureflags) & (gl_texturecompression_normal.integer ? ~0 : ~TEXF_COMPRESS), NULL);
2371 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va("%s_bump", skinframe->basename), false, false)) != NULL)
2373 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2374 Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
2375 skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va("%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | skinframe->textureflags) & (gl_texturecompression_normal.integer ? ~0 : ~TEXF_COMPRESS), NULL);
2377 Mem_Free(bumppixels);
2379 else if (r_shadow_bumpscale_basetexture.value > 0)
2381 pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
2382 Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
2383 skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va("%s_nmap", skinframe->basename), basepixels_width, basepixels_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | skinframe->textureflags) & (gl_texturecompression_normal.integer ? ~0 : ~TEXF_COMPRESS), NULL);
2387 // _luma is supported for tenebrae compatibility
2388 // (I think it's a very stupid name, but oh well)
2389 // _glow is the preferred name
2390 if (loadglow && ((pixels = loadimagepixelsbgra(va("%s_glow", skinframe->basename), false, false)) != NULL || (pixels = loadimagepixelsbgra(va("%s_luma", skinframe->basename), false, false)) != NULL)) {skinframe->glow = R_LoadTexture2D (r_main_texturepool, va("%s_glow", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_glow.integer ? ~0 : ~TEXF_COMPRESS), NULL);Mem_Free(pixels);pixels = NULL;}
2391 if (loadgloss && (pixels = loadimagepixelsbgra(va("%s_gloss", skinframe->basename), false, false)) != NULL) {skinframe->gloss = R_LoadTexture2D (r_main_texturepool, va("%s_gloss", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_gloss.integer ? ~0 : ~TEXF_COMPRESS), NULL);Mem_Free(pixels);pixels = NULL;}
2392 if (loadpantsandshirt && (pixels = loadimagepixelsbgra(va("%s_pants", skinframe->basename), false, false)) != NULL) {skinframe->pants = R_LoadTexture2D (r_main_texturepool, va("%s_pants", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL);Mem_Free(pixels);pixels = NULL;}
2393 if (loadpantsandshirt && (pixels = loadimagepixelsbgra(va("%s_shirt", skinframe->basename), false, false)) != NULL) {skinframe->shirt = R_LoadTexture2D (r_main_texturepool, va("%s_shirt", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL);Mem_Free(pixels);pixels = NULL;}
2396 Mem_Free(basepixels);
2401 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain)
2404 return R_SkinFrame_LoadExternal_CheckAlpha(name, textureflags, complain, &has_alpha);
2407 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)
2412 for (i = 0;i < width*height;i++)
2413 if (((unsigned char *)&palette[in[i]])[3] > 0)
2415 if (i == width*height)
2418 return R_LoadTexture2D (r_main_texturepool, name, width, height, in, TEXTYPE_PALETTE, textureflags, palette);
2421 // this is only used by .spr32 sprites, HL .spr files, HL .bsp files
2422 skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height)
2425 unsigned char *temp1, *temp2;
2426 skinframe_t *skinframe;
2428 if (cls.state == ca_dedicated)
2431 // if already loaded just return it, otherwise make a new skinframe
2432 skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height*4) : 0, true);
2433 if (skinframe && skinframe->base)
2436 skinframe->stain = NULL;
2437 skinframe->merged = NULL;
2438 skinframe->base = r_texture_notexture;
2439 skinframe->pants = NULL;
2440 skinframe->shirt = NULL;
2441 skinframe->nmap = r_texture_blanknormalmap;
2442 skinframe->gloss = NULL;
2443 skinframe->glow = NULL;
2444 skinframe->fog = NULL;
2446 // if no data was provided, then clearly the caller wanted to get a blank skinframe
2450 if (developer_loading.integer)
2451 Con_Printf("loading 32bit skin \"%s\"\n", name);
2453 if (r_shadow_bumpscale_basetexture.value > 0)
2455 temp1 = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2456 temp2 = temp1 + width * height * 4;
2457 Image_HeightmapToNormalmap_BGRA(skindata, temp2, width, height, false, r_shadow_bumpscale_basetexture.value);
2458 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va("%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_BGRA, skinframe->textureflags | TEXF_ALPHA, NULL);
2461 skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_BGRA, skinframe->textureflags, NULL);
2462 if (textureflags & TEXF_ALPHA)
2464 for (i = 3;i < width * height * 4;i += 4)
2465 if (skindata[i] < 255)
2467 if (i < width * height * 4)
2469 unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
2470 memcpy(fogpixels, skindata, width * height * 4);
2471 for (i = 0;i < width * height * 4;i += 4)
2472 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
2473 skinframe->fog = R_LoadTexture2D(r_main_texturepool, va("%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, skinframe->textureflags, NULL);
2474 Mem_Free(fogpixels);
2478 R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]);
2479 //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2484 skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height)
2487 unsigned char *temp1, *temp2;
2488 unsigned int *palette;
2489 skinframe_t *skinframe;
2491 if (cls.state == ca_dedicated)
2494 // if already loaded just return it, otherwise make a new skinframe
2495 skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2496 if (skinframe && skinframe->base)
2499 palette = (loadglowtexture ? palette_bgra_nofullbrights : ((skinframe->textureflags & TEXF_ALPHA) ? palette_bgra_transparent : palette_bgra_complete));
2501 skinframe->stain = NULL;
2502 skinframe->merged = NULL;
2503 skinframe->base = r_texture_notexture;
2504 skinframe->pants = NULL;
2505 skinframe->shirt = NULL;
2506 skinframe->nmap = r_texture_blanknormalmap;
2507 skinframe->gloss = NULL;
2508 skinframe->glow = NULL;
2509 skinframe->fog = NULL;
2511 // if no data was provided, then clearly the caller wanted to get a blank skinframe
2515 if (developer_loading.integer)
2516 Con_Printf("loading quake skin \"%s\"\n", name);
2518 if (r_shadow_bumpscale_basetexture.value > 0)
2520 temp1 = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2521 temp2 = temp1 + width * height * 4;
2522 // use either a custom palette or the quake palette
2523 Image_Copy8bitBGRA(skindata, temp1, width * height, palette_bgra_complete);
2524 Image_HeightmapToNormalmap_BGRA(temp1, temp2, width, height, false, r_shadow_bumpscale_basetexture.value);
2525 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va("%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_BGRA, skinframe->textureflags | TEXF_ALPHA, NULL);
2528 // use either a custom palette, or the quake palette
2529 skinframe->base = skinframe->merged = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_merged", skinframe->basename), palette, skinframe->textureflags, true); // all
2530 if (loadglowtexture)
2531 skinframe->glow = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_glow", skinframe->basename), palette_bgra_onlyfullbrights, skinframe->textureflags, false); // glow
2532 if (loadpantsandshirt)
2534 skinframe->pants = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_pants", skinframe->basename), palette_bgra_pantsaswhite, skinframe->textureflags, false); // pants
2535 skinframe->shirt = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_shirt", skinframe->basename), palette_bgra_shirtaswhite, skinframe->textureflags, false); // shirt
2537 if (skinframe->pants || skinframe->shirt)
2538 skinframe->base = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_nospecial", skinframe->basename), loadglowtexture ? palette_bgra_nocolormapnofullbrights : palette_bgra_nocolormap, skinframe->textureflags, false); // no special colors
2539 if (textureflags & TEXF_ALPHA)
2541 for (i = 0;i < width * height;i++)
2542 if (((unsigned char *)palette_bgra_alpha)[skindata[i]*4+3] < 255)
2544 if (i < width * height)
2545 skinframe->fog = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_fog", skinframe->basename), palette_bgra_alpha, skinframe->textureflags, true); // fog mask
2548 R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
2549 //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2554 skinframe_t *R_SkinFrame_LoadMissing(void)
2556 skinframe_t *skinframe;
2558 if (cls.state == ca_dedicated)
2561 skinframe = R_SkinFrame_Find("missing", TEXF_PRECACHE | TEXF_FORCENEAREST, 0, 0, 0, true);
2562 skinframe->stain = NULL;
2563 skinframe->merged = NULL;
2564 skinframe->base = r_texture_notexture;
2565 skinframe->pants = NULL;
2566 skinframe->shirt = NULL;
2567 skinframe->nmap = r_texture_blanknormalmap;
2568 skinframe->gloss = NULL;
2569 skinframe->glow = NULL;
2570 skinframe->fog = NULL;
2572 skinframe->avgcolor[0] = rand() / RAND_MAX;
2573 skinframe->avgcolor[1] = rand() / RAND_MAX;
2574 skinframe->avgcolor[2] = rand() / RAND_MAX;
2575 skinframe->avgcolor[3] = 1;
2580 void gl_main_start(void)
2584 memset(r_queries, 0, sizeof(r_queries));
2586 memset(r_qwskincache, 0, sizeof(r_qwskincache));
2587 memset(r_qwskincache_skinframe, 0, sizeof(r_qwskincache_skinframe));
2589 // set up r_skinframe loading system for textures
2590 memset(&r_skinframe, 0, sizeof(r_skinframe));
2591 r_skinframe.loadsequence = 1;
2592 Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
2594 r_main_texturepool = R_AllocTexturePool();
2595 R_BuildBlankTextures();
2597 if (gl_texturecubemap)
2600 R_BuildNormalizationCube();
2602 r_texture_fogattenuation = NULL;
2603 r_texture_gammaramps = NULL;
2604 //r_texture_fogintensity = NULL;
2605 memset(&r_bloomstate, 0, sizeof(r_bloomstate));
2606 memset(&r_waterstate, 0, sizeof(r_waterstate));
2607 memset(r_glsl_permutations, 0, sizeof(r_glsl_permutations));
2608 memset(&r_svbsp, 0, sizeof (r_svbsp));
2610 r_refdef.fogmasktable_density = 0;
2613 extern rtexture_t *loadingscreentexture;
2614 void gl_main_shutdown(void)
2617 qglDeleteQueriesARB(r_maxqueries, r_queries);
2621 memset(r_queries, 0, sizeof(r_queries));
2623 memset(r_qwskincache, 0, sizeof(r_qwskincache));
2624 memset(r_qwskincache_skinframe, 0, sizeof(r_qwskincache_skinframe));
2626 // clear out the r_skinframe state
2627 Mem_ExpandableArray_FreeArray(&r_skinframe.array);
2628 memset(&r_skinframe, 0, sizeof(r_skinframe));
2631 Mem_Free(r_svbsp.nodes);
2632 memset(&r_svbsp, 0, sizeof (r_svbsp));
2633 R_FreeTexturePool(&r_main_texturepool);
2634 loadingscreentexture = NULL;
2635 r_texture_blanknormalmap = NULL;
2636 r_texture_white = NULL;
2637 r_texture_grey128 = NULL;
2638 r_texture_black = NULL;
2639 r_texture_whitecube = NULL;
2640 r_texture_normalizationcube = NULL;
2641 r_texture_fogattenuation = NULL;
2642 r_texture_gammaramps = NULL;
2643 //r_texture_fogintensity = NULL;
2644 memset(&r_bloomstate, 0, sizeof(r_bloomstate));
2645 memset(&r_waterstate, 0, sizeof(r_waterstate));
2649 extern void CL_ParseEntityLump(char *entitystring);
2650 void gl_main_newmap(void)
2652 // FIXME: move this code to client
2654 char *entities, entname[MAX_QPATH];
2657 strlcpy(entname, cl.worldmodel->name, sizeof(entname));
2658 l = (int)strlen(entname) - 4;
2659 if (l >= 0 && !strcmp(entname + l, ".bsp"))
2661 memcpy(entname + l, ".ent", 5);
2662 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
2664 CL_ParseEntityLump(entities);
2669 if (cl.worldmodel->brush.entities)
2670 CL_ParseEntityLump(cl.worldmodel->brush.entities);
2674 void GL_Main_Init(void)
2676 r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
2678 Cmd_AddCommand("r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
2679 Cmd_AddCommand("r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
2680 // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
2681 if (gamemode == GAME_NEHAHRA)
2683 Cvar_RegisterVariable (&gl_fogenable);
2684 Cvar_RegisterVariable (&gl_fogdensity);
2685 Cvar_RegisterVariable (&gl_fogred);
2686 Cvar_RegisterVariable (&gl_foggreen);
2687 Cvar_RegisterVariable (&gl_fogblue);
2688 Cvar_RegisterVariable (&gl_fogstart);
2689 Cvar_RegisterVariable (&gl_fogend);
2690 Cvar_RegisterVariable (&gl_skyclip);
2692 Cvar_RegisterVariable(&r_motionblur);
2693 Cvar_RegisterVariable(&r_motionblur_maxblur);
2694 Cvar_RegisterVariable(&r_motionblur_bmin);
2695 Cvar_RegisterVariable(&r_motionblur_vmin);
2696 Cvar_RegisterVariable(&r_motionblur_vmax);
2697 Cvar_RegisterVariable(&r_motionblur_vcoeff);
2698 Cvar_RegisterVariable(&r_motionblur_randomize);
2699 Cvar_RegisterVariable(&r_damageblur);
2700 Cvar_RegisterVariable(&r_animcache);
2701 Cvar_RegisterVariable(&r_depthfirst);
2702 Cvar_RegisterVariable(&r_useinfinitefarclip);
2703 Cvar_RegisterVariable(&r_nearclip);
2704 Cvar_RegisterVariable(&r_showbboxes);
2705 Cvar_RegisterVariable(&r_showsurfaces);
2706 Cvar_RegisterVariable(&r_showtris);
2707 Cvar_RegisterVariable(&r_shownormals);
2708 Cvar_RegisterVariable(&r_showlighting);
2709 Cvar_RegisterVariable(&r_showshadowvolumes);
2710 Cvar_RegisterVariable(&r_showcollisionbrushes);
2711 Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
2712 Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
2713 Cvar_RegisterVariable(&r_showdisabledepthtest);
2714 Cvar_RegisterVariable(&r_drawportals);
2715 Cvar_RegisterVariable(&r_drawentities);
2716 Cvar_RegisterVariable(&r_cullentities_trace);
2717 Cvar_RegisterVariable(&r_cullentities_trace_samples);
2718 Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
2719 Cvar_RegisterVariable(&r_cullentities_trace_delay);
2720 Cvar_RegisterVariable(&r_drawviewmodel);
2721 Cvar_RegisterVariable(&r_speeds);
2722 Cvar_RegisterVariable(&r_fullbrights);
2723 Cvar_RegisterVariable(&r_wateralpha);
2724 Cvar_RegisterVariable(&r_dynamic);
2725 Cvar_RegisterVariable(&r_fullbright);
2726 Cvar_RegisterVariable(&r_shadows);
2727 Cvar_RegisterVariable(&r_shadows_darken);
2728 Cvar_RegisterVariable(&r_shadows_drawafterrtlightning);
2729 Cvar_RegisterVariable(&r_shadows_castfrombmodels);
2730 Cvar_RegisterVariable(&r_shadows_throwdistance);
2731 Cvar_RegisterVariable(&r_shadows_throwdirection);
2732 Cvar_RegisterVariable(&r_q1bsp_skymasking);
2733 Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
2734 Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
2735 Cvar_RegisterVariable(&r_fog_exp2);
2736 Cvar_RegisterVariable(&r_drawfog);
2737 Cvar_RegisterVariable(&r_textureunits);
2738 Cvar_RegisterVariable(&r_glsl);
2739 Cvar_RegisterVariable(&r_glsl_deluxemapping);
2740 Cvar_RegisterVariable(&r_glsl_offsetmapping);
2741 Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
2742 Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
2743 Cvar_RegisterVariable(&r_glsl_postprocess);
2744 Cvar_RegisterVariable(&r_glsl_postprocess_uservec1);
2745 Cvar_RegisterVariable(&r_glsl_postprocess_uservec2);
2746 Cvar_RegisterVariable(&r_glsl_postprocess_uservec3);
2747 Cvar_RegisterVariable(&r_glsl_postprocess_uservec4);
2748 Cvar_RegisterVariable(&r_glsl_usegeneric);
2749 Cvar_RegisterVariable(&r_water);
2750 Cvar_RegisterVariable(&r_water_resolutionmultiplier);
2751 Cvar_RegisterVariable(&r_water_clippingplanebias);
2752 Cvar_RegisterVariable(&r_water_refractdistort);
2753 Cvar_RegisterVariable(&r_water_reflectdistort);
2754 Cvar_RegisterVariable(&r_lerpsprites);
2755 Cvar_RegisterVariable(&r_lerpmodels);
2756 Cvar_RegisterVariable(&r_lerplightstyles);
2757 Cvar_RegisterVariable(&r_waterscroll);
2758 Cvar_RegisterVariable(&r_bloom);
2759 Cvar_RegisterVariable(&r_bloom_colorscale);
2760 Cvar_RegisterVariable(&r_bloom_brighten);
2761 Cvar_RegisterVariable(&r_bloom_blur);
2762 Cvar_RegisterVariable(&r_bloom_resolution);
2763 Cvar_RegisterVariable(&r_bloom_colorexponent);
2764 Cvar_RegisterVariable(&r_bloom_colorsubtract);
2765 Cvar_RegisterVariable(&r_hdr);
2766 Cvar_RegisterVariable(&r_hdr_scenebrightness);
2767 Cvar_RegisterVariable(&r_hdr_glowintensity);
2768 Cvar_RegisterVariable(&r_hdr_range);
2769 Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
2770 Cvar_RegisterVariable(&developer_texturelogging);
2771 Cvar_RegisterVariable(&gl_lightmaps);
2772 Cvar_RegisterVariable(&r_test);
2773 Cvar_RegisterVariable(&r_batchmode);
2774 Cvar_RegisterVariable(&r_glsl_saturation);
2775 if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
2776 Cvar_SetValue("r_fullbrights", 0);
2777 R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
2779 Cvar_RegisterVariable(&r_track_sprites);
2780 Cvar_RegisterVariable(&r_track_sprites_flags);
2781 Cvar_RegisterVariable(&r_track_sprites_scalew);
2782 Cvar_RegisterVariable(&r_track_sprites_scaleh);
2785 extern void R_Textures_Init(void);
2786 extern void GL_Draw_Init(void);
2787 extern void GL_Main_Init(void);
2788 extern void R_Shadow_Init(void);
2789 extern void R_Sky_Init(void);
2790 extern void GL_Surf_Init(void);
2791 extern void R_Particles_Init(void);
2792 extern void R_Explosion_Init(void);
2793 extern void gl_backend_init(void);
2794 extern void Sbar_Init(void);
2795 extern void R_LightningBeams_Init(void);
2796 extern void Mod_RenderInit(void);
2798 void Render_Init(void)
2810 R_LightningBeams_Init();
2819 extern char *ENGINE_EXTENSIONS;
2822 gl_renderer = (const char *)qglGetString(GL_RENDERER);
2823 gl_vendor = (const char *)qglGetString(GL_VENDOR);
2824 gl_version = (const char *)qglGetString(GL_VERSION);
2825 gl_extensions = (const char *)qglGetString(GL_EXTENSIONS);
2829 if (!gl_platformextensions)
2830 gl_platformextensions = "";
2832 Con_Printf("GL_VENDOR: %s\n", gl_vendor);
2833 Con_Printf("GL_RENDERER: %s\n", gl_renderer);
2834 Con_Printf("GL_VERSION: %s\n", gl_version);
2835 Con_DPrintf("GL_EXTENSIONS: %s\n", gl_extensions);
2836 Con_DPrintf("%s_EXTENSIONS: %s\n", gl_platform, gl_platformextensions);
2838 VID_CheckExtensions();
2840 // LordHavoc: report supported extensions
2841 Con_DPrintf("\nQuakeC extensions for server and client: %s\nQuakeC extensions for menu: %s\n", vm_sv_extensions, vm_m_extensions );
2843 // clear to black (loading plaque will be seen over this)
2845 qglClearColor(0,0,0,1);CHECKGLERROR
2846 qglClear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
2849 int R_CullBox(const vec3_t mins, const vec3_t maxs)
2853 for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
2855 // skip nearclip plane, it often culls portals when you are very close, and is almost never useful
2858 p = r_refdef.view.frustum + i;
2863 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
2867 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
2871 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
2875 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
2879 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
2883 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
2887 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
2891 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
2899 int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
2903 for (i = 0;i < numplanes;i++)
2910 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
2914 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
2918 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
2922 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
2926 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
2930 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
2934 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
2938 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
2946 //==================================================================================
2948 // LordHavoc: animcache written by Echon, refactored and reformatted by me
2951 * Animation cache helps save re-animating a player mesh if it's re-rendered again in a given frame
2952 * (reflections, lighting, etc). All animation cache becomes invalid on the next frame and is flushed
2953 * (well, over-wrote). The memory for each cache is kept around to save on allocation thrashing.
2956 typedef struct r_animcache_entity_s
2963 qboolean wantnormals;
2964 qboolean wanttangents;
2966 r_animcache_entity_t;
2968 typedef struct r_animcache_s
2970 r_animcache_entity_t entity[MAX_EDICTS*2];
2976 static r_animcache_t r_animcachestate;
2978 void R_AnimCache_Free(void)
2981 for (idx=0 ; idx<r_animcachestate.maxindex ; idx++)
2983 r_animcachestate.entity[idx].maxvertices = 0;
2984 Mem_Free(r_animcachestate.entity[idx].vertex3f);
2985 r_animcachestate.entity[idx].vertex3f = NULL;
2986 r_animcachestate.entity[idx].normal3f = NULL;
2987 r_animcachestate.entity[idx].svector3f = NULL;
2988 r_animcachestate.entity[idx].tvector3f = NULL;
2990 r_animcachestate.currentindex = 0;
2991 r_animcachestate.maxindex = 0;
2994 void R_AnimCache_ResizeEntityCache(const int cacheIdx, const int numvertices)
2998 r_animcache_entity_t *cache = &r_animcachestate.entity[cacheIdx];
3000 if (cache->maxvertices >= numvertices)
3003 // Release existing memory
3004 if (cache->vertex3f)
3005 Mem_Free(cache->vertex3f);
3007 // Pad by 1024 verts
3008 cache->maxvertices = (numvertices + 1023) & ~1023;
3009 arraySize = cache->maxvertices * 3;
3011 // Allocate, even if we don't need this memory in this instance it will get ignored and potentially used later
3012 base = (float *)Mem_Alloc(r_main_mempool, arraySize * sizeof(float) * 4);
3013 r_animcachestate.entity[cacheIdx].vertex3f = base;
3014 r_animcachestate.entity[cacheIdx].normal3f = base + arraySize;
3015 r_animcachestate.entity[cacheIdx].svector3f = base + arraySize*2;
3016 r_animcachestate.entity[cacheIdx].tvector3f = base + arraySize*3;
3018 // Con_Printf("allocated cache for %i (%f KB)\n", cacheIdx, (arraySize*sizeof(float)*4)/1024.0f);
3021 void R_AnimCache_NewFrame(void)
3025 if (r_animcache.integer && r_drawentities.integer)
3026 r_animcachestate.maxindex = sizeof(r_animcachestate.entity) / sizeof(r_animcachestate.entity[0]);
3027 else if (r_animcachestate.maxindex)
3030 r_animcachestate.currentindex = 0;
3032 for (i = 0;i < r_refdef.scene.numentities;i++)
3033 r_refdef.scene.entities[i]->animcacheindex = -1;
3036 qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
3038 dp_model_t *model = ent->model;
3039 r_animcache_entity_t *c;
3040 // see if it's already cached this frame
3041 if (ent->animcacheindex >= 0)
3043 // add normals/tangents if needed
3044 c = r_animcachestate.entity + ent->animcacheindex;
3046 wantnormals = false;
3047 if (c->wanttangents)
3048 wanttangents = false;
3049 if (wantnormals || wanttangents)
3050 model->AnimateVertices(model, ent->frameblend, NULL, wantnormals ? c->normal3f : NULL, wanttangents ? c->svector3f : NULL, wanttangents ? c->tvector3f : NULL);
3054 // see if this ent is worth caching
3055 if (r_animcachestate.maxindex <= r_animcachestate.currentindex)
3057 if (!model || !model->Draw || !model->surfmesh.isanimated || !model->AnimateVertices || (ent->frameblend[0].lerp == 1 && ent->frameblend[0].subframe == 0))
3059 // assign it a cache entry and make sure the arrays are big enough
3060 R_AnimCache_ResizeEntityCache(r_animcachestate.currentindex, model->surfmesh.num_vertices);
3061 ent->animcacheindex = r_animcachestate.currentindex++;
3062 c = r_animcachestate.entity + ent->animcacheindex;
3063 c->wantnormals = wantnormals;
3064 c->wanttangents = wanttangents;
3065 model->AnimateVertices(model, ent->frameblend, c->vertex3f, wantnormals ? c->normal3f : NULL, wanttangents ? c->svector3f : NULL, wanttangents ? c->tvector3f : NULL);
3070 void R_AnimCache_CacheVisibleEntities(void)
3073 qboolean wantnormals;
3074 qboolean wanttangents;
3076 if (!r_animcachestate.maxindex)
3079 wantnormals = !r_showsurfaces.integer;
3080 wanttangents = !r_showsurfaces.integer && (r_glsl.integer || r_refdef.scene.rtworld || r_refdef.scene.rtdlight);
3082 // TODO: thread this?
3084 for (i = 0;i < r_refdef.scene.numentities;i++)
3086 if (!r_refdef.viewcache.entityvisible[i])
3088 R_AnimCache_GetEntity(r_refdef.scene.entities[i], wantnormals, wanttangents);
3092 //==================================================================================
3094 static void R_View_UpdateEntityLighting (void)
3097 entity_render_t *ent;
3098 vec3_t tempdiffusenormal;
3100 for (i = 0;i < r_refdef.scene.numentities;i++)
3102 ent = r_refdef.scene.entities[i];
3104 // skip unseen models
3105 if (!r_refdef.viewcache.entityvisible[i] && r_shadows.integer != 1)
3109 if (ent->model && ent->model->brush.num_leafs)
3111 // TODO: use modellight for r_ambient settings on world?
3112 VectorSet(ent->modellight_ambient, 0, 0, 0);
3113 VectorSet(ent->modellight_diffuse, 0, 0, 0);
3114 VectorSet(ent->modellight_lightdir, 0, 0, 1);
3118 // fetch the lighting from the worldmodel data
3119 VectorSet(ent->modellight_ambient, r_refdef.scene.ambient * (2.0f / 128.0f), r_refdef.scene.ambient * (2.0f / 128.0f), r_refdef.scene.ambient * (2.0f / 128.0f));
3120 VectorClear(ent->modellight_diffuse);
3121 VectorClear(tempdiffusenormal);
3122 if ((ent->flags & RENDER_LIGHT) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.LightPoint)
3125 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3126 r_refdef.scene.worldmodel->brush.LightPoint(r_refdef.scene.worldmodel, org, ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal);
3129 VectorSet(ent->modellight_ambient, 1, 1, 1);
3131 // move the light direction into modelspace coordinates for lighting code
3132 Matrix4x4_Transform3x3(&ent->inversematrix, tempdiffusenormal, ent->modellight_lightdir);
3133 if(VectorLength2(ent->modellight_lightdir) == 0)
3134 VectorSet(ent->modellight_lightdir, 0, 0, 1); // have to set SOME valid vector here
3135 VectorNormalize(ent->modellight_lightdir);
3139 static void R_View_UpdateEntityVisible (void)
3142 entity_render_t *ent;
3144 if (!r_drawentities.integer)
3147 renderimask = r_refdef.envmap ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL) : ((chase_active.integer || r_waterstate.renderingscene) ? RENDER_VIEWMODEL : RENDER_EXTERIORMODEL);
3148 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
3150 // worldmodel can check visibility
3151 memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
3152 for (i = 0;i < r_refdef.scene.numentities;i++)
3154 ent = r_refdef.scene.entities[i];
3155 if (!(ent->flags & renderimask))
3156 if (!R_CullBox(ent->mins, ent->maxs) || (ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
3157 if ((ent->effects & EF_NODEPTHTEST) || (ent->flags & RENDER_VIEWMODEL) || r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, ent->mins, ent->maxs))
3158 r_refdef.viewcache.entityvisible[i] = true;
3160 if(r_cullentities_trace.integer && r_refdef.scene.worldmodel->brush.TraceLineOfSight)
3162 for (i = 0;i < r_refdef.scene.numentities;i++)
3164 ent = r_refdef.scene.entities[i];
3165 if(r_refdef.viewcache.entityvisible[i] && !(ent->effects & EF_NODEPTHTEST) && !(ent->flags & RENDER_VIEWMODEL) && !(ent->model && (ent->model->name[0] == '*')))
3167 if(Mod_CanSeeBox_Trace(r_cullentities_trace_samples.integer, r_cullentities_trace_enlarge.value, r_refdef.scene.worldmodel, r_refdef.view.origin, ent->mins, ent->maxs))
3168 ent->last_trace_visibility = realtime;
3169 if(ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
3170 r_refdef.viewcache.entityvisible[i] = 0;
3177 // no worldmodel or it can't check visibility
3178 for (i = 0;i < r_refdef.scene.numentities;i++)
3180 ent = r_refdef.scene.entities[i];
3181 r_refdef.viewcache.entityvisible[i] = !(ent->flags & renderimask) && ((ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)) || !R_CullBox(ent->mins, ent->maxs));
3186 /// only used if skyrendermasked, and normally returns false
3187 int R_DrawBrushModelsSky (void)
3190 entity_render_t *ent;
3192 if (!r_drawentities.integer)
3196 for (i = 0;i < r_refdef.scene.numentities;i++)
3198 if (!r_refdef.viewcache.entityvisible[i])
3200 ent = r_refdef.scene.entities[i];
3201 if (!ent->model || !ent->model->DrawSky)
3203 ent->model->DrawSky(ent);
3209 static void R_DrawNoModel(entity_render_t *ent);
3210 static void R_DrawModels(void)
3213 entity_render_t *ent;
3215 if (!r_drawentities.integer)
3218 for (i = 0;i < r_refdef.scene.numentities;i++)
3220 if (!r_refdef.viewcache.entityvisible[i])
3222 ent = r_refdef.scene.entities[i];
3223 r_refdef.stats.entities++;
3224 if (ent->model && ent->model->Draw != NULL)
3225 ent->model->Draw(ent);
3231 static void R_DrawModelsDepth(void)
3234 entity_render_t *ent;
3236 if (!r_drawentities.integer)
3239 for (i = 0;i < r_refdef.scene.numentities;i++)
3241 if (!r_refdef.viewcache.entityvisible[i])
3243 ent = r_refdef.scene.entities[i];
3244 if (ent->model && ent->model->DrawDepth != NULL)
3245 ent->model->DrawDepth(ent);
3249 static void R_DrawModelsDebug(void)
3252 entity_render_t *ent;
3254 if (!r_drawentities.integer)
3257 for (i = 0;i < r_refdef.scene.numentities;i++)
3259 if (!r_refdef.viewcache.entityvisible[i])
3261 ent = r_refdef.scene.entities[i];
3262 if (ent->model && ent->model->DrawDebug != NULL)
3263 ent->model->DrawDebug(ent);
3267 static void R_DrawModelsAddWaterPlanes(void)
3270 entity_render_t *ent;
3272 if (!r_drawentities.integer)
3275 for (i = 0;i < r_refdef.scene.numentities;i++)
3277 if (!r_refdef.viewcache.entityvisible[i])
3279 ent = r_refdef.scene.entities[i];
3280 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
3281 ent->model->DrawAddWaterPlanes(ent);
3285 static void R_View_SetFrustum(void)
3288 double slopex, slopey;
3289 vec3_t forward, left, up, origin;
3291 // we can't trust r_refdef.view.forward and friends in reflected scenes
3292 Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin);
3295 r_refdef.view.frustum[0].normal[0] = 0 - 1.0 / r_refdef.view.frustum_x;
3296 r_refdef.view.frustum[0].normal[1] = 0 - 0;
3297 r_refdef.view.frustum[0].normal[2] = -1 - 0;
3298 r_refdef.view.frustum[1].normal[0] = 0 + 1.0 / r_refdef.view.frustum_x;
3299 r_refdef.view.frustum[1].normal[1] = 0 + 0;
3300 r_refdef.view.frustum[1].normal[2] = -1 + 0;
3301 r_refdef.view.frustum[2].normal[0] = 0 - 0;
3302 r_refdef.view.frustum[2].normal[1] = 0 - 1.0 / r_refdef.view.frustum_y;
3303 r_refdef.view.frustum[2].normal[2] = -1 - 0;
3304 r_refdef.view.frustum[3].normal[0] = 0 + 0;
3305 r_refdef.view.frustum[3].normal[1] = 0 + 1.0 / r_refdef.view.frustum_y;
3306 r_refdef.view.frustum[3].normal[2] = -1 + 0;
3310 zNear = r_refdef.nearclip;
3311 nudge = 1.0 - 1.0 / (1<<23);
3312 r_refdef.view.frustum[4].normal[0] = 0 - 0;
3313 r_refdef.view.frustum[4].normal[1] = 0 - 0;
3314 r_refdef.view.frustum[4].normal[2] = -1 - -nudge;
3315 r_refdef.view.frustum[4].dist = 0 - -2 * zNear * nudge;
3316 r_refdef.view.frustum[5].normal[0] = 0 + 0;
3317 r_refdef.view.frustum[5].normal[1] = 0 + 0;
3318 r_refdef.view.frustum[5].normal[2] = -1 + -nudge;
3319 r_refdef.view.frustum[5].dist = 0 + -2 * zNear * nudge;
3325 r_refdef.view.frustum[0].normal[0] = m[3] - m[0];
3326 r_refdef.view.frustum[0].normal[1] = m[7] - m[4];
3327 r_refdef.view.frustum[0].normal[2] = m[11] - m[8];
3328 r_refdef.view.frustum[0].dist = m[15] - m[12];
3330 r_refdef.view.frustum[1].normal[0] = m[3] + m[0];
3331 r_refdef.view.frustum[1].normal[1] = m[7] + m[4];
3332 r_refdef.view.frustum[1].normal[2] = m[11] + m[8];
3333 r_refdef.view.frustum[1].dist = m[15] + m[12];
3335 r_refdef.view.frustum[2].normal[0] = m[3] - m[1];
3336 r_refdef.view.frustum[2].normal[1] = m[7] - m[5];
3337 r_refdef.view.frustum[2].normal[2] = m[11] - m[9];
3338 r_refdef.view.frustum[2].dist = m[15] - m[13];
3340 r_refdef.view.frustum[3].normal[0] = m[3] + m[1];
3341 r_refdef.view.frustum[3].normal[1] = m[7] + m[5];
3342 r_refdef.view.frustum[3].normal[2] = m[11] + m[9];
3343 r_refdef.view.frustum[3].dist = m[15] + m[13];
3345 r_refdef.view.frustum[4].normal[0] = m[3] - m[2];
3346 r_refdef.view.frustum[4].normal[1] = m[7] - m[6];
3347 r_refdef.view.frustum[4].normal[2] = m[11] - m[10];
3348 r_refdef.view.frustum[4].dist = m[15] - m[14];
3350 r_refdef.view.frustum[5].normal[0] = m[3] + m[2];
3351 r_refdef.view.frustum[5].normal[1] = m[7] + m[6];
3352 r_refdef.view.frustum[5].normal[2] = m[11] + m[10];
3353 r_refdef.view.frustum[5].dist = m[15] + m[14];
3356 if (r_refdef.view.useperspective)
3358 slopex = 1.0 / r_refdef.view.frustum_x;
3359 slopey = 1.0 / r_refdef.view.frustum_y;
3360 VectorMA(forward, -slopex, left, r_refdef.view.frustum[0].normal);
3361 VectorMA(forward, slopex, left, r_refdef.view.frustum[1].normal);
3362 VectorMA(forward, -slopey, up , r_refdef.view.frustum[2].normal);
3363 VectorMA(forward, slopey, up , r_refdef.view.frustum[3].normal);
3364 VectorCopy(forward, r_refdef.view.frustum[4].normal);
3366 // Leaving those out was a mistake, those were in the old code, and they
3367 // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix
3368 // I couldn't reproduce it after adding those normalizations. --blub
3369 VectorNormalize(r_refdef.view.frustum[0].normal);
3370 VectorNormalize(r_refdef.view.frustum[1].normal);
3371 VectorNormalize(r_refdef.view.frustum[2].normal);
3372 VectorNormalize(r_refdef.view.frustum[3].normal);
3374 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
3375 VectorMAMAMAM(1, r_refdef.view.origin, 1024, forward, -1024 * r_refdef.view.frustum_x, left, -1024 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[0]);
3376 VectorMAMAMAM(1, r_refdef.view.origin, 1024, forward, 1024 * r_refdef.view.frustum_x, left, -1024 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[1]);
3377 VectorMAMAMAM(1, r_refdef.view.origin, 1024, forward, -1024 * r_refdef.view.frustum_x, left, 1024 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[2]);
3378 VectorMAMAMAM(1, r_refdef.view.origin, 1024, forward, 1024 * r_refdef.view.frustum_x, left, 1024 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[3]);
3380 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal);
3381 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal);
3382 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal);
3383 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal);
3384 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip;
3388 VectorScale(left, -r_refdef.view.ortho_x, r_refdef.view.frustum[0].normal);
3389 VectorScale(left, r_refdef.view.ortho_x, r_refdef.view.frustum[1].normal);
3390 VectorScale(up, -r_refdef.view.ortho_y, r_refdef.view.frustum[2].normal);
3391 VectorScale(up, r_refdef.view.ortho_y, r_refdef.view.frustum[3].normal);
3392 VectorCopy(forward, r_refdef.view.frustum[4].normal);
3393 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal) + r_refdef.view.ortho_x;
3394 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal) + r_refdef.view.ortho_x;
3395 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal) + r_refdef.view.ortho_y;
3396 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal) + r_refdef.view.ortho_y;
3397 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip;
3399 r_refdef.view.numfrustumplanes = 5;
3401 if (r_refdef.view.useclipplane)
3403 r_refdef.view.numfrustumplanes = 6;
3404 r_refdef.view.frustum[5] = r_refdef.view.clipplane;
3407 for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
3408 PlaneClassify(r_refdef.view.frustum + i);
3410 // LordHavoc: note to all quake engine coders, Quake had a special case
3411 // for 90 degrees which assumed a square view (wrong), so I removed it,
3412 // Quake2 has it disabled as well.
3414 // rotate R_VIEWFORWARD right by FOV_X/2 degrees
3415 //RotatePointAroundVector( r_refdef.view.frustum[0].normal, up, forward, -(90 - r_refdef.fov_x / 2));
3416 //r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, frustum[0].normal);
3417 //PlaneClassify(&frustum[0]);
3419 // rotate R_VIEWFORWARD left by FOV_X/2 degrees
3420 //RotatePointAroundVector( r_refdef.view.frustum[1].normal, up, forward, (90 - r_refdef.fov_x / 2));
3421 //r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, frustum[1].normal);
3422 //PlaneClassify(&frustum[1]);
3424 // rotate R_VIEWFORWARD up by FOV_X/2 degrees
3425 //RotatePointAroundVector( r_refdef.view.frustum[2].normal, left, forward, -(90 - r_refdef.fov_y / 2));
3426 //r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, frustum[2].normal);
3427 //PlaneClassify(&frustum[2]);
3429 // rotate R_VIEWFORWARD down by FOV_X/2 degrees
3430 //RotatePointAroundVector( r_refdef.view.frustum[3].normal, left, forward, (90 - r_refdef.fov_y / 2));
3431 //r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, frustum[3].normal);
3432 //PlaneClassify(&frustum[3]);
3435 //VectorCopy(forward, r_refdef.view.frustum[4].normal);
3436 //r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, frustum[4].normal) + r_nearclip.value;
3437 //PlaneClassify(&frustum[4]);
3440 void R_View_Update(void)
3442 R_View_SetFrustum();
3443 R_View_WorldVisibility(r_refdef.view.useclipplane);
3444 R_View_UpdateEntityVisible();
3445 R_View_UpdateEntityLighting();
3448 void R_SetupView(qboolean allowwaterclippingplane)
3450 const double *customclipplane = NULL;
3452 if (r_refdef.view.useclipplane && allowwaterclippingplane)
3454 // LordHavoc: couldn't figure out how to make this approach the
3455 vec_t dist = r_refdef.view.clipplane.dist - r_water_clippingplanebias.value;
3456 vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
3457 if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
3458 dist = r_refdef.view.clipplane.dist;
3459 plane[0] = r_refdef.view.clipplane.normal[0];
3460 plane[1] = r_refdef.view.clipplane.normal[1];
3461 plane[2] = r_refdef.view.clipplane.normal[2];
3463 customclipplane = plane;
3466 if (!r_refdef.view.useperspective)
3467 R_Viewport_InitOrtho(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height, -r_refdef.view.ortho_x, -r_refdef.view.ortho_y, r_refdef.view.ortho_x, r_refdef.view.ortho_y, -r_refdef.farclip, r_refdef.farclip, customclipplane);
3468 else if (gl_stencil && r_useinfinitefarclip.integer)
3469 R_Viewport_InitPerspectiveInfinite(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, customclipplane);
3471 R_Viewport_InitPerspective(&r_refdef.view.viewport, &r_refdef.view.matrix, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, r_refdef.farclip, customclipplane);
3472 R_SetViewport(&r_refdef.view.viewport);
3475 void R_ResetViewRendering2D(void)
3477 r_viewport_t viewport;
3480 // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
3481 R_Viewport_InitOrtho(&viewport, &identitymatrix, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height, 0, 0, 1, 1, -10, 100, NULL);
3482 R_SetViewport(&viewport);
3483 GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.y - r_refdef.view.height, r_refdef.view.width, r_refdef.view.height);
3484 GL_Color(1, 1, 1, 1);
3485 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3486 GL_BlendFunc(GL_ONE, GL_ZERO);
3487 GL_AlphaTest(false);
3488 GL_ScissorTest(false);
3489 GL_DepthMask(false);
3490 GL_DepthRange(0, 1);
3491 GL_DepthTest(false);
3492 R_Mesh_Matrix(&identitymatrix);
3493 R_Mesh_ResetTextureState();
3494 GL_PolygonOffset(0, 0);
3495 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
3496 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
3497 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
3498 qglStencilMask(~0);CHECKGLERROR
3499 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
3500 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
3501 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
3502 R_SetupGenericShader(true);
3505 void R_ResetViewRendering3D(void)
3509 // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
3510 qglViewport(r_refdef.view.x, vid.height - (r_refdef.view.y + r_refdef.view.height), r_refdef.view.width, r_refdef.view.height);CHECKGLERROR
3512 GL_Scissor(r_refdef.view.x, vid.height - r_refdef.view.y - r_refdef.view.height, r_refdef.view.width, r_refdef.view.height);
3513 GL_Color(1, 1, 1, 1);
3514 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
3515 GL_BlendFunc(GL_ONE, GL_ZERO);
3516 GL_AlphaTest(false);
3517 GL_ScissorTest(true);
3519 GL_DepthRange(0, 1);
3521 R_Mesh_Matrix(&identitymatrix);
3522 R_Mesh_ResetTextureState();
3523 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
3524 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
3525 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
3526 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
3527 qglStencilMask(~0);CHECKGLERROR
3528 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
3529 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
3530 GL_CullFace(r_refdef.view.cullface_back);
3531 R_SetupGenericShader(true);
3534 void R_RenderScene(void);
3535 void R_RenderWaterPlanes(void);
3537 static void R_Water_StartFrame(void)
3540 int waterwidth, waterheight, texturewidth, textureheight;
3541 r_waterstate_waterplane_t *p;
3543 // set waterwidth and waterheight to the water resolution that will be
3544 // used (often less than the screen resolution for faster rendering)
3545 waterwidth = (int)bound(1, r_refdef.view.width * r_water_resolutionmultiplier.value, r_refdef.view.width);
3546 waterheight = (int)bound(1, r_refdef.view.height * r_water_resolutionmultiplier.value, r_refdef.view.height);
3548 // calculate desired texture sizes
3549 // can't use water if the card does not support the texture size
3550 if (!r_water.integer || !r_glsl.integer || !gl_support_fragment_shader || waterwidth > gl_max_texture_size || waterheight > gl_max_texture_size || r_showsurfaces.integer)
3551 texturewidth = textureheight = waterwidth = waterheight = 0;
3552 else if (gl_support_arb_texture_non_power_of_two)
3554 texturewidth = waterwidth;
3555 textureheight = waterheight;
3559 for (texturewidth = 1;texturewidth < waterwidth ;texturewidth *= 2);
3560 for (textureheight = 1;textureheight < waterheight;textureheight *= 2);
3563 // allocate textures as needed
3564 if (r_waterstate.waterwidth != waterwidth || r_waterstate.waterheight != waterheight || r_waterstate.texturewidth != texturewidth || r_waterstate.textureheight != textureheight)
3566 r_waterstate.maxwaterplanes = MAX_WATERPLANES;
3567 for (i = 0, p = r_waterstate.waterplanes;i < r_waterstate.maxwaterplanes;i++, p++)
3569 if (p->texture_refraction)
3570 R_FreeTexture(p->texture_refraction);
3571 p->texture_refraction = NULL;
3572 if (p->texture_reflection)
3573 R_FreeTexture(p->texture_reflection);
3574 p->texture_reflection = NULL;
3576 memset(&r_waterstate, 0, sizeof(r_waterstate));
3577 r_waterstate.waterwidth = waterwidth;
3578 r_waterstate.waterheight = waterheight;
3579 r_waterstate.texturewidth = texturewidth;
3580 r_waterstate.textureheight = textureheight;
3583 if (r_waterstate.waterwidth)
3585 r_waterstate.enabled = true;
3587 // set up variables that will be used in shader setup
3588 r_waterstate.screenscale[0] = 0.5f * (float)waterwidth / (float)texturewidth;
3589 r_waterstate.screenscale[1] = 0.5f * (float)waterheight / (float)textureheight;
3590 r_waterstate.screencenter[0] = 0.5f * (float)waterwidth / (float)texturewidth;
3591 r_waterstate.screencenter[1] = 0.5f * (float)waterheight / (float)textureheight;
3594 r_waterstate.maxwaterplanes = MAX_WATERPLANES;
3595 r_waterstate.numwaterplanes = 0;
3598 void R_Water_AddWaterPlane(msurface_t *surface)
3600 int triangleindex, planeindex;
3606 r_waterstate_waterplane_t *p;
3607 texture_t *t = R_GetCurrentTexture(surface->texture);
3608 // just use the first triangle with a valid normal for any decisions
3609 VectorClear(normal);
3610 for (triangleindex = 0, e = rsurface.modelelement3i + surface->num_firsttriangle * 3;triangleindex < surface->num_triangles;triangleindex++, e += 3)
3612 Matrix4x4_Transform(&rsurface.matrix, rsurface.modelvertex3f + e[0]*3, vert[0]);
3613 Matrix4x4_Transform(&rsurface.matrix, rsurface.modelvertex3f + e[1]*3, vert[1]);
3614 Matrix4x4_Transform(&rsurface.matrix, rsurface.modelvertex3f + e[2]*3, vert[2]);
3615 TriangleNormal(vert[0], vert[1], vert[2], normal);
3616 if (VectorLength2(normal) >= 0.001)
3620 VectorCopy(normal, plane.normal);
3621 VectorNormalize(plane.normal);
3622 plane.dist = DotProduct(vert[0], plane.normal);
3623 PlaneClassify(&plane);
3624 if (PlaneDiff(r_refdef.view.origin, &plane) < 0)
3626 // skip backfaces (except if nocullface is set)
3627 if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE))
3629 VectorNegate(plane.normal, plane.normal);
3631 PlaneClassify(&plane);
3635 // find a matching plane if there is one
3636 for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++)
3637 if (fabs(PlaneDiff(vert[0], &p->plane)) < 1 && fabs(PlaneDiff(vert[1], &p->plane)) < 1 && fabs(PlaneDiff(vert[2], &p->plane)) < 1)
3639 if (planeindex >= r_waterstate.maxwaterplanes)
3640 return; // nothing we can do, out of planes
3642 // if this triangle does not fit any known plane rendered this frame, add one
3643 if (planeindex >= r_waterstate.numwaterplanes)
3645 // store the new plane
3646 r_waterstate.numwaterplanes++;
3648 // clear materialflags and pvs
3649 p->materialflags = 0;
3650 p->pvsvalid = false;
3652 // merge this surface's materialflags into the waterplane
3653 p->materialflags |= t->currentmaterialflags;
3654 // merge this surface's PVS into the waterplane
3655 VectorMAM(0.5f, surface->mins, 0.5f, surface->maxs, center);
3656 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
3657 && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
3659 r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
3664 static void R_Water_ProcessPlanes(void)
3666 r_refdef_view_t originalview;
3667 r_refdef_view_t myview;
3669 r_waterstate_waterplane_t *p;
3671 originalview = r_refdef.view;
3673 // make sure enough textures are allocated
3674 for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++)
3676 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
3678 if (!p->texture_refraction)
3679 p->texture_refraction = R_LoadTexture2D(r_main_texturepool, va("waterplane%i_refraction", planeindex), r_waterstate.texturewidth, r_waterstate.textureheight, NULL, TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
3680 if (!p->texture_refraction)
3684 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
3686 if (!p->texture_reflection)
3687 p->texture_reflection = R_LoadTexture2D(r_main_texturepool, va("waterplane%i_reflection", planeindex), r_waterstate.texturewidth, r_waterstate.textureheight, NULL, TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
3688 if (!p->texture_reflection)
3694 r_refdef.view = originalview;
3695 r_refdef.view.showdebug = false;
3696 r_refdef.view.width = r_waterstate.waterwidth;
3697 r_refdef.view.height = r_waterstate.waterheight;
3698 r_refdef.view.useclipplane = true;
3699 myview = r_refdef.view;
3700 r_waterstate.renderingscene = true;
3701 for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++)
3703 // render the normal view scene and copy into texture
3704 // (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)
3705 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
3707 r_refdef.view = myview;
3708 r_refdef.view.clipplane = p->plane;
3709 VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
3710 r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
3711 PlaneClassify(&r_refdef.view.clipplane);
3713 R_ResetViewRendering3D();
3714 R_ClearScreen(r_refdef.fogenabled);
3718 // copy view into the screen texture
3719 R_Mesh_TexBind(0, R_GetTexture(p->texture_refraction));
3720 GL_ActiveTexture(0);
3722 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.x, vid.height - (r_refdef.view.y + r_refdef.view.height), r_refdef.view.width, r_refdef.view.height);CHECKGLERROR
3725 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
3727 r_refdef.view = myview;
3728 // render reflected scene and copy into texture
3729 Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
3730 // update the r_refdef.view.origin because otherwise the sky renders at the wrong location (amongst other problems)
3731 Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
3732 r_refdef.view.clipplane = p->plane;
3733 // reverse the cullface settings for this render
3734 r_refdef.view.cullface_front = GL_FRONT;
3735 r_refdef.view.cullface_back = GL_BACK;
3736 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
3738 r_refdef.view.usecustompvs = true;
3740 memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
3742 memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
3745 R_ResetViewRendering3D();
3746 R_ClearScreen(r_refdef.fogenabled);
3750 R_Mesh_TexBind(0, R_GetTexture(p->texture_reflection));
3751 GL_ActiveTexture(0);
3753 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.x, vid.height - (r_refdef.view.y + r_refdef.view.height), r_refdef.view.width, r_refdef.view.height);CHECKGLERROR
3756 r_waterstate.renderingscene = false;
3757 r_refdef.view = originalview;
3758 R_ResetViewRendering3D();
3759 R_ClearScreen(r_refdef.fogenabled);
3763 r_refdef.view = originalview;
3764 r_waterstate.renderingscene = false;
3765 Cvar_SetValueQuick(&r_water, 0);
3766 Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed! Turned off r_water.\n");
3770 void R_Bloom_StartFrame(void)
3772 int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight;
3774 // set bloomwidth and bloomheight to the bloom resolution that will be
3775 // used (often less than the screen resolution for faster rendering)
3776 r_bloomstate.bloomwidth = bound(1, r_bloom_resolution.integer, r_refdef.view.width);
3777 r_bloomstate.bloomheight = r_bloomstate.bloomwidth * r_refdef.view.height / r_refdef.view.width;
3778 r_bloomstate.bloomheight = bound(1, r_bloomstate.bloomheight, r_refdef.view.height);
3779 r_bloomstate.bloomwidth = min(r_bloomstate.bloomwidth, gl_max_texture_size);
3780 r_bloomstate.bloomheight = min(r_bloomstate.bloomheight, gl_max_texture_size);
3782 // calculate desired texture sizes
3783 if (gl_support_arb_texture_non_power_of_two)
3785 screentexturewidth = r_refdef.view.width;
3786 screentextureheight = r_refdef.view.height;
3787 bloomtexturewidth = r_bloomstate.bloomwidth;
3788 bloomtextureheight = r_bloomstate.bloomheight;
3792 for (screentexturewidth = 1;screentexturewidth < vid.width ;screentexturewidth *= 2);
3793 for (screentextureheight = 1;screentextureheight < vid.height ;screentextureheight *= 2);
3794 for (bloomtexturewidth = 1;bloomtexturewidth < r_bloomstate.bloomwidth ;bloomtexturewidth *= 2);
3795 for (bloomtextureheight = 1;bloomtextureheight < r_bloomstate.bloomheight;bloomtextureheight *= 2);
3798 if ((r_hdr.integer || r_bloom.integer || (!R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0))) && ((r_bloom_resolution.integer < 4 || r_bloom_blur.value < 1 || r_bloom_blur.value >= 512) || r_refdef.view.width > gl_max_texture_size || r_refdef.view.height > gl_max_texture_size))
3800 Cvar_SetValueQuick(&r_hdr, 0);
3801 Cvar_SetValueQuick(&r_bloom, 0);
3802 Cvar_SetValueQuick(&r_motionblur, 0);
3803 Cvar_SetValueQuick(&r_damageblur, 0);
3806 if (!(r_glsl.integer && (r_glsl_postprocess.integer || (!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) || (v_glslgamma.integer && !vid_gammatables_trivial))) && !r_bloom.integer && !r_hdr.integer && (R_Stereo_Active() || (r_motionblur.value <= 0 && r_damageblur.value <= 0)))
3807 screentexturewidth = screentextureheight = 0;
3808 if (!r_hdr.integer && !r_bloom.integer)
3809 bloomtexturewidth = bloomtextureheight = 0;
3811 // allocate textures as needed
3812 if (r_bloomstate.screentexturewidth != screentexturewidth || r_bloomstate.screentextureheight != screentextureheight)
3814 if (r_bloomstate.texture_screen)
3815 R_FreeTexture(r_bloomstate.texture_screen);
3816 r_bloomstate.texture_screen = NULL;
3817 r_bloomstate.screentexturewidth = screentexturewidth;
3818 r_bloomstate.screentextureheight = screentextureheight;
3819 if (r_bloomstate.screentexturewidth && r_bloomstate.screentextureheight)
3820 r_bloomstate.texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", r_bloomstate.screentexturewidth, r_bloomstate.screentextureheight, NULL, TEXTYPE_BGRA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
3822 if (r_bloomstate.bloomtexturewidth != bloomtexturewidth || r_bloomstate.bloomtextureheight != bloomtextureheight)
3824 if (r_bloomstate.texture_bloom)
3825 R_FreeTexture(r_bloomstate.texture_bloom);
3826 r_bloomstate.texture_bloom = NULL;
3827 r_bloomstate.bloomtexturewidth = bloomtexturewidth;
3828 r_bloomstate.bloomtextureheight = bloomtextureheight;
3829 if (r_bloomstate.bloomtexturewidth && r_bloomstate.bloomtextureheight)
3830 r_bloomstate.texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", r_bloomstate.bloomtexturewidth, r_bloomstate.bloomtextureheight, NULL, TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
3833 // set up a texcoord array for the full resolution screen image
3834 // (we have to keep this around to copy back during final render)
3835 r_bloomstate.screentexcoord2f[0] = 0;
3836 r_bloomstate.screentexcoord2f[1] = (float)r_refdef.view.height / (float)r_bloomstate.screentextureheight;
3837 r_bloomstate.screentexcoord2f[2] = (float)r_refdef.view.width / (float)r_bloomstate.screentexturewidth;
3838 r_bloomstate.screentexcoord2f[3] = (float)r_refdef.view.height / (float)r_bloomstate.screentextureheight;
3839 r_bloomstate.screentexcoord2f[4] = (float)r_refdef.view.width / (float)r_bloomstate.screentexturewidth;
3840 r_bloomstate.screentexcoord2f[5] = 0;
3841 r_bloomstate.screentexcoord2f[6] = 0;
3842 r_bloomstate.screentexcoord2f[7] = 0;
3844 // set up a texcoord array for the reduced resolution bloom image
3845 // (which will be additive blended over the screen image)
3846 r_bloomstate.bloomtexcoord2f[0] = 0;
3847 r_bloomstate.bloomtexcoord2f[1] = (float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
3848 r_bloomstate.bloomtexcoord2f[2] = (float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
3849 r_bloomstate.bloomtexcoord2f[3] = (float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
3850 r_bloomstate.bloomtexcoord2f[4] = (float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
3851 r_bloomstate.bloomtexcoord2f[5] = 0;
3852 r_bloomstate.bloomtexcoord2f[6] = 0;
3853 r_bloomstate.bloomtexcoord2f[7] = 0;
3855 if (r_hdr.integer || r_bloom.integer)
3857 r_bloomstate.enabled = true;
3858 r_bloomstate.hdr = r_hdr.integer != 0;
3862 void R_Bloom_CopyBloomTexture(float colorscale)
3864 r_refdef.stats.bloom++;
3866 // scale down screen texture to the bloom texture size
3868 qglViewport(r_refdef.view.x, vid.height - (r_refdef.view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
3869 GL_BlendFunc(GL_ONE, GL_ZERO);
3870 GL_Color(colorscale, colorscale, colorscale, 1);
3871 // TODO: optimize with multitexture or GLSL
3872 R_SetupGenericShader(true);
3873 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
3874 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
3875 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
3876 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
3878 // we now have a bloom image in the framebuffer
3879 // copy it into the bloom image texture for later processing
3880 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
3881 GL_ActiveTexture(0);
3883 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.x, vid.height - (r_refdef.view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
3884 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
3887 void R_Bloom_CopyHDRTexture(void)
3889 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
3890 GL_ActiveTexture(0);
3892 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.x, vid.height - (r_refdef.view.y + r_refdef.view.height), r_refdef.view.width, r_refdef.view.height);CHECKGLERROR
3893 r_refdef.stats.bloom_copypixels += r_refdef.view.width * r_refdef.view.height;
3896 void R_Bloom_MakeTexture(void)
3899 float xoffset, yoffset, r, brighten;
3901 r_refdef.stats.bloom++;
3903 R_ResetViewRendering2D();
3904 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
3905 R_Mesh_ColorPointer(NULL, 0, 0);
3906 R_SetupGenericShader(true);
3908 // we have a bloom image in the framebuffer
3910 qglViewport(r_refdef.view.x, vid.height - (r_refdef.view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
3912 for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
3915 r = bound(0, r_bloom_colorexponent.value / x, 1);
3916 GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
3917 GL_Color(r, r, r, 1);
3918 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
3919 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
3920 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
3921 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
3923 // copy the vertically blurred bloom view to a texture
3924 GL_ActiveTexture(0);
3926 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.x, vid.height - (r_refdef.view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
3927 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
3930 range = r_bloom_blur.integer * r_bloomstate.bloomwidth / 320;
3931 brighten = r_bloom_brighten.value;
3933 brighten *= r_hdr_range.value;
3934 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
3935 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.offsettexcoord2f, 0, 0);
3937 for (dir = 0;dir < 2;dir++)
3939 // blend on at multiple vertical offsets to achieve a vertical blur
3940 // TODO: do offset blends using GLSL
3941 GL_BlendFunc(GL_ONE, GL_ZERO);
3942 for (x = -range;x <= range;x++)
3944 if (!dir){xoffset = 0;yoffset = x;}
3945 else {xoffset = x;yoffset = 0;}
3946 xoffset /= (float)r_bloomstate.bloomtexturewidth;
3947 yoffset /= (float)r_bloomstate.bloomtextureheight;
3948 // compute a texcoord array with the specified x and y offset
3949 r_bloomstate.offsettexcoord2f[0] = xoffset+0;
3950 r_bloomstate.offsettexcoord2f[1] = yoffset+(float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
3951 r_bloomstate.offsettexcoord2f[2] = xoffset+(float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
3952 r_bloomstate.offsettexcoord2f[3] = yoffset+(float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
3953 r_bloomstate.offsettexcoord2f[4] = xoffset+(float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
3954 r_bloomstate.offsettexcoord2f[5] = yoffset+0;
3955 r_bloomstate.offsettexcoord2f[6] = xoffset+0;
3956 r_bloomstate.offsettexcoord2f[7] = yoffset+0;
3957 // this r value looks like a 'dot' particle, fading sharply to
3958 // black at the edges
3959 // (probably not realistic but looks good enough)
3960 //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
3961 //r = (dir ? 1.0f : brighten)/(range*2+1);
3962 r = (dir ? 1.0f : brighten)/(range*2+1)*(1 - x*x/(float)(range*range));
3963 GL_Color(r, r, r, 1);
3964 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
3965 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
3966 GL_BlendFunc(GL_ONE, GL_ONE);
3969 // copy the vertically blurred bloom view to a texture
3970 GL_ActiveTexture(0);
3972 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.x, vid.height - (r_refdef.view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
3973 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
3976 // apply subtract last
3977 // (just like it would be in a GLSL shader)
3978 if (r_bloom_colorsubtract.value > 0 && gl_support_ext_blend_subtract)
3980 GL_BlendFunc(GL_ONE, GL_ZERO);
3981 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
3982 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
3983 GL_Color(1, 1, 1, 1);
3984 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
3985 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
3987 GL_BlendFunc(GL_ONE, GL_ONE);
3988 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
3989 R_Mesh_TexBind(0, R_GetTexture(r_texture_white));
3990 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
3991 GL_Color(r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, 1);
3992 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
3993 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
3994 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
3996 // copy the darkened bloom view to a texture
3997 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
3998 GL_ActiveTexture(0);
4000 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.x, vid.height - (r_refdef.view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
4001 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
4005 void R_HDR_RenderBloomTexture(void)
4007 int oldwidth, oldheight;
4008 float oldcolorscale;
4010 oldcolorscale = r_refdef.view.colorscale;
4011 oldwidth = r_refdef.view.width;
4012 oldheight = r_refdef.view.height;
4013 r_refdef.view.width = r_bloomstate.bloomwidth;
4014 r_refdef.view.height = r_bloomstate.bloomheight;
4016 // TODO: support GL_EXT_framebuffer_object rather than reusing the framebuffer? it might improve SLI performance.
4017 // TODO: add exposure compensation features
4018 // TODO: add fp16 framebuffer support (using GL_EXT_framebuffer_object)
4020 r_refdef.view.showdebug = false;
4021 r_refdef.view.colorscale *= r_bloom_colorscale.value / bound(1, r_hdr_range.value, 16);
4023 R_ResetViewRendering3D();
4025 R_ClearScreen(r_refdef.fogenabled);
4026 if (r_timereport_active)
4027 R_TimeReport("HDRclear");
4030 if (r_timereport_active)
4031 R_TimeReport("visibility");
4033 r_waterstate.numwaterplanes = 0;
4034 if (r_waterstate.enabled)
4035 R_RenderWaterPlanes();
4037 r_refdef.view.showdebug = true;
4039 r_waterstate.numwaterplanes = 0;
4041 R_ResetViewRendering2D();
4043 R_Bloom_CopyHDRTexture();
4044 R_Bloom_MakeTexture();
4046 // restore the view settings
4047 r_refdef.view.width = oldwidth;
4048 r_refdef.view.height = oldheight;
4049 r_refdef.view.colorscale = oldcolorscale;
4051 R_ResetViewRendering3D();
4053 R_ClearScreen(r_refdef.fogenabled);
4054 if (r_timereport_active)
4055 R_TimeReport("viewclear");
4058 static void R_BlendView(void)
4060 if (r_bloomstate.texture_screen)
4062 // make sure the buffer is available
4063 if (r_bloom_blur.value < 1) { Cvar_SetValueQuick(&r_bloom_blur, 1); }
4065 R_ResetViewRendering2D();
4066 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4067 R_Mesh_ColorPointer(NULL, 0, 0);
4068 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
4069 GL_ActiveTexture(0);CHECKGLERROR
4071 if(!R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0))
4073 // declare variables
4075 static float avgspeed;
4077 speed = VectorLength(cl.movement_velocity);
4079 cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_vcoeff.value), 1);
4080 avgspeed = avgspeed * (1 - cl.motionbluralpha) + speed * cl.motionbluralpha;
4082 speed = (avgspeed - r_motionblur_vmin.value) / max(1, r_motionblur_vmax.value - r_motionblur_vmin.value);
4083 speed = bound(0, speed, 1);
4084 speed = speed * (1 - r_motionblur_bmin.value) + r_motionblur_bmin.value;
4086 // calculate values into a standard alpha
4087 cl.motionbluralpha = 1 - exp(-
4089 (r_motionblur.value * speed / 80)
4091 (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
4094 max(0.0001, cl.time - cl.oldtime) // fps independent
4097 cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
4098 cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
4100 if (cl.motionbluralpha > 0)
4102 R_SetupGenericShader(true);
4103 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4104 GL_Color(1, 1, 1, cl.motionbluralpha);
4105 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
4106 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
4107 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
4108 r_refdef.stats.bloom_drawpixels += r_refdef.view.width * r_refdef.view.height;
4112 // copy view into the screen texture
4113 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_refdef.view.x, vid.height - (r_refdef.view.y + r_refdef.view.height), r_refdef.view.width, r_refdef.view.height);CHECKGLERROR
4114 r_refdef.stats.bloom_copypixels += r_refdef.view.width * r_refdef.view.height;
4117 if (r_glsl.integer && gl_support_fragment_shader && (r_bloomstate.texture_screen || r_bloomstate.texture_bloom))
4119 unsigned int permutation =
4120 (r_bloomstate.texture_bloom ? SHADERPERMUTATION_BLOOM : 0)
4121 | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
4122 | ((v_glslgamma.value && !vid_gammatables_trivial) ? SHADERPERMUTATION_GAMMARAMPS : 0)
4123 | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
4124 | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
4126 if (r_bloomstate.texture_bloom && !r_bloomstate.hdr)
4128 // render simple bloom effect
4129 // copy the screen and shrink it and darken it for the bloom process
4130 R_Bloom_CopyBloomTexture(r_bloom_colorscale.value);
4131 // make the bloom texture
4132 R_Bloom_MakeTexture();
4135 R_ResetViewRendering2D();
4136 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4137 R_Mesh_ColorPointer(NULL, 0, 0);
4138 GL_Color(1, 1, 1, 1);
4139 GL_BlendFunc(GL_ONE, GL_ZERO);
4140 R_SetupShader_SetPermutation(SHADERMODE_POSTPROCESS, permutation);
4141 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
4142 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
4143 R_Mesh_TexBind(1, R_GetTexture(r_bloomstate.texture_bloom));
4144 R_Mesh_TexCoordPointer(1, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
4145 if (r_glsl_permutation->loc_Texture_GammaRamps >= 0)
4146 R_Mesh_TexBind(GL20TU_GAMMARAMPS, R_GetTexture(r_texture_gammaramps));
4147 if (r_glsl_permutation->loc_TintColor >= 0)
4148 qglUniform4fARB(r_glsl_permutation->loc_TintColor, r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
4149 if (r_glsl_permutation->loc_ClientTime >= 0)
4150 qglUniform1fARB(r_glsl_permutation->loc_ClientTime, cl.time);
4151 if (r_glsl_permutation->loc_PixelSize >= 0)
4152 qglUniform2fARB(r_glsl_permutation->loc_PixelSize, 1.0/r_bloomstate.screentexturewidth, 1.0/r_bloomstate.screentextureheight);
4153 if (r_glsl_permutation->loc_UserVec1 >= 0)
4155 float a=0, b=0, c=0, d=0;
4156 #if _MSC_VER >= 1400
4157 #define sscanf sscanf_s
4159 sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &a, &b, &c, &d);
4160 qglUniform4fARB(r_glsl_permutation->loc_UserVec1, a, b, c, d);
4162 if (r_glsl_permutation->loc_UserVec2 >= 0)
4164 float a=0, b=0, c=0, d=0;
4165 sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &a, &b, &c, &d);
4166 qglUniform4fARB(r_glsl_permutation->loc_UserVec2, a, b, c, d);
4168 if (r_glsl_permutation->loc_UserVec3 >= 0)
4170 float a=0, b=0, c=0, d=0;
4171 sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &a, &b, &c, &d);
4172 qglUniform4fARB(r_glsl_permutation->loc_UserVec3, a, b, c, d);
4174 if (r_glsl_permutation->loc_UserVec4 >= 0)
4176 float a=0, b=0, c=0, d=0;
4177 sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &a, &b, &c, &d);
4178 qglUniform4fARB(r_glsl_permutation->loc_UserVec4, a, b, c, d);
4180 if (r_glsl_permutation->loc_Saturation >= 0)
4181 qglUniform1fARB(r_glsl_permutation->loc_Saturation, r_glsl_saturation.value);
4182 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
4183 r_refdef.stats.bloom_drawpixels += r_refdef.view.width * r_refdef.view.height;
4189 if (r_bloomstate.texture_bloom && r_bloomstate.hdr)
4191 // render high dynamic range bloom effect
4192 // the bloom texture was made earlier this render, so we just need to
4193 // blend it onto the screen...
4194 R_ResetViewRendering2D();
4195 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4196 R_Mesh_ColorPointer(NULL, 0, 0);
4197 R_SetupGenericShader(true);
4198 GL_Color(1, 1, 1, 1);
4199 GL_BlendFunc(GL_ONE, GL_ONE);
4200 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
4201 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
4202 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
4203 r_refdef.stats.bloom_drawpixels += r_refdef.view.width * r_refdef.view.height;
4205 else if (r_bloomstate.texture_bloom)
4207 // render simple bloom effect
4208 // copy the screen and shrink it and darken it for the bloom process
4209 R_Bloom_CopyBloomTexture(r_bloom_colorscale.value);
4210 // make the bloom texture
4211 R_Bloom_MakeTexture();
4212 // put the original screen image back in place and blend the bloom
4214 R_ResetViewRendering2D();
4215 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4216 R_Mesh_ColorPointer(NULL, 0, 0);
4217 GL_Color(1, 1, 1, 1);
4218 GL_BlendFunc(GL_ONE, GL_ZERO);
4219 // do both in one pass if possible
4220 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
4221 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
4222 if (r_textureunits.integer >= 2 && gl_combine.integer)
4224 R_SetupGenericTwoTextureShader(GL_ADD);
4225 R_Mesh_TexBind(1, R_GetTexture(r_bloomstate.texture_screen));
4226 R_Mesh_TexCoordPointer(1, 2, r_bloomstate.screentexcoord2f, 0, 0);
4230 R_SetupGenericShader(true);
4231 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
4232 r_refdef.stats.bloom_drawpixels += r_refdef.view.width * r_refdef.view.height;
4233 // now blend on the bloom texture
4234 GL_BlendFunc(GL_ONE, GL_ONE);
4235 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
4236 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
4238 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
4239 r_refdef.stats.bloom_drawpixels += r_refdef.view.width * r_refdef.view.height;
4241 if (r_refdef.viewblend[3] >= (1.0f / 256.0f))
4243 // apply a color tint to the whole view
4244 R_ResetViewRendering2D();
4245 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
4246 R_Mesh_ColorPointer(NULL, 0, 0);
4247 R_SetupGenericShader(false);
4248 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4249 GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
4250 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
4254 matrix4x4_t r_waterscrollmatrix;
4256 void R_UpdateFogColor(void) // needs to be called before HDR subrender too, as that changes colorscale!
4258 if (r_refdef.fog_density)
4260 r_refdef.fogcolor[0] = r_refdef.fog_red;
4261 r_refdef.fogcolor[1] = r_refdef.fog_green;
4262 r_refdef.fogcolor[2] = r_refdef.fog_blue;
4266 VectorCopy(r_refdef.fogcolor, fogvec);
4267 // color.rgb *= ContrastBoost * SceneBrightness;
4268 VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
4269 r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
4270 r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f);
4271 r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f);
4276 void R_UpdateVariables(void)
4280 r_refdef.scene.ambient = r_ambient.value;
4282 r_refdef.farclip = 4096;
4283 if (r_refdef.scene.worldmodel)
4284 r_refdef.farclip += r_refdef.scene.worldmodel->radius * 2;
4285 r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
4287 if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
4288 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
4289 r_refdef.polygonfactor = 0;
4290 r_refdef.polygonoffset = 0;
4291 r_refdef.shadowpolygonfactor = r_refdef.polygonfactor + r_shadow_polygonfactor.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
4292 r_refdef.shadowpolygonoffset = r_refdef.polygonoffset + r_shadow_polygonoffset.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
4294 r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
4295 r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
4296 r_refdef.scene.rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer && r_dynamic.integer;
4297 r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && gl_stencil;
4298 r_refdef.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
4299 if (r_showsurfaces.integer)
4301 r_refdef.scene.rtworld = false;
4302 r_refdef.scene.rtworldshadows = false;
4303 r_refdef.scene.rtdlight = false;
4304 r_refdef.scene.rtdlightshadows = false;
4305 r_refdef.lightmapintensity = 0;
4308 if (gamemode == GAME_NEHAHRA)
4310 if (gl_fogenable.integer)
4312 r_refdef.oldgl_fogenable = true;
4313 r_refdef.fog_density = gl_fogdensity.value;
4314 r_refdef.fog_red = gl_fogred.value;
4315 r_refdef.fog_green = gl_foggreen.value;
4316 r_refdef.fog_blue = gl_fogblue.value;
4317 r_refdef.fog_alpha = 1;
4318 r_refdef.fog_start = 0;
4319 r_refdef.fog_end = gl_skyclip.value;
4321 else if (r_refdef.oldgl_fogenable)
4323 r_refdef.oldgl_fogenable = false;
4324 r_refdef.fog_density = 0;
4325 r_refdef.fog_red = 0;
4326 r_refdef.fog_green = 0;
4327 r_refdef.fog_blue = 0;
4328 r_refdef.fog_alpha = 0;
4329 r_refdef.fog_start = 0;
4330 r_refdef.fog_end = 0;
4334 r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1);
4335 r_refdef.fog_start = max(0, r_refdef.fog_start);
4336 r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end);
4338 // R_UpdateFogColor(); // why? R_RenderScene does it anyway
4340 if (r_refdef.fog_density && r_drawfog.integer)
4342 r_refdef.fogenabled = true;
4343 // this is the point where the fog reaches 0.9986 alpha, which we
4344 // consider a good enough cutoff point for the texture
4345 // (0.9986 * 256 == 255.6)
4346 if (r_fog_exp2.integer)
4347 r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start;
4349 r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start;
4350 r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end);
4351 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
4352 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
4353 // fog color was already set
4354 // update the fog texture
4355 if (r_refdef.fogmasktable_start != r_refdef.fog_start || r_refdef.fogmasktable_alpha != r_refdef.fog_alpha || r_refdef.fogmasktable_density != r_refdef.fog_density || r_refdef.fogmasktable_range != r_refdef.fogrange)
4356 R_BuildFogTexture();
4359 r_refdef.fogenabled = false;
4361 if(r_glsl.integer && v_glslgamma.integer && !vid_gammatables_trivial)
4363 if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
4365 // build GLSL gamma texture
4366 #define RAMPWIDTH 256
4367 unsigned short ramp[RAMPWIDTH * 3];
4368 unsigned char rampbgr[RAMPWIDTH][4];
4371 r_texture_gammaramps_serial = vid_gammatables_serial;
4373 VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
4374 for(i = 0; i < RAMPWIDTH; ++i)
4376 rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
4377 rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
4378 rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
4381 if (r_texture_gammaramps)
4383 R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, RAMPWIDTH, 1);
4387 r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_PRECACHE | TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, NULL);
4393 // remove GLSL gamma texture
4397 static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT;
4398 static r_refdef_scene_t r_scenes_store[ RST_COUNT ];
4404 void R_SelectScene( r_refdef_scene_type_t scenetype ) {
4405 if( scenetype != r_currentscenetype ) {
4406 // store the old scenetype
4407 r_scenes_store[ r_currentscenetype ] = r_refdef.scene;
4408 r_currentscenetype = scenetype;
4409 // move in the new scene
4410 r_refdef.scene = r_scenes_store[ r_currentscenetype ];
4419 r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype )
4421 // of course, we could also add a qboolean that provides a lock state and a ReleaseScenePointer function..
4422 if( scenetype == r_currentscenetype ) {
4423 return &r_refdef.scene;
4425 return &r_scenes_store[ scenetype ];
4434 void R_RenderView(void)
4436 if (r_timereport_active)
4437 R_TimeReport("start");
4438 r_frame++; // used only by R_GetCurrentTexture
4439 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
4441 R_AnimCache_NewFrame();
4443 if (r_refdef.view.isoverlay)
4445 // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
4446 GL_Clear( GL_DEPTH_BUFFER_BIT );
4447 R_TimeReport("depthclear");
4449 r_refdef.view.showdebug = false;
4451 r_waterstate.enabled = false;
4452 r_waterstate.numwaterplanes = 0;
4460 if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0/* || !r_refdef.scene.worldmodel*/)
4461 return; //Host_Error ("R_RenderView: NULL worldmodel");
4463 r_refdef.view.colorscale = r_hdr_scenebrightness.value;
4465 // break apart the view matrix into vectors for various purposes
4466 // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
4467 // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc
4468 Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
4469 VectorNegate(r_refdef.view.left, r_refdef.view.right);
4470 // make an inverted copy of the view matrix for tracking sprites
4471 Matrix4x4_Invert_Simple(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
4473 R_Shadow_UpdateWorldLightSelection();
4475 R_Bloom_StartFrame();
4476 R_Water_StartFrame();
4479 if (r_timereport_active)
4480 R_TimeReport("viewsetup");
4482 R_ResetViewRendering3D();
4484 if (r_refdef.view.clear || r_refdef.fogenabled)
4486 R_ClearScreen(r_refdef.fogenabled);
4487 if (r_timereport_active)
4488 R_TimeReport("viewclear");
4490 r_refdef.view.clear = true;
4492 // this produces a bloom texture to be used in R_BlendView() later
4494 R_HDR_RenderBloomTexture();
4496 r_refdef.view.showdebug = true;
4499 if (r_timereport_active)
4500 R_TimeReport("visibility");
4502 r_waterstate.numwaterplanes = 0;
4503 if (r_waterstate.enabled)
4504 R_RenderWaterPlanes();
4507 r_waterstate.numwaterplanes = 0;
4510 if (r_timereport_active)
4511 R_TimeReport("blendview");
4513 GL_Scissor(0, 0, vid.width, vid.height);
4514 GL_ScissorTest(false);
4518 void R_RenderWaterPlanes(void)
4520 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
4522 r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity);
4523 if (r_timereport_active)
4524 R_TimeReport("waterworld");
4527 // don't let sound skip if going slow
4528 if (r_refdef.scene.extraupdate)
4531 R_DrawModelsAddWaterPlanes();
4532 if (r_timereport_active)
4533 R_TimeReport("watermodels");
4535 if (r_waterstate.numwaterplanes)
4537 R_Water_ProcessPlanes();
4538 if (r_timereport_active)
4539 R_TimeReport("waterscenes");
4543 extern void R_DrawLightningBeams (void);
4544 extern void VM_CL_AddPolygonsToMeshQueue (void);
4545 extern void R_DrawPortals (void);
4546 extern cvar_t cl_locs_show;
4547 static void R_DrawLocs(void);
4548 static void R_DrawEntityBBoxes(void);
4549 void R_RenderScene(void)
4551 r_refdef.stats.renders++;
4555 // don't let sound skip if going slow
4556 if (r_refdef.scene.extraupdate)
4559 R_MeshQueue_BeginScene();
4563 Matrix4x4_CreateTranslate(&r_waterscrollmatrix, sin(r_refdef.scene.time) * 0.025 * r_waterscroll.value, sin(r_refdef.scene.time * 0.8f) * 0.025 * r_waterscroll.value, 0);
4565 if (cl.csqc_vidvars.drawworld)
4567 // don't let sound skip if going slow
4568 if (r_refdef.scene.extraupdate)
4571 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawSky)
4573 r_refdef.scene.worldmodel->DrawSky(r_refdef.scene.worldentity);
4574 if (r_timereport_active)
4575 R_TimeReport("worldsky");
4578 if (R_DrawBrushModelsSky() && r_timereport_active)
4579 R_TimeReport("bmodelsky");
4582 R_AnimCache_CacheVisibleEntities();
4584 if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
4586 r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
4587 if (r_timereport_active)
4588 R_TimeReport("worlddepth");
4590 if (r_depthfirst.integer >= 2)
4592 R_DrawModelsDepth();
4593 if (r_timereport_active)
4594 R_TimeReport("modeldepth");
4597 if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
4599 r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
4600 if (r_timereport_active)
4601 R_TimeReport("world");
4604 // don't let sound skip if going slow
4605 if (r_refdef.scene.extraupdate)
4609 if (r_timereport_active)
4610 R_TimeReport("models");
4612 // don't let sound skip if going slow
4613 if (r_refdef.scene.extraupdate)
4616 if (r_shadows.integer > 0 && !r_shadows_drawafterrtlightning.integer && r_refdef.lightmapintensity > 0)
4618 R_DrawModelShadows();
4619 R_ResetViewRendering3D();
4620 // don't let sound skip if going slow
4621 if (r_refdef.scene.extraupdate)
4625 R_ShadowVolumeLighting(false);
4626 if (r_timereport_active)
4627 R_TimeReport("rtlights");
4629 // don't let sound skip if going slow
4630 if (r_refdef.scene.extraupdate)
4633 if (r_shadows.integer > 0 && r_shadows_drawafterrtlightning.integer && r_refdef.lightmapintensity > 0)
4635 R_DrawModelShadows();
4636 R_ResetViewRendering3D();
4637 // don't let sound skip if going slow
4638 if (r_refdef.scene.extraupdate)
4642 if (cl.csqc_vidvars.drawworld)
4644 R_DrawLightningBeams();
4645 if (r_timereport_active)
4646 R_TimeReport("lightning");
4649 if (r_timereport_active)
4650 R_TimeReport("decals");
4653 if (r_timereport_active)
4654 R_TimeReport("particles");
4657 if (r_timereport_active)
4658 R_TimeReport("explosions");
4661 R_SetupGenericShader(true);
4662 VM_CL_AddPolygonsToMeshQueue();
4664 if (r_refdef.view.showdebug)
4666 if (cl_locs_show.integer)
4669 if (r_timereport_active)
4670 R_TimeReport("showlocs");
4673 if (r_drawportals.integer)
4676 if (r_timereport_active)
4677 R_TimeReport("portals");
4680 if (r_showbboxes.value > 0)
4682 R_DrawEntityBBoxes();
4683 if (r_timereport_active)
4684 R_TimeReport("bboxes");
4688 R_SetupGenericShader(true);
4689 R_MeshQueue_RenderTransparent();
4690 if (r_timereport_active)
4691 R_TimeReport("drawtrans");
4693 R_SetupGenericShader(true);
4695 if (r_refdef.view.showdebug && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDebug && (r_showtris.value > 0 || r_shownormals.value != 0 || r_showcollisionbrushes.value > 0))
4697 r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity);
4698 if (r_timereport_active)
4699 R_TimeReport("worlddebug");
4700 R_DrawModelsDebug();
4701 if (r_timereport_active)
4702 R_TimeReport("modeldebug");
4705 R_SetupGenericShader(true);
4707 if (cl.csqc_vidvars.drawworld)
4710 if (r_timereport_active)
4711 R_TimeReport("coronas");
4714 // don't let sound skip if going slow
4715 if (r_refdef.scene.extraupdate)
4718 R_ResetViewRendering2D();
4721 static const unsigned short bboxelements[36] =
4731 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
4734 float *v, *c, f1, f2, vertex3f[8*3], color4f[8*4];
4735 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4736 GL_DepthMask(false);
4737 GL_DepthRange(0, 1);
4738 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4739 R_Mesh_Matrix(&identitymatrix);
4740 R_Mesh_ResetTextureState();
4742 vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2]; //
4743 vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
4744 vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
4745 vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
4746 vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
4747 vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
4748 vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
4749 vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
4750 R_FillColors(color4f, 8, cr, cg, cb, ca);
4751 if (r_refdef.fogenabled)
4753 for (i = 0, v = vertex3f, c = color4f;i < 8;i++, v += 3, c += 4)
4755 f1 = FogPoint_World(v);
4757 c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
4758 c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
4759 c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
4762 R_Mesh_VertexPointer(vertex3f, 0, 0);
4763 R_Mesh_ColorPointer(color4f, 0, 0);
4764 R_Mesh_ResetTextureState();
4765 R_SetupGenericShader(false);
4766 R_Mesh_Draw(0, 8, 0, 12, NULL, bboxelements, 0, 0);
4769 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4773 prvm_edict_t *edict;
4774 prvm_prog_t *prog_save = prog;
4776 // this function draws bounding boxes of server entities
4780 GL_CullFace(GL_NONE);
4781 R_SetupGenericShader(false);
4785 for (i = 0;i < numsurfaces;i++)
4787 edict = PRVM_EDICT_NUM(surfacelist[i]);
4788 switch ((int)edict->fields.server->solid)
4790 case SOLID_NOT: Vector4Set(color, 1, 1, 1, 0.05);break;
4791 case SOLID_TRIGGER: Vector4Set(color, 1, 0, 1, 0.10);break;
4792 case SOLID_BBOX: Vector4Set(color, 0, 1, 0, 0.10);break;
4793 case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
4794 case SOLID_BSP: Vector4Set(color, 0, 0, 1, 0.05);break;
4795 default: Vector4Set(color, 0, 0, 0, 0.50);break;
4797 color[3] *= r_showbboxes.value;
4798 color[3] = bound(0, color[3], 1);
4799 GL_DepthTest(!r_showdisabledepthtest.integer);
4800 GL_CullFace(r_refdef.view.cullface_front);
4801 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
4807 static void R_DrawEntityBBoxes(void)
4810 prvm_edict_t *edict;
4812 prvm_prog_t *prog_save = prog;
4814 // this function draws bounding boxes of server entities
4820 for (i = 0;i < prog->num_edicts;i++)
4822 edict = PRVM_EDICT_NUM(i);
4823 if (edict->priv.server->free)
4825 // exclude the following for now, as they don't live in world coordinate space and can't be solid:
4826 if(PRVM_EDICTFIELDVALUE(edict, prog->fieldoffsets.tag_entity)->edict != 0)
4828 if(PRVM_EDICTFIELDVALUE(edict, prog->fieldoffsets.viewmodelforclient)->edict != 0)
4830 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
4831 R_MeshQueue_AddTransparent(center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)NULL);
4837 unsigned short nomodelelements[24] =
4849 float nomodelvertex3f[6*3] =
4859 float nomodelcolor4f[6*4] =
4861 0.0f, 0.0f, 0.5f, 1.0f,
4862 0.0f, 0.0f, 0.5f, 1.0f,
4863 0.0f, 0.5f, 0.0f, 1.0f,
4864 0.0f, 0.5f, 0.0f, 1.0f,
4865 0.5f, 0.0f, 0.0f, 1.0f,
4866 0.5f, 0.0f, 0.0f, 1.0f
4869 void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
4874 // this is only called once per entity so numsurfaces is always 1, and
4875 // surfacelist is always {0}, so this code does not handle batches
4876 R_Mesh_Matrix(&ent->matrix);
4878 if (ent->flags & EF_ADDITIVE)
4880 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
4881 GL_DepthMask(false);
4883 else if (ent->alpha < 1)
4885 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4886 GL_DepthMask(false);
4890 GL_BlendFunc(GL_ONE, GL_ZERO);
4893 GL_DepthRange(0, (ent->flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
4894 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4895 GL_DepthTest(!(ent->effects & EF_NODEPTHTEST));
4896 GL_CullFace((ent->effects & EF_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
4897 R_SetupGenericShader(false);
4898 R_Mesh_VertexPointer(nomodelvertex3f, 0, 0);
4899 if (r_refdef.fogenabled)
4902 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
4903 R_Mesh_ColorPointer(color4f, 0, 0);
4904 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4905 f1 = FogPoint_World(org);
4907 for (i = 0, c = color4f;i < 6;i++, c += 4)
4909 c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
4910 c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
4911 c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
4915 else if (ent->alpha != 1)
4917 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
4918 R_Mesh_ColorPointer(color4f, 0, 0);
4919 for (i = 0, c = color4f;i < 6;i++, c += 4)
4923 R_Mesh_ColorPointer(nomodelcolor4f, 0, 0);
4924 R_Mesh_ResetTextureState();
4925 R_Mesh_Draw(0, 6, 0, 8, NULL, nomodelelements, 0, 0);
4928 void R_DrawNoModel(entity_render_t *ent)
4931 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
4932 //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
4933 R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_refdef.view.origin : org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
4935 // R_DrawNoModelCallback(ent, 0);
4938 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
4940 vec3_t right1, right2, diff, normal;
4942 VectorSubtract (org2, org1, normal);
4944 // calculate 'right' vector for start
4945 VectorSubtract (r_refdef.view.origin, org1, diff);
4946 CrossProduct (normal, diff, right1);
4947 VectorNormalize (right1);
4949 // calculate 'right' vector for end
4950 VectorSubtract (r_refdef.view.origin, org2, diff);
4951 CrossProduct (normal, diff, right2);
4952 VectorNormalize (right2);
4954 vert[ 0] = org1[0] + width * right1[0];
4955 vert[ 1] = org1[1] + width * right1[1];
4956 vert[ 2] = org1[2] + width * right1[2];
4957 vert[ 3] = org1[0] - width * right1[0];
4958 vert[ 4] = org1[1] - width * right1[1];
4959 vert[ 5] = org1[2] - width * right1[2];
4960 vert[ 6] = org2[0] - width * right2[0];
4961 vert[ 7] = org2[1] - width * right2[1];
4962 vert[ 8] = org2[2] - width * right2[2];
4963 vert[ 9] = org2[0] + width * right2[0];
4964 vert[10] = org2[1] + width * right2[1];
4965 vert[11] = org2[2] + width * right2[2];
4968 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
4970 void R_DrawSprite(int blendfunc1, int blendfunc2, rtexture_t *texture, rtexture_t *fogtexture, qboolean depthdisable, qboolean depthshort, const vec3_t origin, const vec3_t left, const vec3_t up, float scalex1, float scalex2, float scaley1, float scaley2, float cr, float cg, float cb, float ca)
4972 // NOTE: this must not call qglDepthFunc (see r_shadow.c, R_BeginCoronaQuery) thanks to ATI
4976 if (r_refdef.fogenabled && !depthdisable) // TODO maybe make the unfog effect a separate flag?
4977 fog = FogPoint_World(origin);
4979 R_Mesh_Matrix(&identitymatrix);
4980 GL_BlendFunc(blendfunc1, blendfunc2);
4982 GL_CullFace(GL_NONE);
4984 GL_DepthMask(false);
4985 GL_DepthRange(0, depthshort ? 0.0625 : 1);
4986 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4987 GL_DepthTest(!depthdisable);
4989 vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
4990 vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
4991 vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
4992 vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
4993 vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
4994 vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
4995 vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
4996 vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
4997 vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
4998 vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
4999 vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
5000 vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
5002 R_Mesh_VertexPointer(vertex3f, 0, 0);
5003 R_Mesh_ColorPointer(NULL, 0, 0);
5004 R_Mesh_ResetTextureState();
5005 R_SetupGenericShader(true);
5006 R_Mesh_TexBind(0, R_GetTexture(texture));
5007 R_Mesh_TexCoordPointer(0, 2, spritetexcoord2f, 0, 0);
5008 // FIXME: fixed function path can't properly handle r_refdef.view.colorscale > 1
5009 GL_Color(cr * fog * r_refdef.view.colorscale, cg * fog * r_refdef.view.colorscale, cb * fog * r_refdef.view.colorscale, ca);
5010 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
5012 if (blendfunc2 == GL_ONE_MINUS_SRC_ALPHA)
5014 R_Mesh_TexBind(0, R_GetTexture(fogtexture));
5015 GL_BlendFunc(blendfunc1, GL_ONE);
5017 GL_Color(r_refdef.fogcolor[0] * fog, r_refdef.fogcolor[1] * fog, r_refdef.fogcolor[2] * fog, ca);
5018 R_Mesh_Draw(0, 4, 0, 2, NULL, polygonelements, 0, 0);
5022 int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
5027 VectorSet(v, x, y, z);
5028 for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
5029 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
5031 if (i == mesh->numvertices)
5033 if (mesh->numvertices < mesh->maxvertices)
5035 VectorCopy(v, vertex3f);
5036 mesh->numvertices++;
5038 return mesh->numvertices;
5044 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
5048 element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
5049 element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
5050 e = mesh->element3i + mesh->numtriangles * 3;
5051 for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
5053 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
5054 if (mesh->numtriangles < mesh->maxtriangles)
5059 mesh->numtriangles++;
5061 element[1] = element[2];
5065 void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
5069 element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
5070 element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
5071 e = mesh->element3i + mesh->numtriangles * 3;
5072 for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
5074 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
5075 if (mesh->numtriangles < mesh->maxtriangles)
5080 mesh->numtriangles++;
5082 element[1] = element[2];
5086 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
5087 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
5089 int planenum, planenum2;
5092 mplane_t *plane, *plane2;
5094 double temppoints[2][256*3];
5095 // figure out how large a bounding box we need to properly compute this brush
5097 for (w = 0;w < numplanes;w++)
5098 maxdist = max(maxdist, planes[w].dist);
5099 // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
5100 maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
5101 for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
5105 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
5106 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
5108 if (planenum2 == planenum)
5110 PolygonD_Divide(tempnumpoints, temppoints[w], plane2->normal[0], plane2->normal[1], plane2->normal[2], plane2->dist, R_MESH_PLANE_DIST_EPSILON, 0, NULL, NULL, 256, temppoints[!w], &tempnumpoints, NULL);
5113 if (tempnumpoints < 3)
5115 // generate elements forming a triangle fan for this polygon
5116 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
5120 static void R_Texture_AddLayer(texture_t *t, qboolean depthmask, int blendfunc1, int blendfunc2, texturelayertype_t type, rtexture_t *texture, const matrix4x4_t *matrix, float r, float g, float b, float a)
5122 texturelayer_t *layer;
5123 layer = t->currentlayers + t->currentnumlayers++;
5125 layer->depthmask = depthmask;
5126 layer->blendfunc1 = blendfunc1;
5127 layer->blendfunc2 = blendfunc2;
5128 layer->texture = texture;
5129 layer->texmatrix = *matrix;
5130 layer->color[0] = r * r_refdef.view.colorscale;
5131 layer->color[1] = g * r_refdef.view.colorscale;
5132 layer->color[2] = b * r_refdef.view.colorscale;
5133 layer->color[3] = a;
5136 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
5139 index = parms[2] + r_refdef.scene.time * parms[3];
5140 index -= floor(index);
5144 case Q3WAVEFUNC_NONE:
5145 case Q3WAVEFUNC_NOISE:
5146 case Q3WAVEFUNC_COUNT:
5149 case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
5150 case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
5151 case Q3WAVEFUNC_SAWTOOTH: f = index;break;
5152 case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
5153 case Q3WAVEFUNC_TRIANGLE:
5155 f = index - floor(index);
5166 return (float)(parms[0] + parms[1] * f);
5169 void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
5174 matrix4x4_t matrix, temp;
5175 switch(tcmod->tcmod)
5179 if (currentmaterialflags & MATERIALFLAG_WATERSCROLL)
5180 matrix = r_waterscrollmatrix;
5182 matrix = identitymatrix;
5184 case Q3TCMOD_ENTITYTRANSLATE:
5185 // this is used in Q3 to allow the gamecode to control texcoord
5186 // scrolling on the entity, which is not supported in darkplaces yet.
5187 Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
5189 case Q3TCMOD_ROTATE:
5190 Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
5191 Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * r_refdef.scene.time, 0, 0, 1);
5192 Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
5195 Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
5197 case Q3TCMOD_SCROLL:
5198 Matrix4x4_CreateTranslate(&matrix, tcmod->parms[0] * r_refdef.scene.time, tcmod->parms[1] * r_refdef.scene.time, 0);
5200 case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
5201 w = (int) tcmod->parms[0];
5202 h = (int) tcmod->parms[1];
5203 f = r_refdef.scene.time / (tcmod->parms[2] * w * h);
5205 idx = (int) floor(f * w * h);
5206 Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
5208 case Q3TCMOD_STRETCH:
5209 f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
5210 Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
5212 case Q3TCMOD_TRANSFORM:
5213 VectorSet(tcmat + 0, tcmod->parms[0], tcmod->parms[1], 0);
5214 VectorSet(tcmat + 3, tcmod->parms[2], tcmod->parms[3], 0);
5215 VectorSet(tcmat + 6, 0 , 0 , 1);
5216 VectorSet(tcmat + 9, tcmod->parms[4], tcmod->parms[5], 0);
5217 Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
5219 case Q3TCMOD_TURBULENT:
5220 // this is handled in the RSurf_PrepareVertices function
5221 matrix = identitymatrix;
5225 Matrix4x4_Concat(texmatrix, &matrix, &temp);
5228 texture_t *R_GetCurrentTexture(texture_t *t)
5231 const entity_render_t *ent = rsurface.entity;
5232 dp_model_t *model = ent->model;
5233 q3shaderinfo_layer_tcmod_t *tcmod;
5235 if (t->update_lastrenderframe == r_frame && t->update_lastrenderentity == (void *)ent)
5236 return t->currentframe;
5237 t->update_lastrenderframe = r_frame;
5238 t->update_lastrenderentity = (void *)ent;
5240 // switch to an alternate material if this is a q1bsp animated material
5242 texture_t *texture = t;
5243 int s = ent->skinnum;
5244 if ((unsigned int)s >= (unsigned int)model->numskins)
5246 if (model->skinscenes)
5248 if (model->skinscenes[s].framecount > 1)
5249 s = model->skinscenes[s].firstframe + (unsigned int) (r_refdef.scene.time * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
5251 s = model->skinscenes[s].firstframe;
5254 t = t + s * model->num_surfaces;
5257 // use an alternate animation if the entity's frame is not 0,
5258 // and only if the texture has an alternate animation
5259 if (ent->framegroupblend[0].frame != 0 && t->anim_total[1])
5260 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(r_refdef.scene.time * 5.0f) % t->anim_total[1]) : 0];
5262 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(r_refdef.scene.time * 5.0f) % t->anim_total[0]) : 0];
5264 texture->currentframe = t;
5267 // update currentskinframe to be a qw skin or animation frame
5268 if ((i = ent->entitynumber - 1) >= 0 && i < cl.maxclients && cls.protocol == PROTOCOL_QUAKEWORLD && cl.scores[i].qw_skin[0] && !strcmp(ent->model->name, "progs/player.mdl"))
5270 if (strcmp(r_qwskincache[i], cl.scores[i].qw_skin))
5272 strlcpy(r_qwskincache[i], cl.scores[i].qw_skin, sizeof(r_qwskincache[i]));
5273 if (developer_loading.integer)
5274 Con_Printf("loading skins/%s\n", r_qwskincache[i]);
5275 r_qwskincache_skinframe[i] = R_SkinFrame_LoadExternal(va("skins/%s", r_qwskincache[i]), TEXF_PRECACHE | (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP | TEXF_COMPRESS, developer.integer > 0);
5277 t->currentskinframe = r_qwskincache_skinframe[i];
5278 if (t->currentskinframe == NULL)
5279 t->currentskinframe = t->skinframes[(int)(t->skinframerate * (cl.time - ent->shadertime)) % t->numskinframes];
5281 else if (t->numskinframes >= 2)
5282 t->currentskinframe = t->skinframes[(int)(t->skinframerate * (cl.time - ent->shadertime)) % t->numskinframes];
5283 if (t->backgroundnumskinframes >= 2)
5284 t->backgroundcurrentskinframe = t->backgroundskinframes[(int)(t->backgroundskinframerate * (cl.time - ent->shadertime)) % t->backgroundnumskinframes];
5286 t->currentmaterialflags = t->basematerialflags;
5287 t->currentalpha = ent->alpha;
5288 if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_novis.integer))
5289 t->currentalpha *= r_wateralpha.value;
5290 if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_waterstate.enabled && !r_refdef.view.isoverlay)
5291 t->currentalpha *= t->r_water_wateralpha;
5292 if(!r_waterstate.enabled || r_refdef.view.isoverlay)
5293 t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION);
5294 if (!(ent->flags & RENDER_LIGHT))
5295 t->currentmaterialflags |= MATERIALFLAG_FULLBRIGHT;
5296 else if (rsurface.modeltexcoordlightmap2f == NULL)
5298 // pick a model lighting mode
5299 if (VectorLength2(ent->modellight_diffuse) >= (1.0f / 256.0f))
5300 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT | MATERIALFLAG_MODELLIGHT_DIRECTIONAL;
5302 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
5304 if (ent->effects & EF_ADDITIVE)
5305 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
5306 else if (t->currentalpha < 1)
5307 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
5308 if (ent->effects & EF_DOUBLESIDED)
5309 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
5310 if (ent->effects & EF_NODEPTHTEST)
5311 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
5312 if (ent->flags & RENDER_VIEWMODEL)
5313 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
5314 if (t->backgroundnumskinframes)
5315 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
5316 if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
5318 if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER))
5319 t->currentmaterialflags &= ~MATERIALFLAG_BLENDED;
5322 t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER);
5324 // there is no tcmod
5325 if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
5327 t->currenttexmatrix = r_waterscrollmatrix;
5328 t->currentbackgroundtexmatrix = r_waterscrollmatrix;
5332 Matrix4x4_CreateIdentity(&t->currenttexmatrix);
5333 Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
5336 for (i = 0, tcmod = t->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
5337 R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
5338 for (i = 0, tcmod = t->backgroundtcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
5339 R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
5341 t->colormapping = VectorLength2(ent->colormap_pantscolor) + VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f);
5342 t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
5343 t->glosstexture = r_texture_black;
5344 t->backgroundbasetexture = t->backgroundnumskinframes ? ((!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base) : r_texture_white;
5345 t->backgroundglosstexture = r_texture_black;
5346 t->specularpower = r_shadow_glossexponent.value;
5347 // TODO: store reference values for these in the texture?
5348 t->specularscale = 0;
5349 if (r_shadow_gloss.integer > 0)
5351 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
5353 if (r_shadow_glossintensity.value > 0)
5355 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
5356 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
5357 t->specularscale = r_shadow_glossintensity.value;
5360 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
5362 t->glosstexture = r_texture_white;
5363 t->backgroundglosstexture = r_texture_white;
5364 t->specularscale = r_shadow_gloss2intensity.value;
5368 // lightmaps mode looks bad with dlights using actual texturing, so turn
5369 // off the colormap and glossmap, but leave the normalmap on as it still
5370 // accurately represents the shading involved
5371 if (gl_lightmaps.integer)
5373 t->basetexture = r_texture_grey128;
5374 t->backgroundbasetexture = NULL;
5375 t->specularscale = 0;
5376 t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_MODELLIGHT_DIRECTIONAL | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
5379 Vector4Set(t->lightmapcolor, ent->colormod[0], ent->colormod[1], ent->colormod[2], t->currentalpha);
5380 VectorClear(t->dlightcolor);
5381 t->currentnumlayers = 0;
5382 if (t->currentmaterialflags & MATERIALFLAG_WALL)
5385 int blendfunc1, blendfunc2;
5387 if (t->currentmaterialflags & MATERIALFLAG_ADD)
5389 blendfunc1 = GL_SRC_ALPHA;
5390 blendfunc2 = GL_ONE;
5392 else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
5394 blendfunc1 = GL_SRC_ALPHA;
5395 blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
5397 else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
5399 blendfunc1 = t->customblendfunc[0];
5400 blendfunc2 = t->customblendfunc[1];
5404 blendfunc1 = GL_ONE;
5405 blendfunc2 = GL_ZERO;
5407 depthmask = !(t->currentmaterialflags & MATERIALFLAG_BLENDED);
5408 if (r_refdef.fogenabled && (t->currentmaterialflags & MATERIALFLAG_BLENDED))
5409 layerflags |= TEXTURELAYERFLAG_FOGDARKEN;
5410 if (t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
5412 // fullbright is not affected by r_refdef.lightmapintensity
5413 R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_TEXTURE, t->basetexture, &t->currenttexmatrix, t->lightmapcolor[0], t->lightmapcolor[1], t->lightmapcolor[2], t->lightmapcolor[3]);
5414 if (VectorLength2(ent->colormap_pantscolor) >= (1.0f / 1048576.0f) && t->currentskinframe->pants)
5415 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->pants, &t->currenttexmatrix, ent->colormap_pantscolor[0] * t->lightmapcolor[0], ent->colormap_pantscolor[1] * t->lightmapcolor[1], ent->colormap_pantscolor[2] * t->lightmapcolor[2], t->lightmapcolor[3]);
5416 if (VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->currentskinframe->shirt)
5417 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->shirt, &t->currenttexmatrix, ent->colormap_shirtcolor[0] * t->lightmapcolor[0], ent->colormap_shirtcolor[1] * t->lightmapcolor[1], ent->colormap_shirtcolor[2] * t->lightmapcolor[2], t->lightmapcolor[3]);
5421 vec3_t ambientcolor;
5423 // set the color tint used for lights affecting this surface
5424 VectorSet(t->dlightcolor, ent->colormod[0] * t->lightmapcolor[3], ent->colormod[1] * t->lightmapcolor[3], ent->colormod[2] * t->lightmapcolor[3]);
5426 // q3bsp has no lightmap updates, so the lightstylevalue that
5427 // would normally be baked into the lightmap must be
5428 // applied to the color
5429 // FIXME: r_glsl 1 rendering doesn't support overbright lightstyles with this (the default light style is not overbright)
5430 if (ent->model->type == mod_brushq3)
5431 colorscale *= r_refdef.scene.rtlightstylevalue[0];
5432 colorscale *= r_refdef.lightmapintensity;
5433 VectorScale(t->lightmapcolor, r_refdef.scene.ambient * (1.0f / 64.0f), ambientcolor);
5434 VectorScale(t->lightmapcolor, colorscale, t->lightmapcolor);
5435 // basic lit geometry
5436 R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE, t->basetexture, &t->currenttexmatrix, t->lightmapcolor[0], t->lightmapcolor[1], t->lightmapcolor[2], t->lightmapcolor[3]);
5437 // add pants/shirt if needed
5438 if (VectorLength2(ent->colormap_pantscolor) >= (1.0f / 1048576.0f) && t->currentskinframe->pants)
5439 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->currentskinframe->pants, &t->currenttexmatrix, ent->colormap_pantscolor[0] * t->lightmapcolor[0], ent->colormap_pantscolor[1] * t->lightmapcolor[1], ent->colormap_pantscolor[2] * t->lightmapcolor[2], t->lightmapcolor[3]);
5440 if (VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->currentskinframe->shirt)
5441 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->currentskinframe->shirt, &t->currenttexmatrix, ent->colormap_shirtcolor[0] * t->lightmapcolor[0], ent->colormap_shirtcolor[1] * t->lightmapcolor[1], ent->colormap_shirtcolor[2] * t->lightmapcolor[2], t->lightmapcolor[3]);
5442 // now add ambient passes if needed
5443 if (VectorLength2(ambientcolor) >= (1.0f/1048576.0f))
5445 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->basetexture, &t->currenttexmatrix, ambientcolor[0], ambientcolor[1], ambientcolor[2], t->lightmapcolor[3]);
5446 if (VectorLength2(ent->colormap_pantscolor) >= (1.0f / 1048576.0f) && t->currentskinframe->pants)
5447 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->pants, &t->currenttexmatrix, ent->colormap_pantscolor[0] * ambientcolor[0], ent->colormap_pantscolor[1] * ambientcolor[1], ent->colormap_pantscolor[2] * ambientcolor[2], t->lightmapcolor[3]);
5448 if (VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->currentskinframe->shirt)
5449 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->shirt, &t->currenttexmatrix, ent->colormap_shirtcolor[0] * ambientcolor[0], ent->colormap_shirtcolor[1] * ambientcolor[1], ent->colormap_shirtcolor[2] * ambientcolor[2], t->lightmapcolor[3]);
5452 if (t->currentskinframe->glow != NULL && !gl_lightmaps.integer)
5453 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->glow, &t->currenttexmatrix, r_hdr_glowintensity.value, r_hdr_glowintensity.value, r_hdr_glowintensity.value, t->lightmapcolor[3]);
5454 if (r_refdef.fogenabled && !(t->currentmaterialflags & MATERIALFLAG_ADD))
5456 // if this is opaque use alpha blend which will darken the earlier
5459 // if this is an alpha blended material, all the earlier passes
5460 // were darkened by fog already, so we only need to add the fog
5461 // color ontop through the fog mask texture
5463 // if this is an additive blended material, all the earlier passes
5464 // were darkened by fog already, and we should not add fog color
5465 // (because the background was not darkened, there is no fog color
5466 // that was lost behind it).
5467 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, (t->currentmaterialflags & MATERIALFLAG_BLENDED) ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA, TEXTURELAYERTYPE_FOG, t->currentskinframe->fog, &identitymatrix, r_refdef.fogcolor[0] / r_refdef.view.colorscale, r_refdef.fogcolor[1] / r_refdef.view.colorscale, r_refdef.fogcolor[2] / r_refdef.view.colorscale, t->lightmapcolor[3]);
5471 return t->currentframe;
5474 rsurfacestate_t rsurface;
5476 void R_Mesh_ResizeArrays(int newvertices)
5479 if (rsurface.array_size >= newvertices)
5481 if (rsurface.array_modelvertex3f)
5482 Mem_Free(rsurface.array_modelvertex3f);
5483 rsurface.array_size = (newvertices + 1023) & ~1023;
5484 base = (float *)Mem_Alloc(r_main_mempool, rsurface.array_size * sizeof(float[33]));
5485 rsurface.array_modelvertex3f = base + rsurface.array_size * 0;
5486 rsurface.array_modelsvector3f = base + rsurface.array_size * 3;
5487 rsurface.array_modeltvector3f = base + rsurface.array_size * 6;
5488 rsurface.array_modelnormal3f = base + rsurface.array_size * 9;
5489 rsurface.array_deformedvertex3f = base + rsurface.array_size * 12;
5490 rsurface.array_deformedsvector3f = base + rsurface.array_size * 15;
5491 rsurface.array_deformedtvector3f = base + rsurface.array_size * 18;
5492 rsurface.array_deformednormal3f = base + rsurface.array_size * 21;
5493 rsurface.array_texcoord3f = base + rsurface.array_size * 24;
5494 rsurface.array_color4f = base + rsurface.array_size * 27;
5495 rsurface.array_generatedtexcoordtexture2f = base + rsurface.array_size * 31;
5498 void RSurf_ActiveWorldEntity(void)
5500 dp_model_t *model = r_refdef.scene.worldmodel;
5501 //if (rsurface.entity == r_refdef.scene.worldentity)
5503 rsurface.entity = r_refdef.scene.worldentity;
5504 if (rsurface.array_size < model->surfmesh.num_vertices)
5505 R_Mesh_ResizeArrays(model->surfmesh.num_vertices);
5506 rsurface.matrix = identitymatrix;
5507 rsurface.inversematrix = identitymatrix;
5508 R_Mesh_Matrix(&identitymatrix);
5509 VectorCopy(r_refdef.view.origin, rsurface.modelorg);
5510 VectorSet(rsurface.modellight_ambient, 0, 0, 0);
5511 VectorSet(rsurface.modellight_diffuse, 0, 0, 0);
5512 VectorSet(rsurface.modellight_lightdir, 0, 0, 1);
5513 VectorSet(rsurface.colormap_pantscolor, 0, 0, 0);
5514 VectorSet(rsurface.colormap_shirtcolor, 0, 0, 0);
5515 memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
5516 rsurface.frameblend[0].lerp = 1;
5517 rsurface.basepolygonfactor = r_refdef.polygonfactor;
5518 rsurface.basepolygonoffset = r_refdef.polygonoffset;
5519 rsurface.modelvertex3f = model->surfmesh.data_vertex3f;
5520 rsurface.modelvertex3f_bufferobject = model->surfmesh.vbo;
5521 rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f;
5522 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
5523 rsurface.modelsvector3f_bufferobject = model->surfmesh.vbo;
5524 rsurface.modelsvector3f_bufferoffset = model->surfmesh.vbooffset_svector3f;
5525 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
5526 rsurface.modeltvector3f_bufferobject = model->surfmesh.vbo;
5527 rsurface.modeltvector3f_bufferoffset = model->surfmesh.vbooffset_tvector3f;
5528 rsurface.modelnormal3f = model->surfmesh.data_normal3f;
5529 rsurface.modelnormal3f_bufferobject = model->surfmesh.vbo;
5530 rsurface.modelnormal3f_bufferoffset = model->surfmesh.vbooffset_normal3f;
5531 rsurface.modellightmapcolor4f = model->surfmesh.data_lightmapcolor4f;
5532 rsurface.modellightmapcolor4f_bufferobject = model->surfmesh.vbo;
5533 rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.vbooffset_lightmapcolor4f;
5534 rsurface.modeltexcoordtexture2f = model->surfmesh.data_texcoordtexture2f;
5535 rsurface.modeltexcoordtexture2f_bufferobject = model->surfmesh.vbo;
5536 rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.vbooffset_texcoordtexture2f;
5537 rsurface.modeltexcoordlightmap2f = model->surfmesh.data_texcoordlightmap2f;
5538 rsurface.modeltexcoordlightmap2f_bufferobject = model->surfmesh.vbo;
5539 rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f;
5540 rsurface.modelelement3i = model->surfmesh.data_element3i;
5541 rsurface.modelelement3s = model->surfmesh.data_element3s;
5542 rsurface.modelelement3i_bufferobject = model->surfmesh.ebo3i;
5543 rsurface.modelelement3s_bufferobject = model->surfmesh.ebo3s;
5544 rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
5545 rsurface.modelnum_vertices = model->surfmesh.num_vertices;
5546 rsurface.modelnum_triangles = model->surfmesh.num_triangles;
5547 rsurface.modelsurfaces = model->data_surfaces;
5548 rsurface.generatedvertex = false;
5549 rsurface.vertex3f = rsurface.modelvertex3f;
5550 rsurface.vertex3f_bufferobject = rsurface.modelvertex3f_bufferobject;
5551 rsurface.vertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
5552 rsurface.svector3f = rsurface.modelsvector3f;
5553 rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject;
5554 rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
5555 rsurface.tvector3f = rsurface.modeltvector3f;
5556 rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject;
5557 rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
5558 rsurface.normal3f = rsurface.modelnormal3f;
5559 rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject;
5560 rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
5561 rsurface.texcoordtexture2f = rsurface.modeltexcoordtexture2f;
5564 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
5566 dp_model_t *model = ent->model;
5567 //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
5569 rsurface.entity = (entity_render_t *)ent;
5570 if (rsurface.array_size < model->surfmesh.num_vertices)
5571 R_Mesh_ResizeArrays(model->surfmesh.num_vertices);
5572 rsurface.matrix = ent->matrix;
5573 rsurface.inversematrix = ent->inversematrix;
5574 R_Mesh_Matrix(&rsurface.matrix);
5575 Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.modelorg);
5576 rsurface.modellight_ambient[0] = ent->modellight_ambient[0] * ent->colormod[0];
5577 rsurface.modellight_ambient[1] = ent->modellight_ambient[1] * ent->colormod[1];
5578 rsurface.modellight_ambient[2] = ent->modellight_ambient[2] * ent->colormod[2];
5579 rsurface.modellight_diffuse[0] = ent->modellight_diffuse[0] * ent->colormod[0];
5580 rsurface.modellight_diffuse[1] = ent->modellight_diffuse[1] * ent->colormod[1];
5581 rsurface.modellight_diffuse[2] = ent->modellight_diffuse[2] * ent->colormod[2];
5582 VectorCopy(ent->modellight_diffuse, rsurface.modellight_diffuse);
5583 VectorCopy(ent->modellight_lightdir, rsurface.modellight_lightdir);
5584 VectorCopy(ent->colormap_pantscolor, rsurface.colormap_pantscolor);
5585 VectorCopy(ent->colormap_shirtcolor, rsurface.colormap_shirtcolor);
5586 memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
5587 rsurface.basepolygonfactor = r_refdef.polygonfactor;
5588 rsurface.basepolygonoffset = r_refdef.polygonoffset;
5589 if (ent->model->brush.submodel)
5591 rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
5592 rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
5594 if (model->surfmesh.isanimated && model->AnimateVertices && (rsurface.frameblend[0].lerp != 1 || rsurface.frameblend[0].subframe != 0))
5596 if (R_AnimCache_GetEntity((entity_render_t *)ent, wantnormals, wanttangents))
5598 rsurface.modelvertex3f = r_animcachestate.entity[ent->animcacheindex].vertex3f;
5599 rsurface.modelsvector3f = wanttangents ? r_animcachestate.entity[ent->animcacheindex].svector3f : NULL;
5600 rsurface.modeltvector3f = wanttangents ? r_animcachestate.entity[ent->animcacheindex].tvector3f : NULL;
5601 rsurface.modelnormal3f = wantnormals ? r_animcachestate.entity[ent->animcacheindex].normal3f : NULL;
5603 else if (wanttangents)
5605 rsurface.modelvertex3f = rsurface.array_modelvertex3f;
5606 rsurface.modelsvector3f = rsurface.array_modelsvector3f;
5607 rsurface.modeltvector3f = rsurface.array_modeltvector3f;
5608 rsurface.modelnormal3f = rsurface.array_modelnormal3f;
5609 model->AnimateVertices(model, rsurface.frameblend, rsurface.array_modelvertex3f, rsurface.array_modelnormal3f, rsurface.array_modelsvector3f, rsurface.array_modeltvector3f);
5611 else if (wantnormals)
5613 rsurface.modelvertex3f = rsurface.array_modelvertex3f;
5614 rsurface.modelsvector3f = NULL;
5615 rsurface.modeltvector3f = NULL;
5616 rsurface.modelnormal3f = rsurface.array_modelnormal3f;
5617 model->AnimateVertices(model, rsurface.frameblend, rsurface.array_modelvertex3f, rsurface.array_modelnormal3f, NULL, NULL);
5621 rsurface.modelvertex3f = rsurface.array_modelvertex3f;
5622 rsurface.modelsvector3f = NULL;
5623 rsurface.modeltvector3f = NULL;
5624 rsurface.modelnormal3f = NULL;
5625 model->AnimateVertices(model, rsurface.frameblend, rsurface.array_modelvertex3f, NULL, NULL, NULL);
5627 rsurface.modelvertex3f_bufferobject = 0;
5628 rsurface.modelvertex3f_bufferoffset = 0;
5629 rsurface.modelsvector3f_bufferobject = 0;
5630 rsurface.modelsvector3f_bufferoffset = 0;
5631 rsurface.modeltvector3f_bufferobject = 0;
5632 rsurface.modeltvector3f_bufferoffset = 0;
5633 rsurface.modelnormal3f_bufferobject = 0;
5634 rsurface.modelnormal3f_bufferoffset = 0;
5635 rsurface.generatedvertex = true;
5639 rsurface.modelvertex3f = model->surfmesh.data_vertex3f;
5640 rsurface.modelvertex3f_bufferobject = model->surfmesh.vbo;
5641 rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f;
5642 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
5643 rsurface.modelsvector3f_bufferobject = model->surfmesh.vbo;
5644 rsurface.modelsvector3f_bufferoffset = model->surfmesh.vbooffset_svector3f;
5645 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
5646 rsurface.modeltvector3f_bufferobject = model->surfmesh.vbo;
5647 rsurface.modeltvector3f_bufferoffset = model->surfmesh.vbooffset_tvector3f;
5648 rsurface.modelnormal3f = model->surfmesh.data_normal3f;
5649 rsurface.modelnormal3f_bufferobject = model->surfmesh.vbo;
5650 rsurface.modelnormal3f_bufferoffset = model->surfmesh.vbooffset_normal3f;
5651 rsurface.generatedvertex = false;
5653 rsurface.modellightmapcolor4f = model->surfmesh.data_lightmapcolor4f;
5654 rsurface.modellightmapcolor4f_bufferobject = model->surfmesh.vbo;
5655 rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.vbooffset_lightmapcolor4f;
5656 rsurface.modeltexcoordtexture2f = model->surfmesh.data_texcoordtexture2f;
5657 rsurface.modeltexcoordtexture2f_bufferobject = model->surfmesh.vbo;
5658 rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.vbooffset_texcoordtexture2f;
5659 rsurface.modeltexcoordlightmap2f = model->surfmesh.data_texcoordlightmap2f;
5660 rsurface.modeltexcoordlightmap2f_bufferobject = model->surfmesh.vbo;
5661 rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f;
5662 rsurface.modelelement3i = model->surfmesh.data_element3i;
5663 rsurface.modelelement3s = model->surfmesh.data_element3s;
5664 rsurface.modelelement3i_bufferobject = model->surfmesh.ebo3i;
5665 rsurface.modelelement3s_bufferobject = model->surfmesh.ebo3s;
5666 rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
5667 rsurface.modelnum_vertices = model->surfmesh.num_vertices;
5668 rsurface.modelnum_triangles = model->surfmesh.num_triangles;
5669 rsurface.modelsurfaces = model->data_surfaces;
5670 rsurface.vertex3f = rsurface.modelvertex3f;
5671 rsurface.vertex3f_bufferobject = rsurface.modelvertex3f_bufferobject;
5672 rsurface.vertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
5673 rsurface.svector3f = rsurface.modelsvector3f;
5674 rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject;
5675 rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
5676 rsurface.tvector3f = rsurface.modeltvector3f;
5677 rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject;
5678 rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
5679 rsurface.normal3f = rsurface.modelnormal3f;
5680 rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject;
5681 rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
5682 rsurface.texcoordtexture2f = rsurface.modeltexcoordtexture2f;
5685 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
5686 void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generatetangents, int texturenumsurfaces, msurface_t **texturesurfacelist)
5689 int texturesurfaceindex;
5694 const float *v1, *in_tc;
5696 float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
5698 q3shaderinfo_deform_t *deform;
5699 // if vertices are dynamic (animated models), generate them into the temporary rsurface.array_model* arrays and point rsurface.model* at them instead of the static data from the model itself
5700 if (rsurface.generatedvertex)
5702 if (rsurface.texture->tcgen.tcgen == Q3TCGEN_ENVIRONMENT)
5703 generatenormals = true;
5704 for (i = 0;i < Q3MAXDEFORMS;i++)
5706 if (rsurface.texture->deforms[i].deform == Q3DEFORM_AUTOSPRITE)
5708 generatetangents = true;
5709 generatenormals = true;
5711 if (rsurface.texture->deforms[i].deform != Q3DEFORM_NONE)
5712 generatenormals = true;
5714 if (generatenormals && !rsurface.modelnormal3f)
5716 rsurface.normal3f = rsurface.modelnormal3f = rsurface.array_modelnormal3f;
5717 rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject = 0;
5718 rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset = 0;
5719 Mod_BuildNormals(0, rsurface.modelnum_vertices, rsurface.modelnum_triangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.array_modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
5721 if (generatetangents && !rsurface.modelsvector3f)
5723 rsurface.svector3f = rsurface.modelsvector3f = rsurface.array_modelsvector3f;
5724 rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject = 0;
5725 rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset = 0;
5726 rsurface.tvector3f = rsurface.modeltvector3f = rsurface.array_modeltvector3f;
5727 rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject = 0;
5728 rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset = 0;
5729 Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnum_vertices, rsurface.modelnum_triangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.array_modelsvector3f, rsurface.array_modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
5732 rsurface.vertex3f = rsurface.modelvertex3f;
5733 rsurface.vertex3f_bufferobject = rsurface.modelvertex3f_bufferobject;
5734 rsurface.vertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
5735 rsurface.svector3f = rsurface.modelsvector3f;
5736 rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject;
5737 rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
5738 rsurface.tvector3f = rsurface.modeltvector3f;
5739 rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject;
5740 rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
5741 rsurface.normal3f = rsurface.modelnormal3f;
5742 rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject;
5743 rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
5744 // if vertices are deformed (sprite flares and things in maps, possibly
5745 // water waves, bulges and other deformations), generate them into
5746 // rsurface.deform* arrays from whatever the rsurface.* arrays point to
5747 // (may be static model data or generated data for an animated model, or
5748 // the previous deform pass)
5749 for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform;deformindex++, deform++)
5751 switch (deform->deform)
5754 case Q3DEFORM_PROJECTIONSHADOW:
5755 case Q3DEFORM_TEXT0:
5756 case Q3DEFORM_TEXT1:
5757 case Q3DEFORM_TEXT2:
5758 case Q3DEFORM_TEXT3:
5759 case Q3DEFORM_TEXT4:
5760 case Q3DEFORM_TEXT5:
5761 case Q3DEFORM_TEXT6:
5762 case Q3DEFORM_TEXT7:
5765 case Q3DEFORM_AUTOSPRITE:
5766 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
5767 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
5768 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
5769 VectorNormalize(newforward);
5770 VectorNormalize(newright);
5771 VectorNormalize(newup);
5772 // make deformed versions of only the model vertices used by the specified surfaces
5773 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
5775 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
5776 // a single autosprite surface can contain multiple sprites...
5777 for (j = 0;j < surface->num_vertices - 3;j += 4)
5779 VectorClear(center);
5780 for (i = 0;i < 4;i++)
5781 VectorAdd(center, (rsurface.vertex3f + 3 * surface->num_firstvertex) + (j+i) * 3, center);
5782 VectorScale(center, 0.25f, center);
5783 VectorCopy((rsurface.normal3f + 3 * surface->num_firstvertex) + j*3, forward);
5784 VectorCopy((rsurface.svector3f + 3 * surface->num_firstvertex) + j*3, right);
5785 VectorCopy((rsurface.tvector3f + 3 * surface->num_firstvertex) + j*3, up);
5786 for (i = 0;i < 4;i++)
5788 VectorSubtract((rsurface.vertex3f + 3 * surface->num_firstvertex) + (j+i)*3, center, v);
5789 VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.array_deformedvertex3f + (surface->num_firstvertex+i+j) * 3);
5792 Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformednormal3f, r_smoothnormals_areaweighting.integer != 0);
5793 Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modeltexcoordtexture2f, rsurface.array_deformednormal3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformedsvector3f, rsurface.array_deformedtvector3f, r_smoothnormals_areaweighting.integer != 0);
5795 rsurface.vertex3f = rsurface.array_deformedvertex3f;
5796 rsurface.vertex3f_bufferobject = 0;
5797 rsurface.vertex3f_bufferoffset = 0;
5798 rsurface.svector3f = rsurface.array_deformedsvector3f;
5799 rsurface.svector3f_bufferobject = 0;
5800 rsurface.svector3f_bufferoffset = 0;
5801 rsurface.tvector3f = rsurface.array_deformedtvector3f;
5802 rsurface.tvector3f_bufferobject = 0;
5803 rsurface.tvector3f_bufferoffset = 0;
5804 rsurface.normal3f = rsurface.array_deformednormal3f;
5805 rsurface.normal3f_bufferobject = 0;
5806 rsurface.normal3f_bufferoffset = 0;
5808 case Q3DEFORM_AUTOSPRITE2:
5809 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
5810 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
5811 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
5812 VectorNormalize(newforward);
5813 VectorNormalize(newright);
5814 VectorNormalize(newup);
5815 // make deformed versions of only the model vertices used by the specified surfaces
5816 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
5818 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
5819 const float *v1, *v2;
5829 memset(shortest, 0, sizeof(shortest));
5830 // a single autosprite surface can contain multiple sprites...
5831 for (j = 0;j < surface->num_vertices - 3;j += 4)
5833 VectorClear(center);
5834 for (i = 0;i < 4;i++)
5835 VectorAdd(center, (rsurface.vertex3f + 3 * surface->num_firstvertex) + (j+i) * 3, center);
5836 VectorScale(center, 0.25f, center);
5837 // find the two shortest edges, then use them to define the
5838 // axis vectors for rotating around the central axis
5839 for (i = 0;i < 6;i++)
5841 v1 = rsurface.vertex3f + 3 * (surface->num_firstvertex + quadedges[i][0]);
5842 v2 = rsurface.vertex3f + 3 * (surface->num_firstvertex + quadedges[i][1]);
5844 Debug_PolygonBegin(NULL, 0);
5845 Debug_PolygonVertex(v1[0], v1[1], v1[2], 0, 0, 1, 0, 0, 1);
5846 Debug_PolygonVertex((v1[0] + v2[0]) * 0.5f + rsurface.normal3f[3 * (surface->num_firstvertex + j)+0] * 4, (v1[1] + v2[1]) * 0.5f + rsurface.normal3f[3 * (surface->num_firstvertex + j)+1], (v1[2] + v2[2]) * 0.5f + rsurface.normal3f[3 * (surface->num_firstvertex + j)+2], 0, 0, 1, 1, 0, 1);
5847 Debug_PolygonVertex(v2[0], v2[1], v2[2], 0, 0, 1, 0, 0, 1);
5850 l = VectorDistance2(v1, v2);
5851 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
5853 l += (1.0f / 1024.0f);
5854 if (shortest[0].length2 > l || i == 0)
5856 shortest[1] = shortest[0];
5857 shortest[0].length2 = l;
5858 shortest[0].v1 = v1;
5859 shortest[0].v2 = v2;
5861 else if (shortest[1].length2 > l || i == 1)
5863 shortest[1].length2 = l;
5864 shortest[1].v1 = v1;
5865 shortest[1].v2 = v2;
5868 VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
5869 VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
5871 Debug_PolygonBegin(NULL, 0);
5872 Debug_PolygonVertex(start[0], start[1], start[2], 0, 0, 1, 1, 0, 1);
5873 Debug_PolygonVertex(center[0] + rsurface.normal3f[3 * (surface->num_firstvertex + j)+0] * 4, center[1] + rsurface.normal3f[3 * (surface->num_firstvertex + j)+1] * 4, center[2] + rsurface.normal3f[3 * (surface->num_firstvertex + j)+2] * 4, 0, 0, 0, 1, 0, 1);
5874 Debug_PolygonVertex(end[0], end[1], end[2], 0, 0, 0, 1, 1, 1);
5877 // this calculates the right vector from the shortest edge
5878 // and the up vector from the edge midpoints
5879 VectorSubtract(shortest[0].v1, shortest[0].v2, right);
5880 VectorNormalize(right);
5881 VectorSubtract(end, start, up);
5882 VectorNormalize(up);
5883 // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
5884 VectorSubtract(rsurface.modelorg, center, forward);
5885 //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
5886 VectorNegate(forward, forward);
5887 VectorReflect(forward, 0, up, forward);
5888 VectorNormalize(forward);
5889 CrossProduct(up, forward, newright);
5890 VectorNormalize(newright);
5892 Debug_PolygonBegin(NULL, 0);
5893 Debug_PolygonVertex(center[0] + rsurface.normal3f[3 * (surface->num_firstvertex + j)+0] * 8, center[1] + rsurface.normal3f[3 * (surface->num_firstvertex + j)+1] * 8, center[2] + rsurface.normal3f[3 * (surface->num_firstvertex + j)+2] * 8, 0, 0, 1, 0, 0, 1);
5894 Debug_PolygonVertex(center[0] + right[0] * 8, center[1] + right[1] * 8, center[2] + right[2] * 8, 0, 0, 0, 1, 0, 1);
5895 Debug_PolygonVertex(center[0] + up [0] * 8, center[1] + up [1] * 8, center[2] + up [2] * 8, 0, 0, 0, 0, 1, 1);
5899 Debug_PolygonBegin(NULL, 0);
5900 Debug_PolygonVertex(center[0] + forward [0] * 8, center[1] + forward [1] * 8, center[2] + forward [2] * 8, 0, 0, 1, 0, 0, 1);
5901 Debug_PolygonVertex(center[0] + newright[0] * 8, center[1] + newright[1] * 8, center[2] + newright[2] * 8, 0, 0, 0, 1, 0, 1);
5902 Debug_PolygonVertex(center[0] + up [0] * 8, center[1] + up [1] * 8, center[2] + up [2] * 8, 0, 0, 0, 0, 1, 1);
5905 // rotate the quad around the up axis vector, this is made
5906 // especially easy by the fact we know the quad is flat,
5907 // so we only have to subtract the center position and
5908 // measure distance along the right vector, and then
5909 // multiply that by the newright vector and add back the
5911 // we also need to subtract the old position to undo the
5912 // displacement from the center, which we do with a
5913 // DotProduct, the subtraction/addition of center is also
5914 // optimized into DotProducts here
5915 l = DotProduct(right, center);
5916 for (i = 0;i < 4;i++)
5918 v1 = rsurface.vertex3f + 3 * (surface->num_firstvertex + j + i);
5919 f = DotProduct(right, v1) - l;
5920 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.array_deformedvertex3f + (surface->num_firstvertex+i+j) * 3);
5923 Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformednormal3f, r_smoothnormals_areaweighting.integer != 0);
5924 Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modeltexcoordtexture2f, rsurface.array_deformednormal3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformedsvector3f, rsurface.array_deformedtvector3f, r_smoothnormals_areaweighting.integer != 0);
5926 rsurface.vertex3f = rsurface.array_deformedvertex3f;
5927 rsurface.vertex3f_bufferobject = 0;
5928 rsurface.vertex3f_bufferoffset = 0;
5929 rsurface.svector3f = rsurface.array_deformedsvector3f;
5930 rsurface.svector3f_bufferobject = 0;
5931 rsurface.svector3f_bufferoffset = 0;
5932 rsurface.tvector3f = rsurface.array_deformedtvector3f;
5933 rsurface.tvector3f_bufferobject = 0;
5934 rsurface.tvector3f_bufferoffset = 0;
5935 rsurface.normal3f = rsurface.array_deformednormal3f;
5936 rsurface.normal3f_bufferobject = 0;
5937 rsurface.normal3f_bufferoffset = 0;
5939 case Q3DEFORM_NORMAL:
5940 // deform the normals to make reflections wavey
5941 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
5943 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
5944 for (j = 0;j < surface->num_vertices;j++)
5947 float *normal = (rsurface.array_deformednormal3f + 3 * surface->num_firstvertex) + j*3;
5948 VectorScale((rsurface.vertex3f + 3 * surface->num_firstvertex) + j*3, 0.98f, vertex);
5949 VectorCopy((rsurface.normal3f + 3 * surface->num_firstvertex) + j*3, normal);
5950 normal[0] += deform->parms[0] * noise4f( vertex[0], vertex[1], vertex[2], r_refdef.scene.time * deform->parms[1]);
5951 normal[1] += deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], r_refdef.scene.time * deform->parms[1]);
5952 normal[2] += deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], r_refdef.scene.time * deform->parms[1]);
5953 VectorNormalize(normal);
5955 Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, rsurface.vertex3f, rsurface.modeltexcoordtexture2f, rsurface.array_deformednormal3f, rsurface.modelelement3i + surface->num_firsttriangle * 3, rsurface.array_deformedsvector3f, rsurface.array_deformedtvector3f, r_smoothnormals_areaweighting.integer != 0);
5957 rsurface.svector3f = rsurface.array_deformedsvector3f;
5958 rsurface.svector3f_bufferobject = 0;
5959 rsurface.svector3f_bufferoffset = 0;
5960 rsurface.tvector3f = rsurface.array_deformedtvector3f;
5961 rsurface.tvector3f_bufferobject = 0;
5962 rsurface.tvector3f_bufferoffset = 0;
5963 rsurface.normal3f = rsurface.array_deformednormal3f;
5964 rsurface.normal3f_bufferobject = 0;
5965 rsurface.normal3f_bufferoffset = 0;
5968 // deform vertex array to make wavey water and flags and such
5969 waveparms[0] = deform->waveparms[0];
5970 waveparms[1] = deform->waveparms[1];
5971 waveparms[2] = deform->waveparms[2];
5972 waveparms[3] = deform->waveparms[3];
5973 // this is how a divisor of vertex influence on deformation
5974 animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
5975 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
5976 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
5978 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
5979 for (j = 0;j < surface->num_vertices;j++)
5981 float *vertex = (rsurface.array_deformedvertex3f + 3 * surface->num_firstvertex) + j*3;
5982 VectorCopy((rsurface.vertex3f + 3 * surface->num_firstvertex) + j*3, vertex);
5983 // if the wavefunc depends on time, evaluate it per-vertex
5986 waveparms[2] = deform->waveparms[2] + (vertex[0] + vertex[1] + vertex[2]) * animpos;
5987 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
5989 VectorMA(vertex, scale, (rsurface.normal3f + 3 * surface->num_firstvertex) + j*3, vertex);
5992 rsurface.vertex3f = rsurface.array_deformedvertex3f;
5993 rsurface.vertex3f_bufferobject = 0;
5994 rsurface.vertex3f_bufferoffset = 0;
5996 case Q3DEFORM_BULGE:
5997 // deform vertex array to make the surface have moving bulges
5998 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
6000 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
6001 for (j = 0;j < surface->num_vertices;j++)
6003 scale = sin((rsurface.modeltexcoordtexture2f[2 * (surface->num_firstvertex + j)] * deform->parms[0] + r_refdef.scene.time * deform->parms[2])) * deform->parms[1];
6004 VectorMA(rsurface.vertex3f + 3 * (surface->num_firstvertex + j), scale, rsurface.normal3f + 3 * (surface->num_firstvertex + j), rsurface.array_deformedvertex3f + 3 * (surface->num_firstvertex + j));
6007 rsurface.vertex3f = rsurface.array_deformedvertex3f;
6008 rsurface.vertex3f_bufferobject = 0;
6009 rsurface.vertex3f_bufferoffset = 0;
6012 // deform vertex array
6013 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
6014 VectorScale(deform->parms, scale, waveparms);
6015 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
6017 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
6018 for (j = 0;j < surface->num_vertices;j++)
6019 VectorAdd(rsurface.vertex3f + 3 * (surface->num_firstvertex + j), waveparms, rsurface.array_deformedvertex3f + 3 * (surface->num_firstvertex + j));
6021 rsurface.vertex3f = rsurface.array_deformedvertex3f;
6022 rsurface.vertex3f_bufferobject = 0;
6023 rsurface.vertex3f_bufferoffset = 0;
6027 // generate texcoords based on the chosen texcoord source
6028 switch(rsurface.texture->tcgen.tcgen)
6031 case Q3TCGEN_TEXTURE:
6032 rsurface.texcoordtexture2f = rsurface.modeltexcoordtexture2f;
6033 rsurface.texcoordtexture2f_bufferobject = rsurface.modeltexcoordtexture2f_bufferobject;
6034 rsurface.texcoordtexture2f_bufferoffset = rsurface.modeltexcoordtexture2f_bufferoffset;
6036 case Q3TCGEN_LIGHTMAP:
6037 rsurface.texcoordtexture2f = rsurface.modeltexcoordlightmap2f;
6038 rsurface.texcoordtexture2f_bufferobject = rsurface.modeltexcoordlightmap2f_bufferobject;
6039 rsurface.texcoordtexture2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
6041 case Q3TCGEN_VECTOR:
6042 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
6044 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
6045 for (j = 0, v1 = rsurface.modelvertex3f + 3 * surface->num_firstvertex, out_tc = rsurface.array_generatedtexcoordtexture2f + 2 * surface->num_firstvertex;j < surface->num_vertices;j++, v1 += 3, out_tc += 2)
6047 out_tc[0] = DotProduct(v1, rsurface.texture->tcgen.parms);
6048 out_tc[1] = DotProduct(v1, rsurface.texture->tcgen.parms + 3);
6051 rsurface.texcoordtexture2f = rsurface.array_generatedtexcoordtexture2f;
6052 rsurface.texcoordtexture2f_bufferobject = 0;
6053 rsurface.texcoordtexture2f_bufferoffset = 0;
6055 case Q3TCGEN_ENVIRONMENT:
6056 // make environment reflections using a spheremap
6057 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
6059 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
6060 const float *vertex = rsurface.modelvertex3f + 3 * surface->num_firstvertex;
6061 const float *normal = rsurface.modelnormal3f + 3 * surface->num_firstvertex;
6062 float *out_tc = rsurface.array_generatedtexcoordtexture2f + 2 * surface->num_firstvertex;
6063 for (j = 0;j < surface->num_vertices;j++, vertex += 3, normal += 3, out_tc += 2)
6065 // identical to Q3A's method, but executed in worldspace so
6066 // carried models can be shiny too
6068 float viewer[3], d, reflected[3], worldreflected[3];
6070 VectorSubtract(rsurface.modelorg, vertex, viewer);
6071 // VectorNormalize(viewer);
6073 d = DotProduct(normal, viewer);
6075 reflected[0] = normal[0]*2*d - viewer[0];
6076 reflected[1] = normal[1]*2*d - viewer[1];
6077 reflected[2] = normal[2]*2*d - viewer[2];
6078 // note: this is proportinal to viewer, so we can normalize later
6080 Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
6081 VectorNormalize(worldreflected);
6083 // note: this sphere map only uses world x and z!
6084 // so positive and negative y will LOOK THE SAME.
6085 out_tc[0] = 0.5 + 0.5 * worldreflected[1];
6086 out_tc[1] = 0.5 - 0.5 * worldreflected[2];
6089 rsurface.texcoordtexture2f = rsurface.array_generatedtexcoordtexture2f;
6090 rsurface.texcoordtexture2f_bufferobject = 0;
6091 rsurface.texcoordtexture2f_bufferoffset = 0;
6094 // the only tcmod that needs software vertex processing is turbulent, so
6095 // check for it here and apply the changes if needed
6096 // and we only support that as the first one
6097 // (handling a mixture of turbulent and other tcmods would be problematic
6098 // without punting it entirely to a software path)
6099 if (rsurface.texture->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
6101 amplitude = rsurface.texture->tcmods[0].parms[1];
6102 animpos = rsurface.texture->tcmods[0].parms[2] + r_refdef.scene.time * rsurface.texture->tcmods[0].parms[3];
6103 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
6105 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
6106 for (j = 0, v1 = rsurface.modelvertex3f + 3 * surface->num_firstvertex, in_tc = rsurface.texcoordtexture2f + 2 * surface->num_firstvertex, out_tc = rsurface.array_generatedtexcoordtexture2f + 2 * surface->num_firstvertex;j < surface->num_vertices;j++, v1 += 3, in_tc += 2, out_tc += 2)
6108 out_tc[0] = in_tc[0] + amplitude * sin(((v1[0] + v1[2]) * 1.0 / 1024.0f + animpos) * M_PI * 2);
6109 out_tc[1] = in_tc[1] + amplitude * sin(((v1[1] ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
6112 rsurface.texcoordtexture2f = rsurface.array_generatedtexcoordtexture2f;
6113 rsurface.texcoordtexture2f_bufferobject = 0;
6114 rsurface.texcoordtexture2f_bufferoffset = 0;
6116 rsurface.texcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
6117 rsurface.texcoordlightmap2f_bufferobject = rsurface.modeltexcoordlightmap2f_bufferobject;
6118 rsurface.texcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
6119 R_Mesh_VertexPointer(rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
6122 void RSurf_DrawBatch_Simple(int texturenumsurfaces, msurface_t **texturesurfacelist)
6125 const msurface_t *surface = texturesurfacelist[0];
6126 const msurface_t *surface2;
6131 // TODO: lock all array ranges before render, rather than on each surface
6132 if (texturenumsurfaces == 1)
6134 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
6135 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
6137 else if (r_batchmode.integer == 2)
6139 #define MAXBATCHTRIANGLES 4096
6140 int batchtriangles = 0;
6141 int batchelements[MAXBATCHTRIANGLES*3];
6142 for (i = 0;i < texturenumsurfaces;i = j)
6144 surface = texturesurfacelist[i];
6146 if (surface->num_triangles > MAXBATCHTRIANGLES)
6148 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
6151 memcpy(batchelements, rsurface.modelelement3i + 3 * surface->num_firsttriangle, surface->num_triangles * sizeof(int[3]));
6152 batchtriangles = surface->num_triangles;
6153 firstvertex = surface->num_firstvertex;
6154 endvertex = surface->num_firstvertex + surface->num_vertices;
6155 for (;j < texturenumsurfaces;j++)
6157 surface2 = texturesurfacelist[j];
6158 if (batchtriangles + surface2->num_triangles > MAXBATCHTRIANGLES)
6160 memcpy(batchelements + batchtriangles * 3, rsurface.modelelement3i + 3 * surface2->num_firsttriangle, surface2->num_triangles * sizeof(int[3]));
6161 batchtriangles += surface2->num_triangles;
6162 firstvertex = min(firstvertex, surface2->num_firstvertex);
6163 endvertex = max(endvertex, surface2->num_firstvertex + surface2->num_vertices);
6165 surface2 = texturesurfacelist[j-1];
6166 numvertices = endvertex - firstvertex;
6167 R_Mesh_Draw(firstvertex, numvertices, 0, batchtriangles, batchelements, NULL, 0, 0);
6170 else if (r_batchmode.integer == 1)
6172 for (i = 0;i < texturenumsurfaces;i = j)
6174 surface = texturesurfacelist[i];
6175 for (j = i + 1, surface2 = surface + 1;j < texturenumsurfaces;j++, surface2++)
6176 if (texturesurfacelist[j] != surface2)
6178 surface2 = texturesurfacelist[j-1];
6179 numvertices = surface2->num_firstvertex + surface2->num_vertices - surface->num_firstvertex;
6180 numtriangles = surface2->num_firsttriangle + surface2->num_triangles - surface->num_firsttriangle;
6181 GL_LockArrays(surface->num_firstvertex, numvertices);
6182 R_Mesh_Draw(surface->num_firstvertex, numvertices, surface->num_firsttriangle, numtriangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
6187 for (i = 0;i < texturenumsurfaces;i++)
6189 surface = texturesurfacelist[i];
6190 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
6191 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
6196 static void RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(int texturenumsurfaces, msurface_t **texturesurfacelist, int lightmaptexunit, int deluxemaptexunit, int refractiontexunit, int reflectiontexunit)
6198 int i, planeindex, vertexindex;
6202 r_waterstate_waterplane_t *p, *bestp;
6203 msurface_t *surface;
6204 if (r_waterstate.renderingscene)
6206 for (i = 0;i < texturenumsurfaces;i++)
6208 surface = texturesurfacelist[i];
6209 if (lightmaptexunit >= 0)
6210 R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
6211 if (deluxemaptexunit >= 0)
6212 R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
6213 // pick the closest matching water plane
6216 for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++)
6219 for (vertexindex = 0, v = rsurface.modelvertex3f + surface->num_firstvertex * 3;vertexindex < surface->num_vertices;vertexindex++, v += 3)
6221 Matrix4x4_Transform(&rsurface.matrix, v, vert);
6222 d += fabs(PlaneDiff(vert, &p->plane));
6224 if (bestd > d || !bestp)
6232 if (refractiontexunit >= 0)
6233 R_Mesh_TexBind(refractiontexunit, R_GetTexture(bestp->texture_refraction));
6234 if (reflectiontexunit >= 0)
6235 R_Mesh_TexBind(reflectiontexunit, R_GetTexture(bestp->texture_reflection));
6239 if (refractiontexunit >= 0)
6240 R_Mesh_TexBind(refractiontexunit, R_GetTexture(r_texture_black));
6241 if (reflectiontexunit >= 0)
6242 R_Mesh_TexBind(reflectiontexunit, R_GetTexture(r_texture_black));
6244 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
6245 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
6249 static void RSurf_DrawBatch_WithLightmapSwitching(int texturenumsurfaces, msurface_t **texturesurfacelist, int lightmaptexunit, int deluxemaptexunit)
6253 const msurface_t *surface = texturesurfacelist[0];
6254 const msurface_t *surface2;
6259 // TODO: lock all array ranges before render, rather than on each surface
6260 if (texturenumsurfaces == 1)
6262 R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
6263 if (deluxemaptexunit >= 0)
6264 R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
6265 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
6266 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
6268 else if (r_batchmode.integer == 2)
6270 #define MAXBATCHTRIANGLES 4096
6271 int batchtriangles = 0;
6272 int batchelements[MAXBATCHTRIANGLES*3];
6273 for (i = 0;i < texturenumsurfaces;i = j)
6275 surface = texturesurfacelist[i];
6276 R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
6277 if (deluxemaptexunit >= 0)
6278 R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
6280 if (surface->num_triangles > MAXBATCHTRIANGLES)
6282 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
6285 memcpy(batchelements, rsurface.modelelement3i + 3 * surface->num_firsttriangle, surface->num_triangles * sizeof(int[3]));
6286 batchtriangles = surface->num_triangles;
6287 firstvertex = surface->num_firstvertex;
6288 endvertex = surface->num_firstvertex + surface->num_vertices;
6289 for (;j < texturenumsurfaces;j++)
6291 surface2 = texturesurfacelist[j];
6292 if (surface2->lightmaptexture != surface->lightmaptexture || batchtriangles + surface2->num_triangles > MAXBATCHTRIANGLES)
6294 memcpy(batchelements + batchtriangles * 3, rsurface.modelelement3i + 3 * surface2->num_firsttriangle, surface2->num_triangles * sizeof(int[3]));
6295 batchtriangles += surface2->num_triangles;
6296 firstvertex = min(firstvertex, surface2->num_firstvertex);
6297 endvertex = max(endvertex, surface2->num_firstvertex + surface2->num_vertices);
6299 surface2 = texturesurfacelist[j-1];
6300 numvertices = endvertex - firstvertex;
6301 R_Mesh_Draw(firstvertex, numvertices, 0, batchtriangles, batchelements, NULL, 0, 0);
6304 else if (r_batchmode.integer == 1)
6307 Con_Printf("%s batch sizes ignoring lightmap:", rsurface.texture->name);
6308 for (i = 0;i < texturenumsurfaces;i = j)
6310 surface = texturesurfacelist[i];
6311 for (j = i + 1, surface2 = surface + 1;j < texturenumsurfaces;j++, surface2++)
6312 if (texturesurfacelist[j] != surface2)
6314 Con_Printf(" %i", j - i);
6317 Con_Printf("%s batch sizes honoring lightmap:", rsurface.texture->name);
6319 for (i = 0;i < texturenumsurfaces;i = j)
6321 surface = texturesurfacelist[i];
6322 R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
6323 if (deluxemaptexunit >= 0)
6324 R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
6325 for (j = i + 1, surface2 = surface + 1;j < texturenumsurfaces;j++, surface2++)
6326 if (texturesurfacelist[j] != surface2 || texturesurfacelist[j]->lightmaptexture != surface->lightmaptexture)
6329 Con_Printf(" %i", j - i);
6331 surface2 = texturesurfacelist[j-1];
6332 numvertices = surface2->num_firstvertex + surface2->num_vertices - surface->num_firstvertex;
6333 numtriangles = surface2->num_firsttriangle + surface2->num_triangles - surface->num_firsttriangle;
6334 GL_LockArrays(surface->num_firstvertex, numvertices);
6335 R_Mesh_Draw(surface->num_firstvertex, numvertices, surface->num_firsttriangle, numtriangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
6343 for (i = 0;i < texturenumsurfaces;i++)
6345 surface = texturesurfacelist[i];
6346 R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
6347 if (deluxemaptexunit >= 0)
6348 R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
6349 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
6350 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
6355 static void RSurf_DrawBatch_ShowSurfaces(int texturenumsurfaces, msurface_t **texturesurfacelist)
6358 int texturesurfaceindex;
6359 if (r_showsurfaces.integer == 2)
6361 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
6363 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
6364 for (j = 0;j < surface->num_triangles;j++)
6366 float f = ((j + surface->num_firsttriangle) & 31) * (1.0f / 31.0f) * r_refdef.view.colorscale;
6367 GL_Color(f, f, f, 1);
6368 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle + j, 1, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
6374 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
6376 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
6377 int k = (int)(((size_t)surface) / sizeof(msurface_t));
6378 GL_Color((k & 15) * (1.0f / 16.0f) * r_refdef.view.colorscale, ((k >> 4) & 15) * (1.0f / 16.0f) * r_refdef.view.colorscale, ((k >> 8) & 15) * (1.0f / 16.0f) * r_refdef.view.colorscale, 1);
6379 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
6380 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
6385 static void RSurf_DrawBatch_GL11_MakeFullbrightLightmapColorArray(int texturenumsurfaces, msurface_t **texturesurfacelist)
6387 int texturesurfaceindex;
6390 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
6392 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
6393 for (i = 0, v = (rsurface.vertex3f + 3 * surface->num_firstvertex), c2 = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c2 += 4)
6401 rsurface.lightmapcolor4f = rsurface.array_color4f;
6402 rsurface.lightmapcolor4f_bufferobject = 0;
6403 rsurface.lightmapcolor4f_bufferoffset = 0;
6406 static void RSurf_DrawBatch_GL11_ApplyFog(int texturenumsurfaces, msurface_t **texturesurfacelist)
6408 int texturesurfaceindex;
6412 if (rsurface.lightmapcolor4f)
6414 // generate color arrays for the surfaces in this list
6415 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
6417 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
6418 for (i = 0, v = (rsurface.vertex3f + 3 * surface->num_firstvertex), c = (rsurface.lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4, c2 += 4)
6420 f = FogPoint_Model(v);
6430 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
6432 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
6433 for (i = 0, v = (rsurface.vertex3f + 3 * surface->num_firstvertex), c2 = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c2 += 4)
6435 f = FogPoint_Model(v);
6443 rsurface.lightmapcolor4f = rsurface.array_color4f;
6444 rsurface.lightmapcolor4f_bufferobject = 0;
6445 rsurface.lightmapcolor4f_bufferoffset = 0;
6448 static void RSurf_DrawBatch_GL11_ApplyFogToFinishedVertexColors(int texturenumsurfaces, msurface_t **texturesurfacelist)
6450 int texturesurfaceindex;
6454 if (!rsurface.lightmapcolor4f)
6456 // generate color arrays for the surfaces in this list
6457 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
6459 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
6460 for (i = 0, v = (rsurface.vertex3f + 3 * surface->num_firstvertex), c = (rsurface.lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4, c2 += 4)
6462 f = FogPoint_Model(v);
6463 c2[0] = c[0] * f + r_refdef.fogcolor[0] * (1 - f);
6464 c2[1] = c[1] * f + r_refdef.fogcolor[1] * (1 - f);
6465 c2[2] = c[2] * f + r_refdef.fogcolor[2] * (1 - f);
6469 rsurface.lightmapcolor4f = rsurface.array_color4f;
6470 rsurface.lightmapcolor4f_bufferobject = 0;
6471 rsurface.lightmapcolor4f_bufferoffset = 0;
6474 static void RSurf_DrawBatch_GL11_ApplyColor(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a)
6476 int texturesurfaceindex;
6479 if (!rsurface.lightmapcolor4f)
6481 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
6483 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
6484 for (i = 0, c = (rsurface.lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, c += 4, c2 += 4)
6492 rsurface.lightmapcolor4f = rsurface.array_color4f;
6493 rsurface.lightmapcolor4f_bufferobject = 0;
6494 rsurface.lightmapcolor4f_bufferoffset = 0;
6497 static void RSurf_DrawBatch_GL11_ApplyAmbient(int texturenumsurfaces, msurface_t **texturesurfacelist)
6499 int texturesurfaceindex;
6502 if (!rsurface.lightmapcolor4f)
6504 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
6506 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
6507 for (i = 0, c = (rsurface.lightmapcolor4f + 4 * surface->num_firstvertex), c2 = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, c += 4, c2 += 4)
6509 c2[0] = c[0] + r_refdef.scene.ambient / 128.0;
6510 c2[1] = c[1] + r_refdef.scene.ambient / 128.0;
6511 c2[2] = c[2] + r_refdef.scene.ambient / 128.0;
6515 rsurface.lightmapcolor4f = rsurface.array_color4f;
6516 rsurface.lightmapcolor4f_bufferobject = 0;
6517 rsurface.lightmapcolor4f_bufferoffset = 0;
6520 static void RSurf_DrawBatch_GL11_Lightmap(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
6523 rsurface.lightmapcolor4f = NULL;
6524 rsurface.lightmapcolor4f_bufferobject = 0;
6525 rsurface.lightmapcolor4f_bufferoffset = 0;
6526 if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
6527 if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
6528 R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
6529 GL_Color(r, g, b, a);
6530 RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist, 0, -1);
6533 static void RSurf_DrawBatch_GL11_Unlit(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
6535 // TODO: optimize applyfog && applycolor case
6536 // just apply fog if necessary, and tint the fog color array if necessary
6537 rsurface.lightmapcolor4f = NULL;
6538 rsurface.lightmapcolor4f_bufferobject = 0;
6539 rsurface.lightmapcolor4f_bufferoffset = 0;
6540 if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
6541 if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
6542 R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
6543 GL_Color(r, g, b, a);
6544 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
6547 static void RSurf_DrawBatch_GL11_VertexColor(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
6549 int texturesurfaceindex;
6553 if (texturesurfacelist[0]->lightmapinfo)
6555 // generate color arrays for the surfaces in this list
6556 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
6558 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
6559 for (i = 0, c = rsurface.array_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
6561 if (surface->lightmapinfo->samples)
6563 const unsigned char *lm = surface->lightmapinfo->samples + (rsurface.modellightmapoffsets + surface->num_firstvertex)[i];
6564 float scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]] * (1.0f / 32768.0f);
6565 VectorScale(lm, scale, c);
6566 if (surface->lightmapinfo->styles[1] != 255)
6568 int size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
6570 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]] * (1.0f / 32768.0f);
6571 VectorMA(c, scale, lm, c);
6572 if (surface->lightmapinfo->styles[2] != 255)
6575 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]] * (1.0f / 32768.0f);
6576 VectorMA(c, scale, lm, c);
6577 if (surface->lightmapinfo->styles[3] != 255)
6580 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]] * (1.0f / 32768.0f);
6581 VectorMA(c, scale, lm, c);
6591 rsurface.lightmapcolor4f = rsurface.array_color4f;
6592 rsurface.lightmapcolor4f_bufferobject = 0;
6593 rsurface.lightmapcolor4f_bufferoffset = 0;
6597 rsurface.lightmapcolor4f = rsurface.modellightmapcolor4f;
6598 rsurface.lightmapcolor4f_bufferobject = rsurface.modellightmapcolor4f_bufferobject;
6599 rsurface.lightmapcolor4f_bufferoffset = rsurface.modellightmapcolor4f_bufferoffset;
6601 if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
6602 if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
6603 R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
6604 GL_Color(r, g, b, a);
6605 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
6608 static void RSurf_DrawBatch_GL11_ApplyVertexShade(int texturenumsurfaces, msurface_t **texturesurfacelist, float *r, float *g, float *b, float *a, qboolean *applycolor)
6610 int texturesurfaceindex;
6613 float *v, *c, *c2, alpha;
6614 vec3_t ambientcolor;
6615 vec3_t diffusecolor;
6619 VectorCopy(rsurface.modellight_lightdir, lightdir);
6620 f = 0.5f * r_refdef.lightmapintensity;
6621 ambientcolor[0] = rsurface.modellight_ambient[0] * *r * f;
6622 ambientcolor[1] = rsurface.modellight_ambient[1] * *g * f;
6623 ambientcolor[2] = rsurface.modellight_ambient[2] * *b * f;
6624 diffusecolor[0] = rsurface.modellight_diffuse[0] * *r * f;
6625 diffusecolor[1] = rsurface.modellight_diffuse[1] * *g * f;
6626 diffusecolor[2] = rsurface.modellight_diffuse[2] * *b * f;
6628 if (VectorLength2(diffusecolor) > 0 && rsurface.normal3f)
6630 // generate color arrays for the surfaces in this list
6631 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
6633 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
6634 int numverts = surface->num_vertices;
6635 v = rsurface.vertex3f + 3 * surface->num_firstvertex;
6636 c2 = rsurface.normal3f + 3 * surface->num_firstvertex;
6637 c = rsurface.array_color4f + 4 * surface->num_firstvertex;
6638 // q3-style directional shading
6639 for (i = 0;i < numverts;i++, v += 3, c2 += 3, c += 4)
6641 if ((f = DotProduct(c2, lightdir)) > 0)
6642 VectorMA(ambientcolor, f, diffusecolor, c);
6644 VectorCopy(ambientcolor, c);
6652 rsurface.lightmapcolor4f = rsurface.array_color4f;
6653 rsurface.lightmapcolor4f_bufferobject = 0;
6654 rsurface.lightmapcolor4f_bufferoffset = 0;
6655 *applycolor = false;
6659 *r = ambientcolor[0];
6660 *g = ambientcolor[1];
6661 *b = ambientcolor[2];
6662 rsurface.lightmapcolor4f = NULL;
6663 rsurface.lightmapcolor4f_bufferobject = 0;
6664 rsurface.lightmapcolor4f_bufferoffset = 0;
6668 static void RSurf_DrawBatch_GL11_VertexShade(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
6670 RSurf_DrawBatch_GL11_ApplyVertexShade(texturenumsurfaces, texturesurfacelist, &r, &g, &b, &a, &applycolor);
6671 if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
6672 if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
6673 R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
6674 GL_Color(r, g, b, a);
6675 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
6678 void RSurf_SetupDepthAndCulling(void)
6680 // submodels are biased to avoid z-fighting with world surfaces that they
6681 // may be exactly overlapping (avoids z-fighting artifacts on certain
6682 // doors and things in Quake maps)
6683 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
6684 GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
6685 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
6686 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
6689 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, msurface_t **texturesurfacelist)
6691 // transparent sky would be ridiculous
6692 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
6694 R_SetupGenericShader(false);
6697 skyrendernow = false;
6698 // we have to force off the water clipping plane while rendering sky
6702 // restore entity matrix
6703 R_Mesh_Matrix(&rsurface.matrix);
6705 RSurf_SetupDepthAndCulling();
6707 // LordHavoc: HalfLife maps have freaky skypolys so don't use
6708 // skymasking on them, and Quake3 never did sky masking (unlike
6709 // software Quake and software Quake2), so disable the sky masking
6710 // in Quake3 maps as it causes problems with q3map2 sky tricks,
6711 // and skymasking also looks very bad when noclipping outside the
6712 // level, so don't use it then either.
6713 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->type == mod_brushq1 && r_q1bsp_skymasking.integer && !r_refdef.viewcache.world_novis)
6715 GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
6716 R_Mesh_ColorPointer(NULL, 0, 0);
6717 R_Mesh_ResetTextureState();
6718 if (skyrendermasked)
6720 R_SetupDepthOrShadowShader();
6721 // depth-only (masking)
6722 GL_ColorMask(0,0,0,0);
6723 // just to make sure that braindead drivers don't draw
6724 // anything despite that colormask...
6725 GL_BlendFunc(GL_ZERO, GL_ONE);
6729 R_SetupGenericShader(false);
6731 GL_BlendFunc(GL_ONE, GL_ZERO);
6733 RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
6734 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
6735 if (skyrendermasked)
6736 GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
6738 R_Mesh_ResetTextureState();
6739 GL_Color(1, 1, 1, 1);
6742 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth)
6744 if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION)))
6747 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
6748 R_Mesh_TexMatrix(1, &rsurface.texture->currentbackgroundtexmatrix);
6749 R_Mesh_TexBind(GL20TU_NORMAL, R_GetTexture(rsurface.texture->currentskinframe->nmap));
6750 R_Mesh_TexBind(GL20TU_COLOR, R_GetTexture(rsurface.texture->basetexture));
6751 R_Mesh_TexBind(GL20TU_GLOSS, R_GetTexture(rsurface.texture->glosstexture));
6752 R_Mesh_TexBind(GL20TU_GLOW, R_GetTexture(rsurface.texture->currentskinframe->glow));
6753 if (rsurface.texture->backgroundcurrentskinframe)
6755 R_Mesh_TexBind(GL20TU_SECONDARY_NORMAL, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->nmap));
6756 R_Mesh_TexBind(GL20TU_SECONDARY_COLOR, R_GetTexture(rsurface.texture->backgroundbasetexture));
6757 R_Mesh_TexBind(GL20TU_SECONDARY_GLOSS, R_GetTexture(rsurface.texture->backgroundglosstexture));
6758 R_Mesh_TexBind(GL20TU_SECONDARY_GLOW, R_GetTexture(rsurface.texture->backgroundcurrentskinframe->glow));
6760 if(rsurface.texture->colormapping)
6762 R_Mesh_TexBind(GL20TU_PANTS, R_GetTexture(rsurface.texture->currentskinframe->pants));
6763 R_Mesh_TexBind(GL20TU_SHIRT, R_GetTexture(rsurface.texture->currentskinframe->shirt));
6765 R_Mesh_TexBind(GL20TU_FOGMASK, R_GetTexture(r_texture_fogattenuation));
6766 if ((rsurface.uselightmaptexture || (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)) && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
6767 R_Mesh_ColorPointer(NULL, 0, 0);
6769 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
6771 if (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
6773 // render background
6774 GL_BlendFunc(GL_ONE, GL_ZERO);
6776 GL_AlphaTest(false);
6778 GL_Color(1, 1, 1, 1);
6779 R_Mesh_ColorPointer(NULL, 0, 0);
6781 R_SetupSurfaceShader(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BACKGROUND);
6782 if (r_glsl_permutation)
6784 RSurf_PrepareVerticesForBatch(true, true, texturenumsurfaces, texturesurfacelist);
6785 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
6786 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
6787 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
6788 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
6789 R_Mesh_TexCoordPointer(4, 2, rsurface.modeltexcoordlightmap2f, rsurface.modeltexcoordlightmap2f_bufferobject, rsurface.modeltexcoordlightmap2f_bufferoffset);
6790 RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(texturenumsurfaces, texturesurfacelist, -1, -1, r_glsl_permutation->loc_Texture_Refraction >= 0 ? GL20TU_REFRACTION : -1, r_glsl_permutation->loc_Texture_Reflection >= 0 ? GL20TU_REFLECTION : -1);
6792 GL_LockArrays(0, 0);
6794 GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
6795 GL_DepthMask(false);
6796 if ((rsurface.uselightmaptexture || (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)) && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND))
6797 R_Mesh_ColorPointer(NULL, 0, 0);
6799 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
6800 R_Mesh_TexBind(GL20TU_REFRACTION, R_GetTexture(r_texture_white)); // changed per surface
6801 R_Mesh_TexBind(GL20TU_REFLECTION, R_GetTexture(r_texture_white)); // changed per surface
6804 R_SetupSurfaceShader(vec3_origin, (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT) != 0, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE);
6805 if (!r_glsl_permutation)
6808 RSurf_PrepareVerticesForBatch(r_glsl_permutation->loc_Texture_Normal >= 0 || r_glsl_permutation->loc_LightDir >= 0, r_glsl_permutation->loc_Texture_Normal >= 0, texturenumsurfaces, texturesurfacelist);
6809 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
6810 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
6811 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
6812 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
6813 R_Mesh_TexCoordPointer(4, 2, rsurface.modeltexcoordlightmap2f, rsurface.modeltexcoordlightmap2f_bufferobject, rsurface.modeltexcoordlightmap2f_bufferoffset);
6815 if (r_glsl_permutation->loc_Texture_Refraction >= 0)
6817 GL_BlendFunc(GL_ONE, GL_ZERO);
6819 GL_AlphaTest(false);
6823 GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
6824 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
6825 GL_AlphaTest((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
6828 if (rsurface.uselightmaptexture && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT))
6830 if (r_glsl_permutation->loc_Texture_Refraction >= 0 || r_glsl_permutation->loc_Texture_Reflection >= 0)
6831 RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(texturenumsurfaces, texturesurfacelist, GL20TU_LIGHTMAP, r_glsl_permutation->loc_Texture_Deluxemap >= 0 ? GL20TU_DELUXEMAP : -1, r_glsl_permutation->loc_Texture_Refraction >= 0 ? GL20TU_REFRACTION : -1, r_glsl_permutation->loc_Texture_Reflection >= 0 ? GL20TU_REFLECTION : -1);
6833 RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist, GL20TU_LIGHTMAP, r_glsl_permutation->loc_Texture_Deluxemap >= 0 ? GL20TU_DELUXEMAP : -1);
6837 if (r_glsl_permutation->loc_Texture_Refraction >= 0 || r_glsl_permutation->loc_Texture_Reflection >= 0)
6838 RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(texturenumsurfaces, texturesurfacelist, -1, -1, r_glsl_permutation->loc_Texture_Refraction >= 0 ? GL20TU_REFRACTION : -1, r_glsl_permutation->loc_Texture_Reflection >= 0 ? GL20TU_REFLECTION : -1);
6840 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
6842 GL_LockArrays(0, 0);
6845 static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth)
6847 // OpenGL 1.3 path - anything not completely ancient
6848 int texturesurfaceindex;
6849 qboolean applycolor;
6853 const texturelayer_t *layer;
6854 RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist);
6856 for (layerindex = 0, layer = rsurface.texture->currentlayers;layerindex < rsurface.texture->currentnumlayers;layerindex++, layer++)
6859 int layertexrgbscale;
6860 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
6862 if (layerindex == 0)
6866 GL_AlphaTest(false);
6867 qglDepthFunc(GL_EQUAL);CHECKGLERROR
6870 GL_DepthMask(layer->depthmask && writedepth);
6871 GL_BlendFunc(layer->blendfunc1, layer->blendfunc2);
6872 if (layer->color[0] > 2 || layer->color[1] > 2 || layer->color[2] > 2)
6874 layertexrgbscale = 4;
6875 VectorScale(layer->color, 0.25f, layercolor);
6877 else if (layer->color[0] > 1 || layer->color[1] > 1 || layer->color[2] > 1)
6879 layertexrgbscale = 2;
6880 VectorScale(layer->color, 0.5f, layercolor);
6884 layertexrgbscale = 1;
6885 VectorScale(layer->color, 1.0f, layercolor);
6887 layercolor[3] = layer->color[3];
6888 applycolor = layercolor[0] != 1 || layercolor[1] != 1 || layercolor[2] != 1 || layercolor[3] != 1;
6889 R_Mesh_ColorPointer(NULL, 0, 0);
6890 applyfog = (layer->flags & TEXTURELAYERFLAG_FOGDARKEN) != 0;
6891 switch (layer->type)
6893 case TEXTURELAYERTYPE_LITTEXTURE:
6894 memset(&m, 0, sizeof(m));
6895 m.tex[0] = R_GetTexture(r_texture_white);
6896 m.pointer_texcoord[0] = rsurface.modeltexcoordlightmap2f;
6897 m.pointer_texcoord_bufferobject[0] = rsurface.modeltexcoordlightmap2f_bufferobject;
6898 m.pointer_texcoord_bufferoffset[0] = rsurface.modeltexcoordlightmap2f_bufferoffset;
6899 m.tex[1] = R_GetTexture(layer->texture);
6900 m.texmatrix[1] = layer->texmatrix;
6901 m.texrgbscale[1] = layertexrgbscale;
6902 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
6903 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
6904 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
6905 R_Mesh_TextureState(&m);
6906 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
6907 RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
6908 else if (rsurface.uselightmaptexture)
6909 RSurf_DrawBatch_GL11_Lightmap(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
6911 RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
6913 case TEXTURELAYERTYPE_TEXTURE:
6914 memset(&m, 0, sizeof(m));
6915 m.tex[0] = R_GetTexture(layer->texture);
6916 m.texmatrix[0] = layer->texmatrix;
6917 m.texrgbscale[0] = layertexrgbscale;
6918 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
6919 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
6920 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
6921 R_Mesh_TextureState(&m);
6922 RSurf_DrawBatch_GL11_Unlit(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
6924 case TEXTURELAYERTYPE_FOG:
6925 memset(&m, 0, sizeof(m));
6926 m.texrgbscale[0] = layertexrgbscale;
6929 m.tex[0] = R_GetTexture(layer->texture);
6930 m.texmatrix[0] = layer->texmatrix;
6931 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
6932 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
6933 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
6935 R_Mesh_TextureState(&m);
6936 // generate a color array for the fog pass
6937 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
6938 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
6942 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
6943 for (i = 0, v = (rsurface.vertex3f + 3 * surface->num_firstvertex), c = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4)
6945 f = 1 - FogPoint_Model(v);
6946 c[0] = layercolor[0];
6947 c[1] = layercolor[1];
6948 c[2] = layercolor[2];
6949 c[3] = f * layercolor[3];
6952 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
6955 Con_Printf("R_DrawTextureSurfaceList: unknown layer type %i\n", layer->type);
6957 GL_LockArrays(0, 0);
6960 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
6962 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
6963 GL_AlphaTest(false);
6967 static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth)
6969 // OpenGL 1.1 - crusty old voodoo path
6970 int texturesurfaceindex;
6974 const texturelayer_t *layer;
6975 RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist);
6977 for (layerindex = 0, layer = rsurface.texture->currentlayers;layerindex < rsurface.texture->currentnumlayers;layerindex++, layer++)
6979 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
6981 if (layerindex == 0)
6985 GL_AlphaTest(false);
6986 qglDepthFunc(GL_EQUAL);CHECKGLERROR
6989 GL_DepthMask(layer->depthmask && writedepth);
6990 GL_BlendFunc(layer->blendfunc1, layer->blendfunc2);
6991 R_Mesh_ColorPointer(NULL, 0, 0);
6992 applyfog = (layer->flags & TEXTURELAYERFLAG_FOGDARKEN) != 0;
6993 switch (layer->type)
6995 case TEXTURELAYERTYPE_LITTEXTURE:
6996 if (layer->blendfunc1 == GL_ONE && layer->blendfunc2 == GL_ZERO)
6998 // two-pass lit texture with 2x rgbscale
6999 // first the lightmap pass
7000 memset(&m, 0, sizeof(m));
7001 m.tex[0] = R_GetTexture(r_texture_white);
7002 m.pointer_texcoord[0] = rsurface.modeltexcoordlightmap2f;
7003 m.pointer_texcoord_bufferobject[0] = rsurface.modeltexcoordlightmap2f_bufferobject;
7004 m.pointer_texcoord_bufferoffset[0] = rsurface.modeltexcoordlightmap2f_bufferoffset;
7005 R_Mesh_TextureState(&m);
7006 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
7007 RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
7008 else if (rsurface.uselightmaptexture)
7009 RSurf_DrawBatch_GL11_Lightmap(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
7011 RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
7012 GL_LockArrays(0, 0);
7013 // then apply the texture to it
7014 GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
7015 memset(&m, 0, sizeof(m));
7016 m.tex[0] = R_GetTexture(layer->texture);
7017 m.texmatrix[0] = layer->texmatrix;
7018 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
7019 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
7020 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
7021 R_Mesh_TextureState(&m);
7022 RSurf_DrawBatch_GL11_Unlit(texturenumsurfaces, texturesurfacelist, layer->color[0] * 0.5f, layer->color[1] * 0.5f, layer->color[2] * 0.5f, layer->color[3], layer->color[0] != 2 || layer->color[1] != 2 || layer->color[2] != 2 || layer->color[3] != 1, false);
7026 // single pass vertex-lighting-only texture with 1x rgbscale and transparency support
7027 memset(&m, 0, sizeof(m));
7028 m.tex[0] = R_GetTexture(layer->texture);
7029 m.texmatrix[0] = layer->texmatrix;
7030 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
7031 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
7032 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
7033 R_Mesh_TextureState(&m);
7034 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
7035 RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, layer->color[0], layer->color[1], layer->color[2], layer->color[3], layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog);
7037 RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, layer->color[0], layer->color[1], layer->color[2], layer->color[3], layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog);
7040 case TEXTURELAYERTYPE_TEXTURE:
7041 // singletexture unlit texture with transparency support
7042 memset(&m, 0, sizeof(m));
7043 m.tex[0] = R_GetTexture(layer->texture);
7044 m.texmatrix[0] = layer->texmatrix;
7045 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
7046 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
7047 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
7048 R_Mesh_TextureState(&m);
7049 RSurf_DrawBatch_GL11_Unlit(texturenumsurfaces, texturesurfacelist, layer->color[0], layer->color[1], layer->color[2], layer->color[3], layer->color[0] != 1 || layer->color[1] != 1 || layer->color[2] != 1 || layer->color[3] != 1, applyfog);
7051 case TEXTURELAYERTYPE_FOG:
7052 // singletexture fogging
7053 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
7056 memset(&m, 0, sizeof(m));
7057 m.tex[0] = R_GetTexture(layer->texture);
7058 m.texmatrix[0] = layer->texmatrix;
7059 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
7060 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
7061 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
7062 R_Mesh_TextureState(&m);
7065 R_Mesh_ResetTextureState();
7066 // generate a color array for the fog pass
7067 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
7071 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
7072 for (i = 0, v = (rsurface.vertex3f + 3 * surface->num_firstvertex), c = (rsurface.array_color4f + 4 * surface->num_firstvertex);i < surface->num_vertices;i++, v += 3, c += 4)
7074 f = 1 - FogPoint_Model(v);
7075 c[0] = layer->color[0];
7076 c[1] = layer->color[1];
7077 c[2] = layer->color[2];
7078 c[3] = f * layer->color[3];
7081 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
7084 Con_Printf("R_DrawTextureSurfaceList: unknown layer type %i\n", layer->type);
7086 GL_LockArrays(0, 0);
7089 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
7091 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
7092 GL_AlphaTest(false);
7096 static void R_DrawTextureSurfaceList_ShowSurfaces3(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth)
7100 GL_AlphaTest(false);
7101 R_Mesh_ColorPointer(NULL, 0, 0);
7102 R_Mesh_ResetTextureState();
7103 R_SetupGenericShader(false);
7105 if(rsurface.texture && rsurface.texture->currentskinframe)
7107 memcpy(c, rsurface.texture->currentskinframe->avgcolor, sizeof(c));
7108 c[3] *= rsurface.texture->currentalpha;
7118 if (rsurface.texture->currentskinframe->pants || rsurface.texture->currentskinframe->shirt)
7120 c[0] = 0.5 * (rsurface.colormap_pantscolor[0] * 0.3 + rsurface.colormap_shirtcolor[0] * 0.7);
7121 c[1] = 0.5 * (rsurface.colormap_pantscolor[1] * 0.3 + rsurface.colormap_shirtcolor[1] * 0.7);
7122 c[2] = 0.5 * (rsurface.colormap_pantscolor[2] * 0.3 + rsurface.colormap_shirtcolor[2] * 0.7);
7125 // brighten it up (as texture value 127 means "unlit")
7126 c[0] *= 2 * r_refdef.view.colorscale;
7127 c[1] *= 2 * r_refdef.view.colorscale;
7128 c[2] *= 2 * r_refdef.view.colorscale;
7130 if(rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERALPHA)
7131 c[3] *= r_wateralpha.value;
7133 if(rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHA && c[3] != 1)
7135 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
7136 GL_DepthMask(false);
7138 else if(rsurface.texture->currentmaterialflags & MATERIALFLAG_ADD)
7140 GL_BlendFunc(GL_ONE, GL_ONE);
7141 GL_DepthMask(false);
7143 else if(rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
7145 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // can't do alpha test without texture, so let's blend instead
7146 GL_DepthMask(false);
7148 else if(rsurface.texture->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
7150 GL_BlendFunc(rsurface.texture->customblendfunc[0], rsurface.texture->customblendfunc[1]);
7151 GL_DepthMask(false);
7155 GL_BlendFunc(GL_ONE, GL_ZERO);
7156 GL_DepthMask(writedepth);
7159 rsurface.lightmapcolor4f = NULL;
7161 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
7163 RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
7165 rsurface.lightmapcolor4f = NULL;
7166 rsurface.lightmapcolor4f_bufferobject = 0;
7167 rsurface.lightmapcolor4f_bufferoffset = 0;
7169 else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
7171 qboolean applycolor = true;
7174 RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist);
7176 r_refdef.lightmapintensity = 1;
7177 RSurf_DrawBatch_GL11_ApplyVertexShade(texturenumsurfaces, texturesurfacelist, &one, &one, &one, &one, &applycolor);
7178 r_refdef.lightmapintensity = 0; // we're in showsurfaces, after all
7182 RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
7184 rsurface.lightmapcolor4f = rsurface.modellightmapcolor4f;
7185 rsurface.lightmapcolor4f_bufferobject = rsurface.modellightmapcolor4f_bufferobject;
7186 rsurface.lightmapcolor4f_bufferoffset = rsurface.modellightmapcolor4f_bufferoffset;
7189 if(!rsurface.lightmapcolor4f)
7190 RSurf_DrawBatch_GL11_MakeFullbrightLightmapColorArray(texturenumsurfaces, texturesurfacelist);
7192 RSurf_DrawBatch_GL11_ApplyAmbient(texturenumsurfaces, texturesurfacelist);
7193 RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, c[0], c[1], c[2], c[3]);
7194 if(r_refdef.fogenabled)
7195 RSurf_DrawBatch_GL11_ApplyFogToFinishedVertexColors(texturenumsurfaces, texturesurfacelist);
7197 R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
7198 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
7201 static void R_DrawWorldTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth)
7204 RSurf_SetupDepthAndCulling();
7205 if (r_showsurfaces.integer == 3)
7206 R_DrawTextureSurfaceList_ShowSurfaces3(texturenumsurfaces, texturesurfacelist, writedepth);
7207 else if (r_glsl.integer && gl_support_fragment_shader)
7208 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth);
7209 else if (gl_combine.integer && r_textureunits.integer >= 2)
7210 R_DrawTextureSurfaceList_GL13(texturenumsurfaces, texturesurfacelist, writedepth);
7212 R_DrawTextureSurfaceList_GL11(texturenumsurfaces, texturesurfacelist, writedepth);
7216 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth)
7219 RSurf_SetupDepthAndCulling();
7220 if (r_showsurfaces.integer == 3)
7221 R_DrawTextureSurfaceList_ShowSurfaces3(texturenumsurfaces, texturesurfacelist, writedepth);
7222 else if (r_glsl.integer && gl_support_fragment_shader)
7223 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth);
7224 else if (gl_combine.integer && r_textureunits.integer >= 2)
7225 R_DrawTextureSurfaceList_GL13(texturenumsurfaces, texturesurfacelist, writedepth);
7227 R_DrawTextureSurfaceList_GL11(texturenumsurfaces, texturesurfacelist, writedepth);
7231 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
7234 int texturenumsurfaces, endsurface;
7236 msurface_t *surface;
7237 msurface_t *texturesurfacelist[1024];
7239 // if the model is static it doesn't matter what value we give for
7240 // wantnormals and wanttangents, so this logic uses only rules applicable
7241 // to a model, knowing that they are meaningless otherwise
7242 if (ent == r_refdef.scene.worldentity)
7243 RSurf_ActiveWorldEntity();
7244 else if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
7245 RSurf_ActiveModelEntity(ent, false, false);
7247 RSurf_ActiveModelEntity(ent, true, r_glsl.integer && gl_support_fragment_shader);
7249 for (i = 0;i < numsurfaces;i = j)
7252 surface = rsurface.modelsurfaces + surfacelist[i];
7253 texture = surface->texture;
7254 rsurface.texture = R_GetCurrentTexture(texture);
7255 rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
7256 // scan ahead until we find a different texture
7257 endsurface = min(i + 1024, numsurfaces);
7258 texturenumsurfaces = 0;
7259 texturesurfacelist[texturenumsurfaces++] = surface;
7260 for (;j < endsurface;j++)
7262 surface = rsurface.modelsurfaces + surfacelist[j];
7263 if (texture != surface->texture || rsurface.uselightmaptexture != (surface->lightmaptexture != NULL))
7265 texturesurfacelist[texturenumsurfaces++] = surface;
7267 // render the range of surfaces
7268 if (ent == r_refdef.scene.worldentity)
7269 R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false);
7271 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false);
7273 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
7274 GL_AlphaTest(false);
7277 static void R_ProcessWorldTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly)
7279 const entity_render_t *queueentity = r_refdef.scene.worldentity;
7283 if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
7285 if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
7287 RSurf_SetupDepthAndCulling();
7288 RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
7289 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
7291 else if (r_showsurfaces.integer && !r_refdef.view.showdebug)
7293 RSurf_SetupDepthAndCulling();
7294 GL_AlphaTest(false);
7295 R_Mesh_ColorPointer(NULL, 0, 0);
7296 R_Mesh_ResetTextureState();
7297 R_SetupGenericShader(false);
7298 RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
7300 GL_BlendFunc(GL_ONE, GL_ZERO);
7301 GL_Color(0, 0, 0, 1);
7302 GL_DepthTest(writedepth);
7303 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
7305 else if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
7307 RSurf_SetupDepthAndCulling();
7308 GL_AlphaTest(false);
7309 R_Mesh_ColorPointer(NULL, 0, 0);
7310 R_Mesh_ResetTextureState();
7311 R_SetupGenericShader(false);
7312 RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
7314 GL_BlendFunc(GL_ONE, GL_ZERO);
7316 RSurf_DrawBatch_ShowSurfaces(texturenumsurfaces, texturesurfacelist);
7318 else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY)
7319 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
7320 else if (!rsurface.texture->currentnumlayers)
7322 else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))) && queueentity)
7324 // transparent surfaces get pushed off into the transparent queue
7325 int surfacelistindex;
7326 const msurface_t *surface;
7327 vec3_t tempcenter, center;
7328 for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
7330 surface = texturesurfacelist[surfacelistindex];
7331 tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
7332 tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
7333 tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
7334 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
7335 R_MeshQueue_AddTransparent(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_refdef.view.origin : center, R_DrawSurface_TransparentCallback, queueentity, surface - rsurface.modelsurfaces, rsurface.rtlight);
7340 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
7341 R_DrawWorldTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST));
7346 void R_QueueWorldSurfaceList(int numsurfaces, msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly)
7350 // break the surface list down into batches by texture and use of lightmapping
7351 for (i = 0;i < numsurfaces;i = j)
7354 // texture is the base texture pointer, rsurface.texture is the
7355 // current frame/skin the texture is directing us to use (for example
7356 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
7357 // use skin 1 instead)
7358 texture = surfacelist[i]->texture;
7359 rsurface.texture = R_GetCurrentTexture(texture);
7360 rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
7361 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
7363 // if this texture is not the kind we want, skip ahead to the next one
7364 for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
7368 // simply scan ahead until we find a different texture or lightmap state
7369 for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.uselightmaptexture == (surfacelist[j]->lightmaptexture != NULL);j++)
7371 // render the range of surfaces
7372 R_ProcessWorldTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly);
7376 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, const entity_render_t *queueentity)
7381 if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
7383 if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
7385 RSurf_SetupDepthAndCulling();
7386 RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
7387 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
7389 else if (r_showsurfaces.integer && !r_refdef.view.showdebug)
7391 RSurf_SetupDepthAndCulling();
7392 GL_AlphaTest(false);
7393 R_Mesh_ColorPointer(NULL, 0, 0);
7394 R_Mesh_ResetTextureState();
7395 R_SetupGenericShader(false);
7396 RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
7398 GL_BlendFunc(GL_ONE, GL_ZERO);
7399 GL_Color(0, 0, 0, 1);
7400 GL_DepthTest(writedepth);
7401 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
7403 else if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
7405 RSurf_SetupDepthAndCulling();
7406 GL_AlphaTest(false);
7407 R_Mesh_ColorPointer(NULL, 0, 0);
7408 R_Mesh_ResetTextureState();
7409 R_SetupGenericShader(false);
7410 RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
7412 GL_BlendFunc(GL_ONE, GL_ZERO);
7414 RSurf_DrawBatch_ShowSurfaces(texturenumsurfaces, texturesurfacelist);
7416 else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY)
7417 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
7418 else if (!rsurface.texture->currentnumlayers)
7420 else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))) && queueentity)
7422 // transparent surfaces get pushed off into the transparent queue
7423 int surfacelistindex;
7424 const msurface_t *surface;
7425 vec3_t tempcenter, center;
7426 for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
7428 surface = texturesurfacelist[surfacelistindex];
7429 tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
7430 tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
7431 tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
7432 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
7433 R_MeshQueue_AddTransparent(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_refdef.view.origin : center, R_DrawSurface_TransparentCallback, queueentity, surface - rsurface.modelsurfaces, rsurface.rtlight);
7438 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
7439 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST));
7444 void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly)
7448 // break the surface list down into batches by texture and use of lightmapping
7449 for (i = 0;i < numsurfaces;i = j)
7452 // texture is the base texture pointer, rsurface.texture is the
7453 // current frame/skin the texture is directing us to use (for example
7454 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
7455 // use skin 1 instead)
7456 texture = surfacelist[i]->texture;
7457 rsurface.texture = R_GetCurrentTexture(texture);
7458 rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
7459 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
7461 // if this texture is not the kind we want, skip ahead to the next one
7462 for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
7466 // simply scan ahead until we find a different texture or lightmap state
7467 for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.uselightmaptexture == (surfacelist[j]->lightmaptexture != NULL);j++)
7469 // render the range of surfaces
7470 R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, ent);
7474 float locboxvertex3f[6*4*3] =
7476 1,0,1, 1,0,0, 1,1,0, 1,1,1,
7477 0,1,1, 0,1,0, 0,0,0, 0,0,1,
7478 1,1,1, 1,1,0, 0,1,0, 0,1,1,
7479 0,0,1, 0,0,0, 1,0,0, 1,0,1,
7480 0,0,1, 1,0,1, 1,1,1, 0,1,1,
7481 1,0,0, 0,0,0, 0,1,0, 1,1,0
7484 unsigned short locboxelements[6*2*3] =
7494 void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
7497 cl_locnode_t *loc = (cl_locnode_t *)ent;
7499 float vertex3f[6*4*3];
7501 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
7502 GL_DepthMask(false);
7503 GL_DepthRange(0, 1);
7504 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
7506 GL_CullFace(GL_NONE);
7507 R_Mesh_Matrix(&identitymatrix);
7509 R_Mesh_VertexPointer(vertex3f, 0, 0);
7510 R_Mesh_ColorPointer(NULL, 0, 0);
7511 R_Mesh_ResetTextureState();
7512 R_SetupGenericShader(false);
7515 GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
7516 ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale,
7517 ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale,
7518 surfacelist[0] < 0 ? 0.5f : 0.125f);
7520 if (VectorCompare(loc->mins, loc->maxs))
7522 VectorSet(size, 2, 2, 2);
7523 VectorMA(loc->mins, -0.5f, size, mins);
7527 VectorCopy(loc->mins, mins);
7528 VectorSubtract(loc->maxs, loc->mins, size);
7531 for (i = 0;i < 6*4*3;)
7532 for (j = 0;j < 3;j++, i++)
7533 vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
7535 R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, locboxelements, 0, 0);
7538 void R_DrawLocs(void)
7541 cl_locnode_t *loc, *nearestloc;
7543 nearestloc = CL_Locs_FindNearest(cl.movement_origin);
7544 for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
7546 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
7547 R_MeshQueue_AddTransparent(center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
7551 void R_DrawDebugModel(entity_render_t *ent)
7553 int i, j, k, l, flagsmask;
7554 const int *elements;
7556 msurface_t *surface;
7557 dp_model_t *model = ent->model;
7560 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
7562 R_Mesh_ColorPointer(NULL, 0, 0);
7563 R_Mesh_ResetTextureState();
7564 R_SetupGenericShader(false);
7565 GL_DepthRange(0, 1);
7566 GL_DepthTest(!r_showdisabledepthtest.integer);
7567 GL_DepthMask(false);
7568 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
7570 if (r_showcollisionbrushes.value > 0 && model->brush.num_brushes)
7572 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
7573 for (i = 0, brush = model->brush.data_brushes + model->firstmodelbrush;i < model->nummodelbrushes;i++, brush++)
7575 if (brush->colbrushf && brush->colbrushf->numtriangles)
7577 R_Mesh_VertexPointer(brush->colbrushf->points->v, 0, 0);
7578 GL_Color((i & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((i >> 5) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((i >> 10) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, r_showcollisionbrushes.value);
7579 R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, 0);
7582 for (i = 0, surface = model->data_surfaces + model->firstmodelsurface;i < model->nummodelsurfaces;i++, surface++)
7584 if (surface->num_collisiontriangles)
7586 R_Mesh_VertexPointer(surface->data_collisionvertex3f, 0, 0);
7587 GL_Color((i & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((i >> 5) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((i >> 10) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, r_showcollisionbrushes.value);
7588 R_Mesh_Draw(0, surface->num_collisionvertices, 0, surface->num_collisiontriangles, surface->data_collisionelement3i, NULL, 0, 0);
7593 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
7595 if (r_showtris.integer || r_shownormals.integer)
7597 if (r_showdisabledepthtest.integer)
7599 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
7600 GL_DepthMask(false);
7604 GL_BlendFunc(GL_ONE, GL_ZERO);
7607 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
7609 if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
7611 rsurface.texture = R_GetCurrentTexture(surface->texture);
7612 if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
7614 RSurf_PrepareVerticesForBatch(true, true, 1, &surface);
7615 if (r_showtris.value > 0)
7617 if (!rsurface.texture->currentlayers->depthmask)
7618 GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value);
7619 else if (ent == r_refdef.scene.worldentity)
7620 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
7622 GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
7623 elements = (ent->model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);
7624 R_Mesh_VertexPointer(rsurface.vertex3f, 0, 0);
7625 R_Mesh_ColorPointer(NULL, 0, 0);
7626 R_Mesh_TexCoordPointer(0, 0, NULL, 0, 0);
7627 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
7628 //R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, ent->model->surfmesh.data_element3i, NULL, 0, 0);
7629 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_firsttriangle, surface->num_triangles, rsurface.modelelement3i, rsurface.modelelement3s, rsurface.modelelement3i_bufferobject, rsurface.modelelement3s_bufferobject);
7630 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
7633 if (r_shownormals.value < 0)
7636 for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
7638 VectorCopy(rsurface.vertex3f + l * 3, v);
7639 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
7640 qglVertex3f(v[0], v[1], v[2]);
7641 VectorMA(v, -r_shownormals.value, rsurface.svector3f + l * 3, v);
7642 GL_Color(r_refdef.view.colorscale, 1, 1, 1);
7643 qglVertex3f(v[0], v[1], v[2]);
7648 if (r_shownormals.value > 0)
7651 for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
7653 VectorCopy(rsurface.vertex3f + l * 3, v);
7654 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
7655 qglVertex3f(v[0], v[1], v[2]);
7656 VectorMA(v, r_shownormals.value, rsurface.svector3f + l * 3, v);
7657 GL_Color(r_refdef.view.colorscale, 1, 1, 1);
7658 qglVertex3f(v[0], v[1], v[2]);
7663 for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
7665 VectorCopy(rsurface.vertex3f + l * 3, v);
7666 GL_Color(0, r_refdef.view.colorscale, 0, 1);
7667 qglVertex3f(v[0], v[1], v[2]);
7668 VectorMA(v, r_shownormals.value, rsurface.tvector3f + l * 3, v);
7669 GL_Color(r_refdef.view.colorscale, 1, 1, 1);
7670 qglVertex3f(v[0], v[1], v[2]);
7675 for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
7677 VectorCopy(rsurface.vertex3f + l * 3, v);
7678 GL_Color(0, 0, r_refdef.view.colorscale, 1);
7679 qglVertex3f(v[0], v[1], v[2]);
7680 VectorMA(v, r_shownormals.value, rsurface.normal3f + l * 3, v);
7681 GL_Color(r_refdef.view.colorscale, 1, 1, 1);
7682 qglVertex3f(v[0], v[1], v[2]);
7689 rsurface.texture = NULL;
7693 extern void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface);
7694 int r_maxsurfacelist = 0;
7695 msurface_t **r_surfacelist = NULL;
7696 void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug)
7698 int i, j, endj, f, flagsmask;
7700 dp_model_t *model = r_refdef.scene.worldmodel;
7701 msurface_t *surfaces;
7702 unsigned char *update;
7703 int numsurfacelist = 0;
7707 if (r_maxsurfacelist < model->num_surfaces)
7709 r_maxsurfacelist = model->num_surfaces;
7711 Mem_Free(r_surfacelist);
7712 r_surfacelist = (msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
7715 RSurf_ActiveWorldEntity();
7717 surfaces = model->data_surfaces;
7718 update = model->brushq1.lightmapupdateflags;
7720 // update light styles on this submodel
7721 if (!skysurfaces && !depthonly && model->brushq1.num_lightstyles && r_refdef.lightmapintensity > 0)
7723 model_brush_lightstyleinfo_t *style;
7724 for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++)
7726 if (style->value != r_refdef.scene.lightstylevalue[style->style])
7728 int *list = style->surfacelist;
7729 style->value = r_refdef.scene.lightstylevalue[style->style];
7730 for (j = 0;j < style->numsurfaces;j++)
7731 update[list[j]] = true;
7736 flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
7740 R_DrawDebugModel(r_refdef.scene.worldentity);
7741 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
7747 rsurface.uselightmaptexture = false;
7748 rsurface.texture = NULL;
7749 rsurface.rtlight = NULL;
7751 // add visible surfaces to draw list
7752 for (i = 0;i < model->nummodelsurfaces;i++)
7754 j = model->sortedmodelsurfaces[i];
7755 if (r_refdef.viewcache.world_surfacevisible[j])
7756 r_surfacelist[numsurfacelist++] = surfaces + j;
7758 // update lightmaps if needed
7760 for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
7761 if (r_refdef.viewcache.world_surfacevisible[j])
7763 R_BuildLightMap(r_refdef.scene.worldentity, surfaces + j);
7764 // don't do anything if there were no surfaces
7765 if (!numsurfacelist)
7767 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
7770 R_QueueWorldSurfaceList(numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly);
7771 GL_AlphaTest(false);
7773 // add to stats if desired
7774 if (r_speeds.integer && !skysurfaces && !depthonly)
7776 r_refdef.stats.world_surfaces += numsurfacelist;
7777 for (j = 0;j < numsurfacelist;j++)
7778 r_refdef.stats.world_triangles += r_surfacelist[j]->num_triangles;
7780 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
7783 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug)
7785 int i, j, endj, f, flagsmask;
7787 dp_model_t *model = ent->model;
7788 msurface_t *surfaces;
7789 unsigned char *update;
7790 int numsurfacelist = 0;
7794 if (r_maxsurfacelist < model->num_surfaces)
7796 r_maxsurfacelist = model->num_surfaces;
7798 Mem_Free(r_surfacelist);
7799 r_surfacelist = (msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
7802 // if the model is static it doesn't matter what value we give for
7803 // wantnormals and wanttangents, so this logic uses only rules applicable
7804 // to a model, knowing that they are meaningless otherwise
7805 if (ent == r_refdef.scene.worldentity)
7806 RSurf_ActiveWorldEntity();
7807 else if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
7808 RSurf_ActiveModelEntity(ent, false, false);
7810 RSurf_ActiveModelEntity(ent, true, r_glsl.integer && gl_support_fragment_shader && !depthonly);
7812 surfaces = model->data_surfaces;
7813 update = model->brushq1.lightmapupdateflags;
7815 // update light styles
7816 if (!skysurfaces && !depthonly && model->brushq1.num_lightstyles && r_refdef.lightmapintensity > 0)
7818 model_brush_lightstyleinfo_t *style;
7819 for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++)
7821 if (style->value != r_refdef.scene.lightstylevalue[style->style])
7823 int *list = style->surfacelist;
7824 style->value = r_refdef.scene.lightstylevalue[style->style];
7825 for (j = 0;j < style->numsurfaces;j++)
7826 update[list[j]] = true;
7831 flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
7835 R_DrawDebugModel(ent);
7836 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
7842 rsurface.uselightmaptexture = false;
7843 rsurface.texture = NULL;
7844 rsurface.rtlight = NULL;
7846 // add visible surfaces to draw list
7847 for (i = 0;i < model->nummodelsurfaces;i++)
7848 r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i];
7849 // don't do anything if there were no surfaces
7850 if (!numsurfacelist)
7852 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity
7855 // update lightmaps if needed
7857 for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
7859 R_BuildLightMap(ent, surfaces + j);
7860 R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly);
7861 GL_AlphaTest(false);
7863 // add to stats if desired
7864 if (r_speeds.integer && !skysurfaces && !depthonly)
7866 r_refdef.stats.entities_surfaces += numsurfacelist;
7867 for (j = 0;j < numsurfacelist;j++)
7868 r_refdef.stats.entities_triangles += r_surfacelist[j]->num_triangles;
7870 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveWorldEntity/RSurf_ActiveModelEntity