2 Copyright (C) 1996-1997 Id Software, Inc.
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 mempool_t *r_main_mempool;
28 rtexturepool_t *r_main_texturepool;
35 r_viewcache_t r_viewcache;
37 cvar_t r_depthfirst = {CVAR_SAVE, "r_depthfirst", "1", "renders a depth-only version of the scene before normal rendering begins to eliminate overdraw, values: 0 = off, 1 = world depth, 2 = world and model depth"};
38 cvar_t r_nearclip = {0, "r_nearclip", "1", "distance from camera of nearclip plane" };
39 cvar_t r_showbboxes = {0, "r_showbboxes", "0", "shows bounding boxes of server entities, value controls opacity scaling (1 = 10%, 10 = 100%)"};
40 cvar_t r_showsurfaces = {0, "r_showsurfaces", "0", "1 shows surfaces as different colors, or a value of 2 shows triangle draw order (for analyzing whether meshes are optimized for vertex cache)"};
41 cvar_t r_showtris = {0, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"};
42 cvar_t r_shownormals = {0, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"};
43 cvar_t r_showlighting = {0, "r_showlighting", "0", "shows areas lit by lights, useful for finding out why some areas of a map render slowly (bright orange = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"};
44 cvar_t r_showshadowvolumes = {0, "r_showshadowvolumes", "0", "shows areas shadowed by lights, useful for finding out why some areas of a map render slowly (bright blue = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"};
45 cvar_t r_showcollisionbrushes = {0, "r_showcollisionbrushes", "0", "draws collision brushes in quake3 maps (mode 1), mode 2 disables rendering of world (trippy!)"};
46 cvar_t r_showcollisionbrushes_polygonfactor = {0, "r_showcollisionbrushes_polygonfactor", "-1", "expands outward the brush polygons a little bit, used to make collision brushes appear infront of walls"};
47 cvar_t r_showcollisionbrushes_polygonoffset = {0, "r_showcollisionbrushes_polygonoffset", "0", "nudges brush polygon depth in hardware depth units, used to make collision brushes appear infront of walls"};
48 cvar_t r_showdisabledepthtest = {0, "r_showdisabledepthtest", "0", "disables depth testing on r_show* cvars, allowing you to see what hidden geometry the graphics card is processing"};
49 cvar_t r_drawportals = {0, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"};
50 cvar_t r_drawentities = {0, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"};
51 cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1", "draw your weapon model"};
52 cvar_t r_cullentities_trace = {0, "r_cullentities_trace", "1", "probabistically cull invisible entities"};
53 cvar_t r_cullentities_trace_samples = {0, "r_cullentities_trace_samples", "2", "number of samples to test for entity culling"};
54 cvar_t r_cullentities_trace_enlarge = {0, "r_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
55 cvar_t r_cullentities_trace_delay = {0, "r_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
56 cvar_t r_speeds = {0, "r_speeds","0", "displays rendering statistics and per-subsystem timings"};
57 cvar_t r_fullbright = {0, "r_fullbright","0", "makes map very bright and renders faster"};
58 cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1", "opacity of water polygons"};
59 cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1", "enables dynamic lights (rocket glow and such)"};
60 cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1", "enables glowing pixels in quake textures (changes need r_restart to take effect)"};
61 cvar_t r_shadows = {CVAR_SAVE, "r_shadows", "0", "casts fake stencil shadows from models onto the world (rtlights are unaffected by this)"};
62 cvar_t r_shadows_throwdistance = {CVAR_SAVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"};
63 cvar_t r_q1bsp_skymasking = {0, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
64 cvar_t r_polygonoffset_submodel_factor = {0, "r_polygonoffset_submodel_factor", "0", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
65 cvar_t r_polygonoffset_submodel_offset = {0, "r_polygonoffset_submodel_offset", "2", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
67 cvar_t gl_fogenable = {0, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"};
68 cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"};
69 cvar_t gl_fogred = {0, "gl_fogred","0.3", "nehahra fog color red value (for Nehahra compatibility only)"};
70 cvar_t gl_foggreen = {0, "gl_foggreen","0.3", "nehahra fog color green value (for Nehahra compatibility only)"};
71 cvar_t gl_fogblue = {0, "gl_fogblue","0.3", "nehahra fog color blue value (for Nehahra compatibility only)"};
72 cvar_t gl_fogstart = {0, "gl_fogstart", "0", "nehahra fog start distance (for Nehahra compatibility only)"};
73 cvar_t gl_fogend = {0, "gl_fogend","0", "nehahra fog end distance (for Nehahra compatibility only)"};
75 cvar_t r_textureunits = {0, "r_textureunits", "32", "number of hardware texture units reported by driver (note: setting this to 1 turns off gl_combine)"};
77 cvar_t r_glsl = {CVAR_SAVE, "r_glsl", "1", "enables use of OpenGL 2.0 pixel shaders for lighting"};
78 cvar_t r_glsl_offsetmapping = {CVAR_SAVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
79 cvar_t r_glsl_offsetmapping_reliefmapping = {CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
80 cvar_t r_glsl_offsetmapping_scale = {CVAR_SAVE, "r_glsl_offsetmapping_scale", "0.04", "how deep the offset mapping effect is"};
81 cvar_t r_glsl_deluxemapping = {CVAR_SAVE, "r_glsl_deluxemapping", "1", "use per pixel lighting on deluxemap-compiled q3bsp maps (or a value of 2 forces deluxemap shading even without deluxemaps)"};
82 cvar_t r_glsl_contrastboost = {CVAR_SAVE, "r_glsl_contrastboost", "1", "by how much to multiply the contrast in dark areas (1 is no change)"};
84 cvar_t r_water = {CVAR_SAVE, "r_water", "0", "whether to use reflections and refraction on water surfaces (note: r_wateralpha must be set below 1)"};
85 cvar_t r_water_clippingplanebias = {CVAR_SAVE, "r_water_clippingplanebias", "1", "a rather technical setting which avoids black pixels around water edges"};
86 cvar_t r_water_resolutionmultiplier = {CVAR_SAVE, "r_water_resolutionmultiplier", "0.5", "multiplier for screen resolution when rendering refracted/reflected scenes, 1 is full quality, lower values are faster"};
87 cvar_t r_water_refractdistort = {CVAR_SAVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
88 cvar_t r_water_reflectdistort = {CVAR_SAVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"};
90 cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "1", "enables animation smoothing on sprites (requires r_lerpmodels 1)"};
91 cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
92 cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
94 cvar_t r_bloom = {CVAR_SAVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"};
95 cvar_t r_bloom_colorscale = {CVAR_SAVE, "r_bloom_colorscale", "1", "how bright the glow is"};
96 cvar_t r_bloom_brighten = {CVAR_SAVE, "r_bloom_brighten", "2", "how bright the glow is, after subtract/power"};
97 cvar_t r_bloom_blur = {CVAR_SAVE, "r_bloom_blur", "4", "how large the glow is"};
98 cvar_t r_bloom_resolution = {CVAR_SAVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"};
99 cvar_t r_bloom_colorexponent = {CVAR_SAVE, "r_bloom_colorexponent", "1", "how exagerated the glow is"};
100 cvar_t r_bloom_colorsubtract = {CVAR_SAVE, "r_bloom_colorsubtract", "0.125", "reduces bloom colors by a certain amount"};
102 cvar_t r_hdr = {CVAR_SAVE, "r_hdr", "0", "enables High Dynamic Range bloom effect (higher quality version of r_bloom)"};
103 cvar_t r_hdr_scenebrightness = {CVAR_SAVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
104 cvar_t r_hdr_glowintensity = {CVAR_SAVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
105 cvar_t r_hdr_range = {CVAR_SAVE, "r_hdr_range", "4", "how much dynamic range to render bloom with (equivilant to multiplying r_bloom_brighten by this value and dividing r_bloom_colorscale by this value)"};
107 cvar_t r_smoothnormals_areaweighting = {0, "r_smoothnormals_areaweighting", "1", "uses significantly faster (and supposedly higher quality) area-weighted vertex normals and tangent vectors rather than summing normalized triangle normals and tangents"};
109 cvar_t developer_texturelogging = {0, "developer_texturelogging", "0", "produces a textures.log file containing names of skins and map textures the engine tried to load"};
111 cvar_t gl_lightmaps = {0, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers)"};
113 cvar_t r_test = {0, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
114 cvar_t r_batchmode = {0, "r_batchmode", "1", "selects method of rendering multiple surfaces with one driver call (values are 0, 1, 2, etc...)"};
116 extern qboolean v_flipped_state;
118 typedef struct r_glsl_bloomshader_s
121 int loc_Texture_Bloom;
123 r_glsl_bloomshader_t;
125 static struct r_bloomstate_s
130 int bloomwidth, bloomheight;
132 int screentexturewidth, screentextureheight;
133 rtexture_t *texture_screen;
135 int bloomtexturewidth, bloomtextureheight;
136 rtexture_t *texture_bloom;
138 r_glsl_bloomshader_t *shader;
140 // arrays for rendering the screen passes
141 float screentexcoord2f[8];
142 float bloomtexcoord2f[8];
143 float offsettexcoord2f[8];
147 typedef struct r_waterstate_waterplane_s
149 rtexture_t *texture_refraction;
150 rtexture_t *texture_reflection;
152 int materialflags; // combined flags of all water surfaces on this plane
153 unsigned char pvsbits[(32768+7)>>3]; // FIXME: buffer overflow on huge maps
156 r_waterstate_waterplane_t;
158 #define MAX_WATERPLANES 16
160 static struct r_waterstate_s
164 qboolean renderingscene; // true while rendering a refraction or reflection texture, disables water surfaces
166 int waterwidth, waterheight;
167 int texturewidth, textureheight;
169 int maxwaterplanes; // same as MAX_WATERPLANES
171 r_waterstate_waterplane_t waterplanes[MAX_WATERPLANES];
173 float screenscale[2];
174 float screencenter[2];
178 // shadow volume bsp struct with automatically growing nodes buffer
181 rtexture_t *r_texture_blanknormalmap;
182 rtexture_t *r_texture_white;
183 rtexture_t *r_texture_grey128;
184 rtexture_t *r_texture_black;
185 rtexture_t *r_texture_notexture;
186 rtexture_t *r_texture_whitecube;
187 rtexture_t *r_texture_normalizationcube;
188 rtexture_t *r_texture_fogattenuation;
189 //rtexture_t *r_texture_fogintensity;
191 char r_qwskincache[MAX_SCOREBOARD][MAX_QPATH];
192 skinframe_t *r_qwskincache_skinframe[MAX_SCOREBOARD];
194 // vertex coordinates for a quad that covers the screen exactly
195 const static float r_screenvertex3f[12] =
203 extern void R_DrawModelShadows(void);
205 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
208 for (i = 0;i < verts;i++)
219 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
222 for (i = 0;i < verts;i++)
232 // FIXME: move this to client?
235 if (gamemode == GAME_NEHAHRA)
237 Cvar_Set("gl_fogenable", "0");
238 Cvar_Set("gl_fogdensity", "0.2");
239 Cvar_Set("gl_fogred", "0.3");
240 Cvar_Set("gl_foggreen", "0.3");
241 Cvar_Set("gl_fogblue", "0.3");
243 r_refdef.fog_density = r_refdef.fog_red = r_refdef.fog_green = r_refdef.fog_blue = 0.0f;
246 float FogPoint_World(const vec3_t p)
248 int fogmasktableindex = (int)(VectorDistance((p), r_view.origin) * r_refdef.fogmasktabledistmultiplier);
249 return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
252 float FogPoint_Model(const vec3_t p)
254 int fogmasktableindex = (int)(VectorDistance((p), rsurface.modelorg) * r_refdef.fogmasktabledistmultiplier);
255 return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
258 static void R_BuildBlankTextures(void)
260 unsigned char data[4];
261 data[0] = 128; // normal X
262 data[1] = 128; // normal Y
263 data[2] = 255; // normal Z
264 data[3] = 128; // height
265 r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
270 r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
275 r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
280 r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
283 static void R_BuildNoTexture(void)
286 unsigned char pix[16][16][4];
287 // this makes a light grey/dark grey checkerboard texture
288 for (y = 0;y < 16;y++)
290 for (x = 0;x < 16;x++)
292 if ((y < 8) ^ (x < 8))
308 r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP, NULL);
311 static void R_BuildWhiteCube(void)
313 unsigned char data[6*1*1*4];
314 data[ 0] = 255;data[ 1] = 255;data[ 2] = 255;data[ 3] = 255;
315 data[ 4] = 255;data[ 5] = 255;data[ 6] = 255;data[ 7] = 255;
316 data[ 8] = 255;data[ 9] = 255;data[10] = 255;data[11] = 255;
317 data[12] = 255;data[13] = 255;data[14] = 255;data[15] = 255;
318 data[16] = 255;data[17] = 255;data[18] = 255;data[19] = 255;
319 data[20] = 255;data[21] = 255;data[22] = 255;data[23] = 255;
320 r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
323 static void R_BuildNormalizationCube(void)
327 vec_t s, t, intensity;
329 unsigned char data[6][NORMSIZE][NORMSIZE][4];
330 for (side = 0;side < 6;side++)
332 for (y = 0;y < NORMSIZE;y++)
334 for (x = 0;x < NORMSIZE;x++)
336 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
337 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
372 intensity = 127.0f / sqrt(DotProduct(v, v));
373 data[side][y][x][0] = (unsigned char)(128.0f + intensity * v[0]);
374 data[side][y][x][1] = (unsigned char)(128.0f + intensity * v[1]);
375 data[side][y][x][2] = (unsigned char)(128.0f + intensity * v[2]);
376 data[side][y][x][3] = 255;
380 r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, &data[0][0][0][0], TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
383 static void R_BuildFogTexture(void)
387 unsigned char data1[FOGWIDTH][4];
388 //unsigned char data2[FOGWIDTH][4];
389 for (x = 0;x < FOGWIDTH;x++)
391 b = (int)(r_refdef.fogmasktable[x * (FOGMASKTABLEWIDTH - 1) / (FOGWIDTH - 1)] * 255);
396 //data2[x][0] = 255 - b;
397 //data2[x][1] = 255 - b;
398 //data2[x][2] = 255 - b;
401 r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
402 //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
405 static const char *builtinshaderstring =
406 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
407 "// written by Forest 'LordHavoc' Hale\n"
409 "// common definitions between vertex shader and fragment shader:\n"
411 "#ifdef __GLSL_CG_DATA_TYPES\n"
412 "# define myhalf half\n"
413 "# define myhvec2 hvec2\n"
414 "# define myhvec3 hvec3\n"
415 "# define myhvec4 hvec4\n"
417 "# define myhalf float\n"
418 "# define myhvec2 vec2\n"
419 "# define myhvec3 vec3\n"
420 "# define myhvec4 vec4\n"
423 "varying vec2 TexCoord;\n"
424 "varying vec2 TexCoordLightmap;\n"
426 "//#ifdef MODE_LIGHTSOURCE\n"
427 "varying vec3 CubeVector;\n"
430 "//#ifdef MODE_LIGHTSOURCE\n"
431 "varying vec3 LightVector;\n"
433 "//# ifdef MODE_LIGHTDIRECTION\n"
434 "//varying vec3 LightVector;\n"
438 "varying vec3 EyeVector;\n"
440 "varying vec3 EyeVectorModelSpace;\n"
443 "varying vec3 VectorS; // direction of S texcoord (sometimes crudely called tangent)\n"
444 "varying vec3 VectorT; // direction of T texcoord (sometimes crudely called binormal)\n"
445 "varying vec3 VectorR; // direction of R texcoord (surface normal)\n"
447 "//#ifdef USEWATER\n"
448 "varying vec4 ModelViewProjectionPosition;\n"
450 "//# ifdef USEREFRACTION\n"
451 "//varying vec4 ModelViewProjectionPosition;\n"
453 "//# ifdef USEREFLECTION\n"
454 "//varying vec4 ModelViewProjectionPosition;\n"
463 "// vertex shader specific:\n"
464 "#ifdef VERTEX_SHADER\n"
466 "uniform vec3 LightPosition;\n"
467 "uniform vec3 EyePosition;\n"
468 "uniform vec3 LightDir;\n"
470 "// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3)\n"
474 " gl_FrontColor = gl_Color;\n"
475 " // copy the surface texcoord\n"
476 " TexCoord = vec2(gl_TextureMatrix[0] * gl_MultiTexCoord0);\n"
477 "#ifndef MODE_LIGHTSOURCE\n"
478 "# ifndef MODE_LIGHTDIRECTION\n"
479 " TexCoordLightmap = vec2(gl_MultiTexCoord4);\n"
483 "#ifdef MODE_LIGHTSOURCE\n"
484 " // transform vertex position into light attenuation/cubemap space\n"
485 " // (-1 to +1 across the light box)\n"
486 " CubeVector = vec3(gl_TextureMatrix[3] * gl_Vertex);\n"
488 " // transform unnormalized light direction into tangent space\n"
489 " // (we use unnormalized to ensure that it interpolates correctly and then\n"
490 " // normalize it per pixel)\n"
491 " vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n"
492 " LightVector.x = dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
493 " LightVector.y = dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
494 " LightVector.z = dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n"
497 "#ifdef MODE_LIGHTDIRECTION\n"
498 " LightVector.x = dot(LightDir, gl_MultiTexCoord1.xyz);\n"
499 " LightVector.y = dot(LightDir, gl_MultiTexCoord2.xyz);\n"
500 " LightVector.z = dot(LightDir, gl_MultiTexCoord3.xyz);\n"
503 " // transform unnormalized eye direction into tangent space\n"
505 " vec3 EyeVectorModelSpace;\n"
507 " EyeVectorModelSpace = EyePosition - gl_Vertex.xyz;\n"
508 " EyeVector.x = dot(EyeVectorModelSpace, gl_MultiTexCoord1.xyz);\n"
509 " EyeVector.y = dot(EyeVectorModelSpace, gl_MultiTexCoord2.xyz);\n"
510 " EyeVector.z = dot(EyeVectorModelSpace, gl_MultiTexCoord3.xyz);\n"
512 "#ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
513 " VectorS = gl_MultiTexCoord1.xyz;\n"
514 " VectorT = gl_MultiTexCoord2.xyz;\n"
515 " VectorR = gl_MultiTexCoord3.xyz;\n"
518 "//#if defined(USEWATER) || defined(USEREFRACTION) || defined(USEREFLECTION)\n"
519 "// ModelViewProjectionPosition = gl_Vertex * gl_ModelViewProjectionMatrix;\n"
520 "// //ModelViewProjectionPosition_svector = (gl_Vertex + vec4(gl_MultiTexCoord1.xyz, 0)) * gl_ModelViewProjectionMatrix - ModelViewProjectionPosition;\n"
521 "// //ModelViewProjectionPosition_tvector = (gl_Vertex + vec4(gl_MultiTexCoord2.xyz, 0)) * gl_ModelViewProjectionMatrix - ModelViewProjectionPosition;\n"
524 "// transform vertex to camera space, using ftransform to match non-VS\n"
526 " gl_Position = ftransform();\n"
528 "#ifdef MODE_WATER\n"
529 " ModelViewProjectionPosition = gl_Position;\n"
531 "#ifdef MODE_REFRACTION\n"
532 " ModelViewProjectionPosition = gl_Position;\n"
535 " ModelViewProjectionPosition = gl_Position;\n"
537 "#ifdef USEREFRACTION\n"
538 " ModelViewProjectionPosition = gl_Position;\n"
540 "#ifdef USEREFLECTION\n"
541 " ModelViewProjectionPosition = gl_Position;\n"
545 "#endif // VERTEX_SHADER\n"
550 "// fragment shader specific:\n"
551 "#ifdef FRAGMENT_SHADER\n"
553 "// 13 textures, we can only use up to 16 on DX9-class hardware\n"
554 "uniform sampler2D Texture_Normal;\n"
555 "uniform sampler2D Texture_Color;\n"
556 "uniform sampler2D Texture_Gloss;\n"
557 "uniform samplerCube Texture_Cube;\n"
558 "uniform sampler2D Texture_Attenuation;\n"
559 "uniform sampler2D Texture_FogMask;\n"
560 "uniform sampler2D Texture_Pants;\n"
561 "uniform sampler2D Texture_Shirt;\n"
562 "uniform sampler2D Texture_Lightmap;\n"
563 "uniform sampler2D Texture_Deluxemap;\n"
564 "uniform sampler2D Texture_Glow;\n"
565 "uniform sampler2D Texture_Reflection;\n"
566 "uniform sampler2D Texture_Refraction;\n"
568 "uniform myhvec3 LightColor;\n"
569 "uniform myhvec3 AmbientColor;\n"
570 "uniform myhvec3 DiffuseColor;\n"
571 "uniform myhvec3 SpecularColor;\n"
572 "uniform myhvec3 Color_Pants;\n"
573 "uniform myhvec3 Color_Shirt;\n"
574 "uniform myhvec3 FogColor;\n"
576 "//#ifdef USEWATER\n"
577 "uniform vec4 DistortScaleRefractReflect;\n"
578 "uniform vec4 ScreenScaleRefractReflect;\n"
579 "uniform vec4 ScreenCenterRefractReflect;\n"
580 "uniform myhvec4 RefractColor;\n"
581 "uniform myhvec4 ReflectColor;\n"
582 "uniform myhalf ReflectFactor;\n"
583 "uniform myhalf ReflectOffset;\n"
585 "//# ifdef USEREFRACTION\n"
586 "//uniform vec4 DistortScaleRefractReflect;\n"
587 "//uniform vec4 ScreenScaleRefractReflect;\n"
588 "//uniform vec4 ScreenCenterRefractReflect;\n"
589 "//uniform myhvec4 RefractColor;\n"
591 "//# ifdef USEREFLECTION\n"
592 "//uniform vec4 DistortScaleRefractReflect;\n"
593 "//uniform vec4 ScreenScaleRefractReflect;\n"
594 "//uniform vec4 ScreenCenterRefractReflect;\n"
595 "//uniform myhvec4 ReflectColor;\n"
600 "uniform myhalf GlowScale;\n"
601 "uniform myhalf SceneBrightness;\n"
602 "#ifdef USECONTRASTBOOST\n"
603 "uniform myhalf ContrastBoostCoeff;\n"
606 "uniform float OffsetMapping_Scale;\n"
607 "uniform float OffsetMapping_Bias;\n"
608 "uniform float FogRangeRecip;\n"
610 "uniform myhalf AmbientScale;\n"
611 "uniform myhalf DiffuseScale;\n"
612 "uniform myhalf SpecularScale;\n"
613 "uniform myhalf SpecularPower;\n"
615 "#ifdef USEOFFSETMAPPING\n"
616 "vec2 OffsetMapping(vec2 TexCoord)\n"
618 "#ifdef USEOFFSETMAPPING_RELIEFMAPPING\n"
619 " // 14 sample relief mapping: linear search and then binary search\n"
620 " // this basically steps forward a small amount repeatedly until it finds\n"
621 " // itself inside solid, then jitters forward and back using decreasing\n"
622 " // amounts to find the impact\n"
623 " //vec3 OffsetVector = vec3(EyeVector.xy * ((1.0 / EyeVector.z) * OffsetMapping_Scale) * vec2(-1, 1), -1);\n"
624 " //vec3 OffsetVector = vec3(normalize(EyeVector.xy) * OffsetMapping_Scale * vec2(-1, 1), -1);\n"
625 " vec3 OffsetVector = vec3(normalize(EyeVector).xy * OffsetMapping_Scale * vec2(-1, 1), -1);\n"
626 " vec3 RT = vec3(TexCoord, 1);\n"
627 " OffsetVector *= 0.1;\n"
628 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
629 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
630 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
631 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
632 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
633 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
634 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
635 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
636 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
637 " RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) - 0.5);\n"
638 " RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) * 0.5 - 0.25);\n"
639 " RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) * 0.25 - 0.125);\n"
640 " RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) * 0.125 - 0.0625);\n"
641 " RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) * 0.0625 - 0.03125);\n"
644 " // 3 sample offset mapping (only 3 samples because of ATI Radeon 9500-9800/X300 limits)\n"
645 " // this basically moves forward the full distance, and then backs up based\n"
646 " // on height of samples\n"
647 " //vec2 OffsetVector = vec2(EyeVector.xy * ((1.0 / EyeVector.z) * OffsetMapping_Scale) * vec2(-1, 1));\n"
648 " //vec2 OffsetVector = vec2(normalize(EyeVector.xy) * OffsetMapping_Scale * vec2(-1, 1));\n"
649 " vec2 OffsetVector = vec2(normalize(EyeVector).xy * OffsetMapping_Scale * vec2(-1, 1));\n"
650 " TexCoord += OffsetVector;\n"
651 " OffsetVector *= 0.333;\n"
652 " TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
653 " TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
654 " TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
655 " return TexCoord;\n"
658 "#endif // USEOFFSETMAPPING\n"
660 "#ifdef MODE_WATER\n"
665 "#ifdef USEOFFSETMAPPING\n"
666 " // apply offsetmapping\n"
667 " vec2 TexCoordOffset = OffsetMapping(TexCoord);\n"
668 "#define TexCoord TexCoordOffset\n"
671 " vec4 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect * (1.0 / ModelViewProjectionPosition.w);\n"
672 " //vec4 ScreenTexCoord = (ModelViewProjectionPosition.xyxy + normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
673 " vec4 ScreenTexCoord = ModelViewProjectionPosition.xyxy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect + vec2(normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5))).xyxy * DistortScaleRefractReflect;\n"
674 " float Fresnel = pow(min(1.0, 1.0 - float(normalize(EyeVector).z)), 5.0) * ReflectFactor + ReflectOffset;\n"
675 " gl_FragColor = mix(texture2D(Texture_Refraction, ScreenTexCoord.xy) * RefractColor, texture2D(Texture_Reflection, ScreenTexCoord.zw) * ReflectColor, Fresnel);\n"
678 "#else // MODE_WATER\n"
679 "#ifdef MODE_REFRACTION\n"
681 "// refraction pass\n"
684 "#ifdef USEOFFSETMAPPING\n"
685 " // apply offsetmapping\n"
686 " vec2 TexCoordOffset = OffsetMapping(TexCoord);\n"
687 "#define TexCoord TexCoordOffset\n"
690 " vec2 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect.xy * (1.0 / ModelViewProjectionPosition.w);\n"
691 " //vec2 ScreenTexCoord = (ModelViewProjectionPosition.xy + normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5)).xy * DistortScaleRefractReflect.xy * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy;\n"
692 " vec2 ScreenTexCoord = ModelViewProjectionPosition.xy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect.xy + vec2(normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5))).xy * DistortScaleRefractReflect.xy;\n"
693 " gl_FragColor = texture2D(Texture_Refraction, ScreenTexCoord) * RefractColor;\n"
696 "#else // MODE_REFRACTION\n"
699 "#ifdef USEOFFSETMAPPING\n"
700 " // apply offsetmapping\n"
701 " vec2 TexCoordOffset = OffsetMapping(TexCoord);\n"
702 "#define TexCoord TexCoordOffset\n"
705 " // combine the diffuse textures (base, pants, shirt)\n"
706 " myhvec4 color = myhvec4(texture2D(Texture_Color, TexCoord));\n"
707 "#ifdef USECOLORMAPPING\n"
708 " color.rgb += myhvec3(texture2D(Texture_Pants, TexCoord)) * Color_Pants + myhvec3(texture2D(Texture_Shirt, TexCoord)) * Color_Shirt;\n"
714 "#ifdef MODE_LIGHTSOURCE\n"
717 " // calculate surface normal, light normal, and specular normal\n"
718 " // compute color intensity for the two textures (colormap and glossmap)\n"
719 " // scale by light color and attenuation as efficiently as possible\n"
720 " // (do as much scalar math as possible rather than vector math)\n"
721 "# ifdef USESPECULAR\n"
722 " myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5));\n"
723 " myhvec3 diffusenormal = myhvec3(normalize(LightVector));\n"
724 " myhvec3 specularnormal = normalize(diffusenormal + myhvec3(normalize(EyeVector)));\n"
726 " // calculate directional shading\n"
727 " color.rgb = LightColor * myhalf(texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0))) * (color.rgb * (AmbientScale + DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0))) + (SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower)) * myhvec3(texture2D(Texture_Gloss, TexCoord)));\n"
729 "# ifdef USEDIFFUSE\n"
730 " myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5));\n"
731 " myhvec3 diffusenormal = myhvec3(normalize(LightVector));\n"
733 " // calculate directional shading\n"
734 " color.rgb = color.rgb * LightColor * (myhalf(texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0))) * (AmbientScale + DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0))));\n"
736 " // calculate directionless shading\n"
737 " color.rgb = color.rgb * LightColor * myhalf(texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0)));\n"
741 "# ifdef USECUBEFILTER\n"
742 " // apply light cubemap filter\n"
743 " //color.rgb *= normalize(CubeVector) * 0.5 + 0.5;//vec3(textureCube(Texture_Cube, CubeVector));\n"
744 " color.rgb *= myhvec3(textureCube(Texture_Cube, CubeVector));\n"
746 " color *= myhvec4(gl_Color);\n"
747 "#endif // MODE_LIGHTSOURCE\n"
752 "#ifdef MODE_LIGHTDIRECTION\n"
753 " // directional model lighting\n"
755 " // get the surface normal and light normal\n"
756 " myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5));\n"
757 " myhvec3 diffusenormal = myhvec3(LightVector);\n"
759 " // calculate directional shading\n"
760 " color.rgb *= AmbientColor + DiffuseColor * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0));\n"
761 "# ifdef USESPECULAR\n"
762 " myhvec3 specularnormal = normalize(diffusenormal + myhvec3(normalize(EyeVector)));\n"
763 " color.rgb += myhvec3(texture2D(Texture_Gloss, TexCoord)) * SpecularColor * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
765 " color *= myhvec4(gl_Color);\n"
766 "#endif // MODE_LIGHTDIRECTION\n"
771 "#ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
772 " // deluxemap lightmapping using light vectors in modelspace (evil q3map2)\n"
774 " // get the surface normal and light normal\n"
775 " myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5));\n"
777 " myhvec3 diffusenormal_modelspace = myhvec3(texture2D(Texture_Deluxemap, TexCoordLightmap)) - myhvec3(0.5);\n"
778 " myhvec3 diffusenormal = normalize(myhvec3(dot(diffusenormal_modelspace, myhvec3(VectorS)), dot(diffusenormal_modelspace, myhvec3(VectorT)), dot(diffusenormal_modelspace, myhvec3(VectorR))));\n"
779 " // calculate directional shading\n"
780 " myhvec3 tempcolor = color.rgb * (DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0)));\n"
781 "# ifdef USESPECULAR\n"
782 " myhvec3 specularnormal = myhvec3(normalize(diffusenormal + myhvec3(normalize(EyeVector))));\n"
783 " tempcolor += myhvec3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
786 " // apply lightmap color\n"
787 " color.rgb = myhvec4(tempcolor,1) * myhvec4(texture2D(Texture_Lightmap, TexCoordLightmap)) * myhvec4(gl_Color) + myhvec4(color.rgb * AmbientScale, 0);\n"
788 "#endif // MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
793 "#ifdef MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n"
794 " // deluxemap lightmapping using light vectors in tangentspace (hmap2 -light)\n"
796 " // get the surface normal and light normal\n"
797 " myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5));\n"
799 " myhvec3 diffusenormal = normalize(myhvec3(texture2D(Texture_Deluxemap, TexCoordLightmap)) - myhvec3(0.5));\n"
800 " // calculate directional shading\n"
801 " myhvec3 tempcolor = color.rgb * (DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0)));\n"
802 "# ifdef USESPECULAR\n"
803 " myhvec3 specularnormal = myhvec3(normalize(diffusenormal + myhvec3(normalize(EyeVector))));\n"
804 " tempcolor += myhvec3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
807 " // apply lightmap color\n"
808 " color = myhvec4(tempcolor, 1) * myhvec4(texture2D(Texture_Lightmap, TexCoordLightmap)) * myhvec4(gl_Color) + myhvec4(color.rgb * AmbientScale, 0);\n"
809 "#endif // MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n"
814 "#ifdef MODE_LIGHTMAP\n"
815 " // apply lightmap color\n"
816 " color *= myhvec4(texture2D(Texture_Lightmap, TexCoordLightmap)) * myhvec4(gl_Color) * myhvec4(myhvec3(DiffuseScale), 1) + myhvec4(myhvec3(AmbientScale), 0);\n"
817 "#endif // MODE_LIGHTMAP\n"
827 " color.rgb += myhvec3(texture2D(Texture_Glow, TexCoord)) * GlowScale;\n"
830 "#ifdef MODE_LIGHTSOURCE\n"
832 " color.rgb *= color.a;\n"
834 "# ifdef USEREFRACTION\n"
835 " color.rgb *= color.a;\n"
839 " vec4 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect * (1.0 / ModelViewProjectionPosition.w);\n"
840 " //vec4 ScreenTexCoord = (ModelViewProjectionPosition.xyxy + normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
841 " vec4 ScreenTexCoord = ModelViewProjectionPosition.xyxy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect + vec3(normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5))).xyxy * DistortScaleRefractReflect;\n"
842 " myhalf Fresnel = myhalf(pow(min(1.0, 1.0 - float(normalize(EyeVector).z)), 5.0)) * ReflectFactor + ReflectOffset;\n"
843 " color.rgb = mix(mix(myhvec3(texture2D(Texture_Refraction, ScreenTexCoord.xy)) * RefractColor.rgb, myhvec3(texture2D(Texture_Reflection, ScreenTexCoord.zw)) * ReflectColor.rgb, Fresnel), color.rgb, color.a);\n"
845 "# ifdef USEREFRACTION\n"
846 " vec4 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect * (1.0 / ModelViewProjectionPosition.w);\n"
847 " //vec4 ScreenTexCoord = (ModelViewProjectionPosition.xyxy + normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
848 " vec4 ScreenTexCoord = ModelViewProjectionPosition.xyxy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect + vec3(normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5))).xyxy * DistortScaleRefractReflect;\n"
849 " color.rgb = mix(myhvec3(texture2D(Texture_Refraction, ScreenTexCoord.xy)) * RefractColor.rgb, color.rgb, color.a);\n"
851 "# ifdef USEREFLECTION\n"
852 " vec4 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect * (1.0 / ModelViewProjectionPosition.w);\n"
853 " //vec4 ScreenTexCoord = (ModelViewProjectionPosition.xyxy + normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
854 " vec4 ScreenTexCoord = ModelViewProjectionPosition.xyxy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect + vec3(normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5))).xyxy * DistortScaleRefractReflect;\n"
855 " color.rgb = mix(color.rgb, myhvec3(texture2D(Texture_Reflection, ScreenTexCoord.zw)) * ReflectColor.rgb, ReflectColor.a);\n"
861 " color.rgb = mix(FogColor, color.rgb, myhalf(texture2D(Texture_FogMask, myhvec2(length(EyeVectorModelSpace)*FogRangeRecip, 0.0))));\n"
864 "#ifdef USECONTRASTBOOST\n"
865 " color.rgb = color.rgb / (ContrastBoostCoeff * color.rgb + myhvec3(1, 1, 1));\n"
868 " color.rgb *= SceneBrightness;\n"
870 " gl_FragColor = vec4(color);\n"
872 "#endif // MODE_REFRACTION\n"
873 "#endif // MODE_WATER\n"
875 "#endif // FRAGMENT_SHADER\n"
878 #define SHADERPERMUTATION_COLORMAPPING (1<<0) // indicates this is a colormapped skin
879 #define SHADERPERMUTATION_CONTRASTBOOST (1<<1) // r_glsl_contrastboost boosts the contrast at low color levels (similar to gamma)
880 #define SHADERPERMUTATION_FOG (1<<2) // tint the color by fog color or black if using additive blend mode
881 #define SHADERPERMUTATION_CUBEFILTER (1<<3) // (lightsource) use cubemap light filter
882 #define SHADERPERMUTATION_GLOW (1<<4) // (lightmap) blend in an additive glow texture
883 #define SHADERPERMUTATION_DIFFUSE (1<<5) // (lightsource) whether to use directional shading
884 #define SHADERPERMUTATION_SPECULAR (1<<6) // (lightsource or deluxemapping) render specular effects
885 #define SHADERPERMUTATION_REFLECTION (1<<7) // normalmap-perturbed reflection of the scene infront of the surface, preformed as an overlay on the surface
886 #define SHADERPERMUTATION_OFFSETMAPPING (1<<8) // adjust texcoords to roughly simulate a displacement mapped surface
887 #define SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING (1<<9) // adjust texcoords to accurately simulate a displacement mapped surface (requires OFFSETMAPPING to also be set!)
888 #define SHADERPERMUTATION_WATER (1<<10) // normalmap-perturbed refraction of the background, performed behind the surface (the texture or material must be transparent to see it)
889 #define SHADERPERMUTATION_REFRACTION (1<<11) // normalmap-perturbed reflection of the scene infront of the surface, preformed as an overlay on the surface
890 #define SHADERPERMUTATION_MODEBASE (1<<12) // multiplier for the SHADERMODE_ values to get a valid index
892 // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
893 const char *shaderpermutationinfo[][2] =
895 {"#define USECOLORMAPPING\n", " colormapping"},
896 {"#define USECONTRASTBOOST\n", " contrastboost"},
897 {"#define USEFOG\n", " fog"},
898 {"#define USECUBEFILTER\n", " cubefilter"},
899 {"#define USEGLOW\n", " glow"},
900 {"#define USEDIFFUSE\n", " diffuse"},
901 {"#define USESPECULAR\n", " specular"},
902 {"#define USEREFLECTION\n", " reflection"},
903 {"#define USEOFFSETMAPPING\n", " offsetmapping"},
904 {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
905 {"#define USEWATER\n", " water"},
906 {"#define USEREFRACTION\n", " refraction"},
910 // this enum is multiplied by SHADERPERMUTATION_MODEBASE
911 typedef enum shadermode_e
913 SHADERMODE_LIGHTMAP, // (lightmap) use directional pixel shading from fixed light direction (q3bsp)
914 SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE, // (lightmap) use directional pixel shading from texture containing modelspace light directions (deluxemap)
915 SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE, // (lightmap) use directional pixel shading from texture containing tangentspace light directions (deluxemap)
916 SHADERMODE_LIGHTDIRECTION, // (lightmap) use directional pixel shading from fixed light direction (q3bsp)
917 SHADERMODE_LIGHTSOURCE, // (lightsource) use directional pixel shading from light source (rtlight)
918 SHADERMODE_REFRACTION, // refract background (the material is rendered normally after this pass)
919 SHADERMODE_WATER, // refract background and reflection (the material is rendered normally after this pass)
924 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
925 const char *shadermodeinfo[][2] =
927 {"#define MODE_LIGHTMAP\n", " lightmap"},
928 {"#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
929 {"#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
930 {"#define MODE_LIGHTDIRECTION\n", " lightdirection"},
931 {"#define MODE_LIGHTSOURCE\n", " lightsource"},
932 {"#define MODE_REFRACTION\n", " refraction"},
933 {"#define MODE_WATER\n", " water"},
937 #define SHADERPERMUTATION_INDICES (SHADERPERMUTATION_MODEBASE * SHADERMODE_COUNT)
939 typedef struct r_glsl_permutation_s
941 // indicates if we have tried compiling this permutation already
943 // 0 if compilation failed
945 // locations of detected uniforms in program object, or -1 if not found
946 int loc_Texture_Normal;
947 int loc_Texture_Color;
948 int loc_Texture_Gloss;
949 int loc_Texture_Cube;
950 int loc_Texture_Attenuation;
951 int loc_Texture_FogMask;
952 int loc_Texture_Pants;
953 int loc_Texture_Shirt;
954 int loc_Texture_Lightmap;
955 int loc_Texture_Deluxemap;
956 int loc_Texture_Glow;
957 int loc_Texture_Refraction;
958 int loc_Texture_Reflection;
960 int loc_LightPosition;
965 int loc_FogRangeRecip;
966 int loc_AmbientScale;
967 int loc_DiffuseScale;
968 int loc_SpecularScale;
969 int loc_SpecularPower;
971 int loc_SceneBrightness; // or: Scenebrightness * ContrastBoost
972 int loc_OffsetMapping_Scale;
973 int loc_AmbientColor;
974 int loc_DiffuseColor;
975 int loc_SpecularColor;
977 int loc_ContrastBoostCoeff; // 1 - 1/ContrastBoost
978 int loc_DistortScaleRefractReflect;
979 int loc_ScreenScaleRefractReflect;
980 int loc_ScreenCenterRefractReflect;
981 int loc_RefractColor;
982 int loc_ReflectColor;
983 int loc_ReflectFactor;
984 int loc_ReflectOffset;
986 r_glsl_permutation_t;
988 // information about each possible shader permutation
989 r_glsl_permutation_t r_glsl_permutations[SHADERPERMUTATION_INDICES];
990 // currently selected permutation
991 r_glsl_permutation_t *r_glsl_permutation;
993 // these are additional flags used only by R_GLSL_CompilePermutation
994 #define SHADERTYPE_USES_VERTEXSHADER (1<<0)
995 #define SHADERTYPE_USES_GEOMETRYSHADER (1<<1)
996 #define SHADERTYPE_USES_FRAGMENTSHADER (1<<2)
998 static void R_GLSL_CompilePermutation(const char *filename, int permutation, int shadertype)
1001 qboolean shaderfound;
1002 r_glsl_permutation_t *p = r_glsl_permutations + permutation;
1003 int vertstrings_count;
1004 int geomstrings_count;
1005 int fragstrings_count;
1007 const char *vertstrings_list[32+1];
1008 const char *geomstrings_list[32+1];
1009 const char *fragstrings_list[32+1];
1010 char permutationname[256];
1015 vertstrings_list[0] = "#define VERTEX_SHADER\n";
1016 geomstrings_list[0] = "#define GEOMETRY_SHADER\n";
1017 fragstrings_list[0] = "#define FRAGMENT_SHADER\n";
1018 vertstrings_count = 1;
1019 geomstrings_count = 1;
1020 fragstrings_count = 1;
1021 permutationname[0] = 0;
1022 i = permutation / SHADERPERMUTATION_MODEBASE;
1023 vertstrings_list[vertstrings_count++] = shadermodeinfo[i][0];
1024 geomstrings_list[geomstrings_count++] = shadermodeinfo[i][0];
1025 fragstrings_list[fragstrings_count++] = shadermodeinfo[i][0];
1026 strlcat(permutationname, shadermodeinfo[i][1], sizeof(permutationname));
1027 for (i = 0;shaderpermutationinfo[i][0];i++)
1029 if (permutation & (1<<i))
1031 vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i][0];
1032 geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i][0];
1033 fragstrings_list[fragstrings_count++] = shaderpermutationinfo[i][0];
1034 strlcat(permutationname, shaderpermutationinfo[i][1], sizeof(permutationname));
1038 // keep line numbers correct
1039 vertstrings_list[vertstrings_count++] = "\n";
1040 geomstrings_list[geomstrings_count++] = "\n";
1041 fragstrings_list[fragstrings_count++] = "\n";
1044 shaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL);
1045 shaderfound = false;
1048 Con_DPrint("from disk... ");
1049 vertstrings_list[vertstrings_count++] = shaderstring;
1050 geomstrings_list[geomstrings_count++] = shaderstring;
1051 fragstrings_list[fragstrings_count++] = shaderstring;
1054 else if (!strcmp(filename, "glsl/default.glsl"))
1056 vertstrings_list[vertstrings_count++] = builtinshaderstring;
1057 geomstrings_list[geomstrings_count++] = builtinshaderstring;
1058 fragstrings_list[fragstrings_count++] = builtinshaderstring;
1061 // clear any lists that are not needed by this shader
1062 if (!(shadertype & SHADERTYPE_USES_VERTEXSHADER))
1063 vertstrings_count = 0;
1064 if (!(shadertype & SHADERTYPE_USES_GEOMETRYSHADER))
1065 geomstrings_count = 0;
1066 if (!(shadertype & SHADERTYPE_USES_FRAGMENTSHADER))
1067 fragstrings_count = 0;
1068 // compile the shader program
1069 if (shaderfound && vertstrings_count + geomstrings_count + fragstrings_count)
1070 p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
1074 qglUseProgramObjectARB(p->program);CHECKGLERROR
1075 // look up all the uniform variable names we care about, so we don't
1076 // have to look them up every time we set them
1077 p->loc_Texture_Normal = qglGetUniformLocationARB(p->program, "Texture_Normal");
1078 p->loc_Texture_Color = qglGetUniformLocationARB(p->program, "Texture_Color");
1079 p->loc_Texture_Gloss = qglGetUniformLocationARB(p->program, "Texture_Gloss");
1080 p->loc_Texture_Cube = qglGetUniformLocationARB(p->program, "Texture_Cube");
1081 p->loc_Texture_Attenuation = qglGetUniformLocationARB(p->program, "Texture_Attenuation");
1082 p->loc_Texture_FogMask = qglGetUniformLocationARB(p->program, "Texture_FogMask");
1083 p->loc_Texture_Pants = qglGetUniformLocationARB(p->program, "Texture_Pants");
1084 p->loc_Texture_Shirt = qglGetUniformLocationARB(p->program, "Texture_Shirt");
1085 p->loc_Texture_Lightmap = qglGetUniformLocationARB(p->program, "Texture_Lightmap");
1086 p->loc_Texture_Deluxemap = qglGetUniformLocationARB(p->program, "Texture_Deluxemap");
1087 p->loc_Texture_Glow = qglGetUniformLocationARB(p->program, "Texture_Glow");
1088 p->loc_Texture_Refraction = qglGetUniformLocationARB(p->program, "Texture_Refraction");
1089 p->loc_Texture_Reflection = qglGetUniformLocationARB(p->program, "Texture_Reflection");
1090 p->loc_FogColor = qglGetUniformLocationARB(p->program, "FogColor");
1091 p->loc_LightPosition = qglGetUniformLocationARB(p->program, "LightPosition");
1092 p->loc_EyePosition = qglGetUniformLocationARB(p->program, "EyePosition");
1093 p->loc_LightColor = qglGetUniformLocationARB(p->program, "LightColor");
1094 p->loc_Color_Pants = qglGetUniformLocationARB(p->program, "Color_Pants");
1095 p->loc_Color_Shirt = qglGetUniformLocationARB(p->program, "Color_Shirt");
1096 p->loc_FogRangeRecip = qglGetUniformLocationARB(p->program, "FogRangeRecip");
1097 p->loc_AmbientScale = qglGetUniformLocationARB(p->program, "AmbientScale");
1098 p->loc_DiffuseScale = qglGetUniformLocationARB(p->program, "DiffuseScale");
1099 p->loc_SpecularPower = qglGetUniformLocationARB(p->program, "SpecularPower");
1100 p->loc_SpecularScale = qglGetUniformLocationARB(p->program, "SpecularScale");
1101 p->loc_GlowScale = qglGetUniformLocationARB(p->program, "GlowScale");
1102 p->loc_SceneBrightness = qglGetUniformLocationARB(p->program, "SceneBrightness");
1103 p->loc_OffsetMapping_Scale = qglGetUniformLocationARB(p->program, "OffsetMapping_Scale");
1104 p->loc_AmbientColor = qglGetUniformLocationARB(p->program, "AmbientColor");
1105 p->loc_DiffuseColor = qglGetUniformLocationARB(p->program, "DiffuseColor");
1106 p->loc_SpecularColor = qglGetUniformLocationARB(p->program, "SpecularColor");
1107 p->loc_LightDir = qglGetUniformLocationARB(p->program, "LightDir");
1108 p->loc_ContrastBoostCoeff = qglGetUniformLocationARB(p->program, "ContrastBoostCoeff");
1109 p->loc_DistortScaleRefractReflect = qglGetUniformLocationARB(p->program, "DistortScaleRefractReflect");
1110 p->loc_ScreenScaleRefractReflect = qglGetUniformLocationARB(p->program, "ScreenScaleRefractReflect");
1111 p->loc_ScreenCenterRefractReflect = qglGetUniformLocationARB(p->program, "ScreenCenterRefractReflect");
1112 p->loc_RefractColor = qglGetUniformLocationARB(p->program, "RefractColor");
1113 p->loc_ReflectColor = qglGetUniformLocationARB(p->program, "ReflectColor");
1114 p->loc_ReflectFactor = qglGetUniformLocationARB(p->program, "ReflectFactor");
1115 p->loc_ReflectOffset = qglGetUniformLocationARB(p->program, "ReflectOffset");
1116 // initialize the samplers to refer to the texture units we use
1117 if (p->loc_Texture_Normal >= 0) qglUniform1iARB(p->loc_Texture_Normal, 0);
1118 if (p->loc_Texture_Color >= 0) qglUniform1iARB(p->loc_Texture_Color, 1);
1119 if (p->loc_Texture_Gloss >= 0) qglUniform1iARB(p->loc_Texture_Gloss, 2);
1120 if (p->loc_Texture_Cube >= 0) qglUniform1iARB(p->loc_Texture_Cube, 3);
1121 if (p->loc_Texture_FogMask >= 0) qglUniform1iARB(p->loc_Texture_FogMask, 4);
1122 if (p->loc_Texture_Pants >= 0) qglUniform1iARB(p->loc_Texture_Pants, 5);
1123 if (p->loc_Texture_Shirt >= 0) qglUniform1iARB(p->loc_Texture_Shirt, 6);
1124 if (p->loc_Texture_Lightmap >= 0) qglUniform1iARB(p->loc_Texture_Lightmap, 7);
1125 if (p->loc_Texture_Deluxemap >= 0) qglUniform1iARB(p->loc_Texture_Deluxemap, 8);
1126 if (p->loc_Texture_Glow >= 0) qglUniform1iARB(p->loc_Texture_Glow, 9);
1127 if (p->loc_Texture_Attenuation >= 0) qglUniform1iARB(p->loc_Texture_Attenuation, 10);
1128 if (p->loc_Texture_Refraction >= 0) qglUniform1iARB(p->loc_Texture_Refraction, 11);
1129 if (p->loc_Texture_Reflection >= 0) qglUniform1iARB(p->loc_Texture_Reflection, 12);
1131 qglUseProgramObjectARB(0);CHECKGLERROR
1132 if (developer.integer)
1133 Con_Printf("GLSL shader %s :%s compiled.\n", filename, permutationname);
1137 if (developer.integer)
1138 Con_Printf("GLSL shader %s :%s failed! source code line offset for above errors is %i.\n", permutationname, filename, -(vertstrings_count - 1));
1140 Con_Printf("GLSL shader %s :%s failed! some features may not work properly.\n", permutationname, filename);
1143 Mem_Free(shaderstring);
1146 void R_GLSL_Restart_f(void)
1149 for (i = 0;i < SHADERPERMUTATION_INDICES;i++)
1150 if (r_glsl_permutations[i].program)
1151 GL_Backend_FreeProgram(r_glsl_permutations[i].program);
1152 memset(r_glsl_permutations, 0, sizeof(r_glsl_permutations));
1155 void R_GLSL_DumpShader_f(void)
1159 qfile_t *file = FS_Open("glsl/default.glsl", "w", false, false);
1162 Con_Printf("failed to write to glsl/default.glsl\n");
1166 FS_Print(file, "// The engine may define the following macros:\n");
1167 FS_Print(file, "// #define VERTEX_SHADER\n// #define GEOMETRY_SHADER\n// #define FRAGMENT_SHADER\n");
1168 for (i = 0;shadermodeinfo[i][0];i++)
1169 FS_Printf(file, "// %s", shadermodeinfo[i][0]);
1170 for (i = 0;shaderpermutationinfo[i][0];i++)
1171 FS_Printf(file, "// %s", shaderpermutationinfo[i][0]);
1172 FS_Print(file, "\n");
1173 FS_Print(file, builtinshaderstring);
1176 Con_Printf("glsl/default.glsl written\n");
1179 extern rtexture_t *r_shadow_attenuationgradienttexture;
1180 extern rtexture_t *r_shadow_attenuation2dtexture;
1181 extern rtexture_t *r_shadow_attenuation3dtexture;
1182 int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, float ambientscale, float diffusescale, float specularscale, rsurfacepass_t rsurfacepass)
1184 // select a permutation of the lighting shader appropriate to this
1185 // combination of texture, entity, light source, and fogging, only use the
1186 // minimum features necessary to avoid wasting rendering time in the
1187 // fragment shader on features that are not being used
1188 const char *shaderfilename = NULL;
1189 unsigned int permutation = 0;
1190 unsigned int shadertype = 0;
1191 shadermode_t mode = 0;
1192 r_glsl_permutation = NULL;
1193 shaderfilename = "glsl/default.glsl";
1194 shadertype = SHADERTYPE_USES_VERTEXSHADER | SHADERTYPE_USES_FRAGMENTSHADER;
1195 // TODO: implement geometry-shader based shadow volumes someday
1196 if (r_glsl_offsetmapping.integer)
1198 permutation |= SHADERPERMUTATION_OFFSETMAPPING;
1199 if (r_glsl_offsetmapping_reliefmapping.integer)
1200 permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
1202 if (rsurfacepass == RSURFPASS_BACKGROUND)
1204 // distorted background
1205 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1206 mode = SHADERMODE_WATER;
1208 mode = SHADERMODE_REFRACTION;
1210 else if (rsurfacepass == RSURFPASS_RTLIGHT)
1213 mode = SHADERMODE_LIGHTSOURCE;
1214 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1215 permutation |= SHADERPERMUTATION_CUBEFILTER;
1216 if (diffusescale > 0)
1217 permutation |= SHADERPERMUTATION_DIFFUSE;
1218 if (specularscale > 0)
1219 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1220 if (r_refdef.fogenabled)
1221 permutation |= SHADERPERMUTATION_FOG;
1222 if (rsurface.texture->colormapping)
1223 permutation |= SHADERPERMUTATION_COLORMAPPING;
1224 if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
1225 permutation |= SHADERPERMUTATION_CONTRASTBOOST;
1226 //if (rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1227 // permutation |= SHADERPERMUTATION_WATER;
1228 //if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFRACTION)
1229 // permutation |= SHADERPERMUTATION_REFRACTION;
1230 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
1231 permutation |= SHADERPERMUTATION_REFLECTION;
1233 else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
1235 // bright unshaded geometry
1236 mode = SHADERMODE_LIGHTMAP;
1237 if (rsurface.texture->currentskinframe->glow)
1238 permutation |= SHADERPERMUTATION_GLOW;
1239 if (r_refdef.fogenabled)
1240 permutation |= SHADERPERMUTATION_FOG;
1241 if (rsurface.texture->colormapping)
1242 permutation |= SHADERPERMUTATION_COLORMAPPING;
1243 if (r_glsl_offsetmapping.integer)
1245 permutation |= SHADERPERMUTATION_OFFSETMAPPING;
1246 if (r_glsl_offsetmapping_reliefmapping.integer)
1247 permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
1249 if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
1250 permutation |= SHADERPERMUTATION_CONTRASTBOOST;
1251 //if (rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1252 // permutation |= SHADERPERMUTATION_WATER;
1253 //if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFRACTION)
1254 // permutation |= SHADERPERMUTATION_REFRACTION;
1255 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
1256 permutation |= SHADERPERMUTATION_REFLECTION;
1258 else if (modellighting)
1260 // directional model lighting
1261 mode = SHADERMODE_LIGHTDIRECTION;
1262 if (rsurface.texture->currentskinframe->glow)
1263 permutation |= SHADERPERMUTATION_GLOW;
1264 if (specularscale > 0)
1265 permutation |= SHADERPERMUTATION_SPECULAR;
1266 if (r_refdef.fogenabled)
1267 permutation |= SHADERPERMUTATION_FOG;
1268 if (rsurface.texture->colormapping)
1269 permutation |= SHADERPERMUTATION_COLORMAPPING;
1270 if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
1271 permutation |= SHADERPERMUTATION_CONTRASTBOOST;
1272 //if (rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1273 // permutation |= SHADERPERMUTATION_WATER;
1274 //if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFRACTION)
1275 // permutation |= SHADERPERMUTATION_REFRACTION;
1276 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
1277 permutation |= SHADERPERMUTATION_REFLECTION;
1282 if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping)
1284 // deluxemapping (light direction texture)
1285 if (rsurface.uselightmaptexture && r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping && r_refdef.worldmodel->brushq3.deluxemapping_modelspace)
1286 mode = SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE;
1288 mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1289 if (specularscale > 0)
1290 permutation |= SHADERPERMUTATION_SPECULAR;
1292 else if (r_glsl_deluxemapping.integer >= 2)
1294 // fake deluxemapping (uniform light direction in tangentspace)
1295 mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1296 if (specularscale > 0)
1297 permutation |= SHADERPERMUTATION_SPECULAR;
1301 // ordinary lightmapping
1302 mode = SHADERMODE_LIGHTMAP;
1304 if (rsurface.texture->currentskinframe->glow)
1305 permutation |= SHADERPERMUTATION_GLOW;
1306 if (r_refdef.fogenabled)
1307 permutation |= SHADERPERMUTATION_FOG;
1308 if (rsurface.texture->colormapping)
1309 permutation |= SHADERPERMUTATION_COLORMAPPING;
1310 if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
1311 permutation |= SHADERPERMUTATION_CONTRASTBOOST;
1312 //if (rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1313 // permutation |= SHADERPERMUTATION_WATER;
1314 //if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFRACTION)
1315 // permutation |= SHADERPERMUTATION_REFRACTION;
1316 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
1317 permutation |= SHADERPERMUTATION_REFLECTION;
1319 permutation |= mode * SHADERPERMUTATION_MODEBASE;
1320 if (!r_glsl_permutations[permutation].program)
1322 if (!r_glsl_permutations[permutation].compiled)
1323 R_GLSL_CompilePermutation(shaderfilename, permutation, shadertype);
1324 if (!r_glsl_permutations[permutation].program)
1326 // remove features until we find a valid permutation
1328 for (i = (SHADERPERMUTATION_MODEBASE >> 1);;i>>=1)
1332 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");
1333 Cvar_SetValueQuick(&r_glsl, 0);
1334 return 0; // no bit left to clear
1336 // reduce i more quickly whenever it would not remove any bits
1337 if (!(permutation & i))
1340 if (!r_glsl_permutations[permutation].compiled)
1341 R_GLSL_CompilePermutation(shaderfilename, permutation, shadertype);
1342 if (r_glsl_permutations[permutation].program)
1347 r_glsl_permutation = r_glsl_permutations + permutation;
1349 qglUseProgramObjectARB(r_glsl_permutation->program);CHECKGLERROR
1350 if (mode == SHADERMODE_LIGHTSOURCE)
1352 if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
1353 if (permutation & SHADERPERMUTATION_DIFFUSE)
1355 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightColor, lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);
1356 if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, ambientscale);
1357 if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, diffusescale);
1358 if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, specularscale);
1362 // ambient only is simpler
1363 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightColor, lightcolorbase[0] * ambientscale, lightcolorbase[1] * ambientscale, lightcolorbase[2] * ambientscale);
1364 if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, 1);
1365 if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, 0);
1366 if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, 0);
1369 else if (mode == SHADERMODE_LIGHTDIRECTION)
1371 if (r_glsl_permutation->loc_AmbientColor >= 0)
1372 qglUniform3fARB(r_glsl_permutation->loc_AmbientColor, rsurface.modellight_ambient[0] * ambientscale, rsurface.modellight_ambient[1] * ambientscale, rsurface.modellight_ambient[2] * ambientscale);
1373 if (r_glsl_permutation->loc_DiffuseColor >= 0)
1374 qglUniform3fARB(r_glsl_permutation->loc_DiffuseColor, rsurface.modellight_diffuse[0] * diffusescale, rsurface.modellight_diffuse[1] * diffusescale, rsurface.modellight_diffuse[2] * diffusescale);
1375 if (r_glsl_permutation->loc_SpecularColor >= 0)
1376 qglUniform3fARB(r_glsl_permutation->loc_SpecularColor, rsurface.modellight_diffuse[0] * specularscale, rsurface.modellight_diffuse[1] * specularscale, rsurface.modellight_diffuse[2] * specularscale);
1377 if (r_glsl_permutation->loc_LightDir >= 0)
1378 qglUniform3fARB(r_glsl_permutation->loc_LightDir, rsurface.modellight_lightdir[0], rsurface.modellight_lightdir[1], rsurface.modellight_lightdir[2]);
1382 if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, r_ambient.value * 2.0f / 128.0f);
1383 if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, r_refdef.lightmapintensity * 2.0f);
1384 if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, r_refdef.lightmapintensity * specularscale * 2.0f);
1386 if (r_glsl_permutation->loc_GlowScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_GlowScale, r_hdr_glowintensity.value);
1387 if (r_glsl_permutation->loc_ContrastBoostCoeff >= 0)
1389 // The formula used is actually:
1390 // color.rgb *= SceneBrightness;
1391 // color.rgb *= ContrastBoost / ((ContrastBoost - 1) * color.rgb + 1);
1392 // I simplify that to
1393 // color.rgb *= [[SceneBrightness * ContrastBoost]];
1394 // color.rgb /= [[(ContrastBoost - 1) / ContrastBoost]] * color.rgb + 1;
1396 // color.rgb = [[SceneBrightness * ContrastBoost]] / ([[(ContrastBoost - 1) * SceneBrightness]] + 1 / color.rgb);
1397 // and do [[calculations]] here in the engine
1398 qglUniform1fARB(r_glsl_permutation->loc_ContrastBoostCoeff, (r_glsl_contrastboost.value - 1) * r_view.colorscale);
1399 if (r_glsl_permutation->loc_SceneBrightness >= 0) qglUniform1fARB(r_glsl_permutation->loc_SceneBrightness, r_view.colorscale * r_glsl_contrastboost.value);
1402 if (r_glsl_permutation->loc_SceneBrightness >= 0) qglUniform1fARB(r_glsl_permutation->loc_SceneBrightness, r_view.colorscale);
1403 if (r_glsl_permutation->loc_FogColor >= 0)
1405 // additive passes are only darkened by fog, not tinted
1406 if (rsurface.rtlight || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ADD))
1407 qglUniform3fARB(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1409 qglUniform3fARB(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1411 if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_EyePosition, rsurface.modelorg[0], rsurface.modelorg[1], rsurface.modelorg[2]);
1412 if (r_glsl_permutation->loc_Color_Pants >= 0)
1414 if (rsurface.texture->currentskinframe->pants)
1415 qglUniform3fARB(r_glsl_permutation->loc_Color_Pants, rsurface.colormap_pantscolor[0], rsurface.colormap_pantscolor[1], rsurface.colormap_pantscolor[2]);
1417 qglUniform3fARB(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
1419 if (r_glsl_permutation->loc_Color_Shirt >= 0)
1421 if (rsurface.texture->currentskinframe->shirt)
1422 qglUniform3fARB(r_glsl_permutation->loc_Color_Shirt, rsurface.colormap_shirtcolor[0], rsurface.colormap_shirtcolor[1], rsurface.colormap_shirtcolor[2]);
1424 qglUniform3fARB(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
1426 if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1fARB(r_glsl_permutation->loc_FogRangeRecip, r_refdef.fograngerecip);
1427 if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularPower, rsurface.texture->specularpower);
1428 if (r_glsl_permutation->loc_OffsetMapping_Scale >= 0) qglUniform1fARB(r_glsl_permutation->loc_OffsetMapping_Scale, r_glsl_offsetmapping_scale.value);
1429 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);
1430 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]);
1431 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]);
1432 if (r_glsl_permutation->loc_RefractColor >= 0) qglUniform4fvARB(r_glsl_permutation->loc_RefractColor, 1, rsurface.texture->refractcolor4f);
1433 if (r_glsl_permutation->loc_ReflectColor >= 0) qglUniform4fvARB(r_glsl_permutation->loc_ReflectColor, 1, rsurface.texture->reflectcolor4f);
1434 if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1fARB(r_glsl_permutation->loc_ReflectFactor, rsurface.texture->reflectmax - rsurface.texture->reflectmin);
1435 if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1fARB(r_glsl_permutation->loc_ReflectOffset, rsurface.texture->reflectmin);
1440 #define SKINFRAME_HASH 1024
1444 int loadsequence; // incremented each level change
1445 memexpandablearray_t array;
1446 skinframe_t *hash[SKINFRAME_HASH];
1450 void R_SkinFrame_PrepareForPurge(void)
1452 r_skinframe.loadsequence++;
1453 // wrap it without hitting zero
1454 if (r_skinframe.loadsequence >= 200)
1455 r_skinframe.loadsequence = 1;
1458 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
1462 // mark the skinframe as used for the purging code
1463 skinframe->loadsequence = r_skinframe.loadsequence;
1466 void R_SkinFrame_Purge(void)
1470 for (i = 0;i < SKINFRAME_HASH;i++)
1472 for (s = r_skinframe.hash[i];s;s = s->next)
1474 if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
1476 if (s->base == r_texture_notexture) s->base = NULL;
1477 if (s->nmap == r_texture_blanknormalmap)s->nmap = NULL;
1478 if (s->merged == s->base) s->merged = NULL;
1479 if (s->stain ) R_FreeTexture(s->stain );s->stain = NULL;
1480 if (s->merged) R_FreeTexture(s->merged);s->merged = NULL;
1481 if (s->base ) R_FreeTexture(s->base );s->base = NULL;
1482 if (s->pants ) R_FreeTexture(s->pants );s->pants = NULL;
1483 if (s->shirt ) R_FreeTexture(s->shirt );s->shirt = NULL;
1484 if (s->nmap ) R_FreeTexture(s->nmap );s->nmap = NULL;
1485 if (s->gloss ) R_FreeTexture(s->gloss );s->gloss = NULL;
1486 if (s->glow ) R_FreeTexture(s->glow );s->glow = NULL;
1487 if (s->fog ) R_FreeTexture(s->fog );s->fog = NULL;
1488 s->loadsequence = 0;
1494 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qboolean add)
1498 char basename[MAX_QPATH];
1500 Image_StripImageExtension(name, basename, sizeof(basename));
1502 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
1503 for (item = r_skinframe.hash[hashindex];item;item = item->next)
1504 if (!strcmp(item->basename, basename) && item->textureflags == textureflags && item->comparewidth == comparewidth && item->compareheight == compareheight && item->comparecrc == comparecrc)
1510 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
1511 memset(item, 0, sizeof(*item));
1512 strlcpy(item->basename, basename, sizeof(item->basename));
1513 item->textureflags = textureflags;
1514 item->comparewidth = comparewidth;
1515 item->compareheight = compareheight;
1516 item->comparecrc = comparecrc;
1517 item->next = r_skinframe.hash[hashindex];
1518 r_skinframe.hash[hashindex] = item;
1520 R_SkinFrame_MarkUsed(item);
1524 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain)
1526 // FIXME: it should be possible to disable loading various layers using
1527 // cvars, to prevent wasted loading time and memory usage if the user does
1529 qboolean loadnormalmap = true;
1530 qboolean loadgloss = true;
1531 qboolean loadpantsandshirt = true;
1532 qboolean loadglow = true;
1534 unsigned char *pixels;
1535 unsigned char *bumppixels;
1536 unsigned char *basepixels = NULL;
1537 int basepixels_width;
1538 int basepixels_height;
1539 skinframe_t *skinframe;
1541 if (cls.state == ca_dedicated)
1544 // return an existing skinframe if already loaded
1545 // if loading of the first image fails, don't make a new skinframe as it
1546 // would cause all future lookups of this to be missing
1547 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
1548 if (skinframe && skinframe->base)
1551 basepixels = loadimagepixels(name, complain, 0, 0);
1552 if (basepixels == NULL)
1555 // we've got some pixels to store, so really allocate this new texture now
1557 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
1558 skinframe->stain = NULL;
1559 skinframe->merged = NULL;
1560 skinframe->base = r_texture_notexture;
1561 skinframe->pants = NULL;
1562 skinframe->shirt = NULL;
1563 skinframe->nmap = r_texture_blanknormalmap;
1564 skinframe->gloss = NULL;
1565 skinframe->glow = NULL;
1566 skinframe->fog = NULL;
1568 basepixels_width = image_width;
1569 basepixels_height = image_height;
1570 skinframe->base = R_LoadTexture2D (r_main_texturepool, skinframe->basename, basepixels_width, basepixels_height, basepixels, TEXTYPE_RGBA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL);
1572 if (textureflags & TEXF_ALPHA)
1574 for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
1575 if (basepixels[j] < 255)
1577 if (j < basepixels_width * basepixels_height * 4)
1579 // has transparent pixels
1580 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
1581 for (j = 0;j < image_width * image_height * 4;j += 4)
1586 pixels[j+3] = basepixels[j+3];
1588 skinframe->fog = R_LoadTexture2D (r_main_texturepool, va("%s_mask", skinframe->basename), image_width, image_height, pixels, TEXTYPE_RGBA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL);
1593 // _norm is the name used by tenebrae and has been adopted as standard
1596 if ((pixels = loadimagepixels(va("%s_norm", skinframe->basename), false, 0, 0)) != NULL)
1598 skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va("%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_RGBA, skinframe->textureflags & (gl_texturecompression_normal.integer ? ~0 : ~TEXF_COMPRESS), NULL);
1602 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixels(va("%s_bump", skinframe->basename), false, 0, 0)) != NULL)
1604 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
1605 Image_HeightmapToNormalmap(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
1606 skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va("%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_RGBA, skinframe->textureflags & (gl_texturecompression_normal.integer ? ~0 : ~TEXF_COMPRESS), NULL);
1608 Mem_Free(bumppixels);
1610 else if (r_shadow_bumpscale_basetexture.value > 0)
1612 pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
1613 Image_HeightmapToNormalmap(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
1614 skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va("%s_nmap", skinframe->basename), basepixels_width, basepixels_height, pixels, TEXTYPE_RGBA, skinframe->textureflags & (gl_texturecompression_normal.integer ? ~0 : ~TEXF_COMPRESS), NULL);
1618 // _luma is supported for tenebrae compatibility
1619 // (I think it's a very stupid name, but oh well)
1620 // _glow is the preferred name
1621 if (loadglow && ((pixels = loadimagepixels(va("%s_glow", skinframe->basename), false, 0, 0)) != NULL || (pixels = loadimagepixels(va("%s_luma", skinframe->basename), false, 0, 0)) != NULL)) {skinframe->glow = R_LoadTexture2D (r_main_texturepool, va("%s_glow", skinframe->basename), image_width, image_height, pixels, TEXTYPE_RGBA, skinframe->textureflags & (gl_texturecompression_glow.integer ? ~0 : ~TEXF_COMPRESS), NULL);Mem_Free(pixels);pixels = NULL;}
1622 if (loadgloss && (pixels = loadimagepixels(va("%s_gloss", skinframe->basename), false, 0, 0)) != NULL) {skinframe->gloss = R_LoadTexture2D (r_main_texturepool, va("%s_gloss", skinframe->basename), image_width, image_height, pixels, TEXTYPE_RGBA, skinframe->textureflags & (gl_texturecompression_gloss.integer ? ~0 : ~TEXF_COMPRESS), NULL);Mem_Free(pixels);pixels = NULL;}
1623 if (loadpantsandshirt && (pixels = loadimagepixels(va("%s_pants", skinframe->basename), false, 0, 0)) != NULL) {skinframe->pants = R_LoadTexture2D (r_main_texturepool, va("%s_pants", skinframe->basename), image_width, image_height, pixels, TEXTYPE_RGBA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL);Mem_Free(pixels);pixels = NULL;}
1624 if (loadpantsandshirt && (pixels = loadimagepixels(va("%s_shirt", skinframe->basename), false, 0, 0)) != NULL) {skinframe->shirt = R_LoadTexture2D (r_main_texturepool, va("%s_shirt", skinframe->basename), image_width, image_height, pixels, TEXTYPE_RGBA, skinframe->textureflags & (gl_texturecompression_color.integer ? ~0 : ~TEXF_COMPRESS), NULL);Mem_Free(pixels);pixels = NULL;}
1627 Mem_Free(basepixels);
1632 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)
1637 for (i = 0;i < width*height;i++)
1638 if (((unsigned char *)&palette[in[i]])[3] > 0)
1640 if (i == width*height)
1643 return R_LoadTexture2D (r_main_texturepool, name, width, height, in, TEXTYPE_PALETTE, textureflags, palette);
1646 skinframe_t *R_SkinFrame_LoadInternal(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height, int bitsperpixel, const unsigned int *palette, const unsigned int *alphapalette)
1649 unsigned char *temp1, *temp2;
1650 skinframe_t *skinframe;
1652 if (cls.state == ca_dedicated)
1655 // if already loaded just return it, otherwise make a new skinframe
1656 skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height*bitsperpixel/8) : 0, true);
1657 if (skinframe && skinframe->base)
1660 skinframe->stain = NULL;
1661 skinframe->merged = NULL;
1662 skinframe->base = r_texture_notexture;
1663 skinframe->pants = NULL;
1664 skinframe->shirt = NULL;
1665 skinframe->nmap = r_texture_blanknormalmap;
1666 skinframe->gloss = NULL;
1667 skinframe->glow = NULL;
1668 skinframe->fog = NULL;
1670 // if no data was provided, then clearly the caller wanted to get a blank skinframe
1674 if (bitsperpixel == 32)
1676 if (r_shadow_bumpscale_basetexture.value > 0)
1678 temp1 = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
1679 temp2 = temp1 + width * height * 4;
1680 Image_HeightmapToNormalmap(skindata, temp2, width, height, false, r_shadow_bumpscale_basetexture.value);
1681 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va("%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_RGBA, skinframe->textureflags | TEXF_ALPHA, NULL);
1684 skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_RGBA, skinframe->textureflags, NULL);
1685 if (textureflags & TEXF_ALPHA)
1687 for (i = 3;i < width * height * 4;i += 4)
1688 if (skindata[i] < 255)
1690 if (i < width * height * 4)
1692 unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
1693 memcpy(fogpixels, skindata, width * height * 4);
1694 for (i = 0;i < width * height * 4;i += 4)
1695 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
1696 skinframe->fog = R_LoadTexture2D(r_main_texturepool, va("%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_RGBA, skinframe->textureflags, NULL);
1697 Mem_Free(fogpixels);
1701 else if (bitsperpixel == 8)
1703 if (r_shadow_bumpscale_basetexture.value > 0)
1705 temp1 = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
1706 temp2 = temp1 + width * height * 4;
1707 if (bitsperpixel == 32)
1708 Image_HeightmapToNormalmap(skindata, temp2, width, height, false, r_shadow_bumpscale_basetexture.value);
1711 // use either a custom palette or the quake palette
1712 Image_Copy8bitRGBA(skindata, temp1, width * height, palette ? palette : palette_complete);
1713 Image_HeightmapToNormalmap(temp1, temp2, width, height, false, r_shadow_bumpscale_basetexture.value);
1715 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va("%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_RGBA, skinframe->textureflags | TEXF_ALPHA, NULL);
1718 // use either a custom palette, or the quake palette
1719 skinframe->base = skinframe->merged = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_merged", skinframe->basename), palette ? palette : (loadglowtexture ? palette_nofullbrights : ((skinframe->textureflags & TEXF_ALPHA) ? palette_transparent : palette_complete)), skinframe->textureflags, true); // all
1720 if (!palette && loadglowtexture)
1721 skinframe->glow = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_glow", skinframe->basename), palette_onlyfullbrights, skinframe->textureflags, false); // glow
1722 if (!palette && loadpantsandshirt)
1724 skinframe->pants = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_pants", skinframe->basename), palette_pantsaswhite, skinframe->textureflags, false); // pants
1725 skinframe->shirt = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_shirt", skinframe->basename), palette_shirtaswhite, skinframe->textureflags, false); // shirt
1727 if (skinframe->pants || skinframe->shirt)
1728 skinframe->base = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_nospecial", skinframe->basename),loadglowtexture ? palette_nocolormapnofullbrights : palette_nocolormap, skinframe->textureflags, false); // no special colors
1729 if (textureflags & TEXF_ALPHA)
1731 // if not using a custom alphapalette, use the quake one
1733 alphapalette = palette_alpha;
1734 for (i = 0;i < width * height;i++)
1735 if (((unsigned char *)alphapalette)[skindata[i]*4+3] < 255)
1737 if (i < width * height)
1738 skinframe->fog = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_fog", skinframe->basename), alphapalette, skinframe->textureflags, true); // fog mask
1745 skinframe_t *R_SkinFrame_LoadMissing(void)
1747 skinframe_t *skinframe;
1749 if (cls.state == ca_dedicated)
1752 skinframe = R_SkinFrame_Find("missing", TEXF_PRECACHE, 0, 0, 0, true);
1753 skinframe->stain = NULL;
1754 skinframe->merged = NULL;
1755 skinframe->base = r_texture_notexture;
1756 skinframe->pants = NULL;
1757 skinframe->shirt = NULL;
1758 skinframe->nmap = r_texture_blanknormalmap;
1759 skinframe->gloss = NULL;
1760 skinframe->glow = NULL;
1761 skinframe->fog = NULL;
1766 void gl_main_start(void)
1771 r = (-1.0/256.0) * (FOGMASKTABLEWIDTH * FOGMASKTABLEWIDTH);
1772 for (x = 0;x < FOGMASKTABLEWIDTH;x++)
1774 alpha = 1 - exp(r / ((double)x*(double)x));
1775 if (x == FOGMASKTABLEWIDTH - 1)
1777 r_refdef.fogmasktable[x] = bound(0, alpha, 1);
1780 memset(r_qwskincache, 0, sizeof(r_qwskincache));
1781 memset(r_qwskincache_skinframe, 0, sizeof(r_qwskincache_skinframe));
1783 // set up r_skinframe loading system for textures
1784 memset(&r_skinframe, 0, sizeof(r_skinframe));
1785 r_skinframe.loadsequence = 1;
1786 Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
1788 r_main_texturepool = R_AllocTexturePool();
1789 R_BuildBlankTextures();
1791 if (gl_texturecubemap)
1794 R_BuildNormalizationCube();
1796 R_BuildFogTexture();
1797 memset(&r_bloomstate, 0, sizeof(r_bloomstate));
1798 memset(&r_waterstate, 0, sizeof(r_waterstate));
1799 memset(r_glsl_permutations, 0, sizeof(r_glsl_permutations));
1800 memset(&r_svbsp, 0, sizeof (r_svbsp));
1803 void gl_main_shutdown(void)
1805 memset(r_qwskincache, 0, sizeof(r_qwskincache));
1806 memset(r_qwskincache_skinframe, 0, sizeof(r_qwskincache_skinframe));
1808 // clear out the r_skinframe state
1809 Mem_ExpandableArray_FreeArray(&r_skinframe.array);
1810 memset(&r_skinframe, 0, sizeof(r_skinframe));
1813 Mem_Free(r_svbsp.nodes);
1814 memset(&r_svbsp, 0, sizeof (r_svbsp));
1815 R_FreeTexturePool(&r_main_texturepool);
1816 r_texture_blanknormalmap = NULL;
1817 r_texture_white = NULL;
1818 r_texture_grey128 = NULL;
1819 r_texture_black = NULL;
1820 r_texture_whitecube = NULL;
1821 r_texture_normalizationcube = NULL;
1822 memset(&r_bloomstate, 0, sizeof(r_bloomstate));
1823 memset(&r_waterstate, 0, sizeof(r_waterstate));
1827 extern void CL_ParseEntityLump(char *entitystring);
1828 void gl_main_newmap(void)
1830 // FIXME: move this code to client
1832 char *entities, entname[MAX_QPATH];
1835 strlcpy(entname, cl.worldmodel->name, sizeof(entname));
1836 l = (int)strlen(entname) - 4;
1837 if (l >= 0 && !strcmp(entname + l, ".bsp"))
1839 memcpy(entname + l, ".ent", 5);
1840 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
1842 CL_ParseEntityLump(entities);
1847 if (cl.worldmodel->brush.entities)
1848 CL_ParseEntityLump(cl.worldmodel->brush.entities);
1852 void GL_Main_Init(void)
1854 r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
1856 Cmd_AddCommand("r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
1857 Cmd_AddCommand("r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
1858 // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
1859 if (gamemode == GAME_NEHAHRA)
1861 Cvar_RegisterVariable (&gl_fogenable);
1862 Cvar_RegisterVariable (&gl_fogdensity);
1863 Cvar_RegisterVariable (&gl_fogred);
1864 Cvar_RegisterVariable (&gl_foggreen);
1865 Cvar_RegisterVariable (&gl_fogblue);
1866 Cvar_RegisterVariable (&gl_fogstart);
1867 Cvar_RegisterVariable (&gl_fogend);
1869 Cvar_RegisterVariable(&r_depthfirst);
1870 Cvar_RegisterVariable(&r_nearclip);
1871 Cvar_RegisterVariable(&r_showbboxes);
1872 Cvar_RegisterVariable(&r_showsurfaces);
1873 Cvar_RegisterVariable(&r_showtris);
1874 Cvar_RegisterVariable(&r_shownormals);
1875 Cvar_RegisterVariable(&r_showlighting);
1876 Cvar_RegisterVariable(&r_showshadowvolumes);
1877 Cvar_RegisterVariable(&r_showcollisionbrushes);
1878 Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
1879 Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
1880 Cvar_RegisterVariable(&r_showdisabledepthtest);
1881 Cvar_RegisterVariable(&r_drawportals);
1882 Cvar_RegisterVariable(&r_drawentities);
1883 Cvar_RegisterVariable(&r_cullentities_trace);
1884 Cvar_RegisterVariable(&r_cullentities_trace_samples);
1885 Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
1886 Cvar_RegisterVariable(&r_cullentities_trace_delay);
1887 Cvar_RegisterVariable(&r_drawviewmodel);
1888 Cvar_RegisterVariable(&r_speeds);
1889 Cvar_RegisterVariable(&r_fullbrights);
1890 Cvar_RegisterVariable(&r_wateralpha);
1891 Cvar_RegisterVariable(&r_dynamic);
1892 Cvar_RegisterVariable(&r_fullbright);
1893 Cvar_RegisterVariable(&r_shadows);
1894 Cvar_RegisterVariable(&r_shadows_throwdistance);
1895 Cvar_RegisterVariable(&r_q1bsp_skymasking);
1896 Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
1897 Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
1898 Cvar_RegisterVariable(&r_textureunits);
1899 Cvar_RegisterVariable(&r_glsl);
1900 Cvar_RegisterVariable(&r_glsl_offsetmapping);
1901 Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
1902 Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
1903 Cvar_RegisterVariable(&r_glsl_deluxemapping);
1904 Cvar_RegisterVariable(&r_water);
1905 Cvar_RegisterVariable(&r_water_resolutionmultiplier);
1906 Cvar_RegisterVariable(&r_water_clippingplanebias);
1907 Cvar_RegisterVariable(&r_water_refractdistort);
1908 Cvar_RegisterVariable(&r_water_reflectdistort);
1909 Cvar_RegisterVariable(&r_lerpsprites);
1910 Cvar_RegisterVariable(&r_lerpmodels);
1911 Cvar_RegisterVariable(&r_waterscroll);
1912 Cvar_RegisterVariable(&r_bloom);
1913 Cvar_RegisterVariable(&r_bloom_colorscale);
1914 Cvar_RegisterVariable(&r_bloom_brighten);
1915 Cvar_RegisterVariable(&r_bloom_blur);
1916 Cvar_RegisterVariable(&r_bloom_resolution);
1917 Cvar_RegisterVariable(&r_bloom_colorexponent);
1918 Cvar_RegisterVariable(&r_bloom_colorsubtract);
1919 Cvar_RegisterVariable(&r_hdr);
1920 Cvar_RegisterVariable(&r_hdr_scenebrightness);
1921 Cvar_RegisterVariable(&r_glsl_contrastboost);
1922 Cvar_RegisterVariable(&r_hdr_glowintensity);
1923 Cvar_RegisterVariable(&r_hdr_range);
1924 Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
1925 Cvar_RegisterVariable(&developer_texturelogging);
1926 Cvar_RegisterVariable(&gl_lightmaps);
1927 Cvar_RegisterVariable(&r_test);
1928 Cvar_RegisterVariable(&r_batchmode);
1929 if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
1930 Cvar_SetValue("r_fullbrights", 0);
1931 R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
1934 extern void R_Textures_Init(void);
1935 extern void GL_Draw_Init(void);
1936 extern void GL_Main_Init(void);
1937 extern void R_Shadow_Init(void);
1938 extern void R_Sky_Init(void);
1939 extern void GL_Surf_Init(void);
1940 extern void R_Light_Init(void);
1941 extern void R_Particles_Init(void);
1942 extern void R_Explosion_Init(void);
1943 extern void gl_backend_init(void);
1944 extern void Sbar_Init(void);
1945 extern void R_LightningBeams_Init(void);
1946 extern void Mod_RenderInit(void);
1948 void Render_Init(void)
1961 R_LightningBeams_Init();
1970 extern char *ENGINE_EXTENSIONS;
1973 VID_CheckExtensions();
1975 // LordHavoc: report supported extensions
1976 Con_DPrintf("\nQuakeC extensions for server and client: %s\nQuakeC extensions for menu: %s\n", vm_sv_extensions, vm_m_extensions );
1978 // clear to black (loading plaque will be seen over this)
1980 qglClearColor(0,0,0,1);CHECKGLERROR
1981 qglClear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
1984 int R_CullBox(const vec3_t mins, const vec3_t maxs)
1988 for (i = 0;i < r_view.numfrustumplanes;i++)
1990 // skip nearclip plane, it often culls portals when you are very close, and is almost never useful
1993 p = r_view.frustum + i;
1998 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
2002 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
2006 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
2010 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
2014 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
2018 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
2022 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
2026 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
2034 int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
2038 for (i = 0;i < numplanes;i++)
2045 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
2049 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
2053 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
2057 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
2061 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
2065 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
2069 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
2073 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
2081 //==================================================================================
2083 static void R_UpdateEntityLighting(entity_render_t *ent)
2085 vec3_t tempdiffusenormal;
2087 // fetch the lighting from the worldmodel data
2088 VectorSet(ent->modellight_ambient, r_ambient.value * (2.0f / 128.0f), r_ambient.value * (2.0f / 128.0f), r_ambient.value * (2.0f / 128.0f));
2089 VectorClear(ent->modellight_diffuse);
2090 VectorClear(tempdiffusenormal);
2091 if ((ent->flags & RENDER_LIGHT) && r_refdef.worldmodel && r_refdef.worldmodel->brush.LightPoint)
2094 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2095 r_refdef.worldmodel->brush.LightPoint(r_refdef.worldmodel, org, ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal);
2098 VectorSet(ent->modellight_ambient, 1, 1, 1);
2100 // move the light direction into modelspace coordinates for lighting code
2101 Matrix4x4_Transform3x3(&ent->inversematrix, tempdiffusenormal, ent->modellight_lightdir);
2102 if(VectorLength2(ent->modellight_lightdir) > 0)
2104 VectorNormalize(ent->modellight_lightdir);
2108 VectorSet(ent->modellight_lightdir, 0, 0, 1); // have to set SOME valid vector here
2111 // scale ambient and directional light contributions according to rendering variables
2112 ent->modellight_ambient[0] *= ent->colormod[0] * r_refdef.lightmapintensity;
2113 ent->modellight_ambient[1] *= ent->colormod[1] * r_refdef.lightmapintensity;
2114 ent->modellight_ambient[2] *= ent->colormod[2] * r_refdef.lightmapintensity;
2115 ent->modellight_diffuse[0] *= ent->colormod[0] * r_refdef.lightmapintensity;
2116 ent->modellight_diffuse[1] *= ent->colormod[1] * r_refdef.lightmapintensity;
2117 ent->modellight_diffuse[2] *= ent->colormod[2] * r_refdef.lightmapintensity;
2120 static void R_View_UpdateEntityVisible (void)
2123 entity_render_t *ent;
2125 if (!r_drawentities.integer)
2128 renderimask = r_refdef.envmap ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL) : ((chase_active.integer || r_waterstate.renderingscene) ? RENDER_VIEWMODEL : RENDER_EXTERIORMODEL);
2129 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingVisibleLeafs)
2131 // worldmodel can check visibility
2132 for (i = 0;i < r_refdef.numentities;i++)
2134 ent = r_refdef.entities[i];
2135 r_viewcache.entityvisible[i] = !(ent->flags & renderimask) && !R_CullBox(ent->mins, ent->maxs) && ((ent->effects & EF_NODEPTHTEST) || (ent->flags & RENDER_VIEWMODEL) || r_refdef.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.worldmodel, r_viewcache.world_leafvisible, ent->mins, ent->maxs));
2137 if(r_cullentities_trace.integer)
2139 for (i = 0;i < r_refdef.numentities;i++)
2141 ent = r_refdef.entities[i];
2142 if(r_viewcache.entityvisible[i] && !(ent->effects & EF_NODEPTHTEST) && !(ent->flags & RENDER_VIEWMODEL) && !(ent->model && (ent->model->name[0] == '*')))
2144 if(Mod_CanSeeBox_Trace(r_cullentities_trace_samples.integer, r_cullentities_trace_enlarge.value, r_refdef.worldmodel, r_view.origin, ent->mins, ent->maxs))
2145 ent->last_trace_visibility = realtime;
2146 if(ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
2147 r_viewcache.entityvisible[i] = 0;
2154 // no worldmodel or it can't check visibility
2155 for (i = 0;i < r_refdef.numentities;i++)
2157 ent = r_refdef.entities[i];
2158 r_viewcache.entityvisible[i] = !(ent->flags & renderimask) && !R_CullBox(ent->mins, ent->maxs);
2162 // update entity lighting (even on hidden entities for r_shadows)
2163 for (i = 0;i < r_refdef.numentities;i++)
2164 R_UpdateEntityLighting(r_refdef.entities[i]);
2167 // only used if skyrendermasked, and normally returns false
2168 int R_DrawBrushModelsSky (void)
2171 entity_render_t *ent;
2173 if (!r_drawentities.integer)
2177 for (i = 0;i < r_refdef.numentities;i++)
2179 if (!r_viewcache.entityvisible[i])
2181 ent = r_refdef.entities[i];
2182 if (!ent->model || !ent->model->DrawSky)
2184 ent->model->DrawSky(ent);
2190 static void R_DrawNoModel(entity_render_t *ent);
2191 static void R_DrawModels(void)
2194 entity_render_t *ent;
2196 if (!r_drawentities.integer)
2199 for (i = 0;i < r_refdef.numentities;i++)
2201 if (!r_viewcache.entityvisible[i])
2203 ent = r_refdef.entities[i];
2204 r_refdef.stats.entities++;
2205 if (ent->model && ent->model->Draw != NULL)
2206 ent->model->Draw(ent);
2212 static void R_DrawModelsDepth(void)
2215 entity_render_t *ent;
2217 if (!r_drawentities.integer)
2220 for (i = 0;i < r_refdef.numentities;i++)
2222 if (!r_viewcache.entityvisible[i])
2224 ent = r_refdef.entities[i];
2225 r_refdef.stats.entities++;
2226 if (ent->model && ent->model->DrawDepth != NULL)
2227 ent->model->DrawDepth(ent);
2231 static void R_DrawModelsDebug(void)
2234 entity_render_t *ent;
2236 if (!r_drawentities.integer)
2239 for (i = 0;i < r_refdef.numentities;i++)
2241 if (!r_viewcache.entityvisible[i])
2243 ent = r_refdef.entities[i];
2244 r_refdef.stats.entities++;
2245 if (ent->model && ent->model->DrawDebug != NULL)
2246 ent->model->DrawDebug(ent);
2250 static void R_DrawModelsAddWaterPlanes(void)
2253 entity_render_t *ent;
2255 if (!r_drawentities.integer)
2258 for (i = 0;i < r_refdef.numentities;i++)
2260 if (!r_viewcache.entityvisible[i])
2262 ent = r_refdef.entities[i];
2263 r_refdef.stats.entities++;
2264 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
2265 ent->model->DrawAddWaterPlanes(ent);
2269 static void R_View_SetFrustum(void)
2272 double slopex, slopey;
2274 // break apart the view matrix into vectors for various purposes
2275 Matrix4x4_ToVectors(&r_view.matrix, r_view.forward, r_view.left, r_view.up, r_view.origin);
2276 VectorNegate(r_view.left, r_view.right);
2279 r_view.frustum[0].normal[0] = 0 - 1.0 / r_view.frustum_x;
2280 r_view.frustum[0].normal[1] = 0 - 0;
2281 r_view.frustum[0].normal[2] = -1 - 0;
2282 r_view.frustum[1].normal[0] = 0 + 1.0 / r_view.frustum_x;
2283 r_view.frustum[1].normal[1] = 0 + 0;
2284 r_view.frustum[1].normal[2] = -1 + 0;
2285 r_view.frustum[2].normal[0] = 0 - 0;
2286 r_view.frustum[2].normal[1] = 0 - 1.0 / r_view.frustum_y;
2287 r_view.frustum[2].normal[2] = -1 - 0;
2288 r_view.frustum[3].normal[0] = 0 + 0;
2289 r_view.frustum[3].normal[1] = 0 + 1.0 / r_view.frustum_y;
2290 r_view.frustum[3].normal[2] = -1 + 0;
2294 zNear = r_refdef.nearclip;
2295 nudge = 1.0 - 1.0 / (1<<23);
2296 r_view.frustum[4].normal[0] = 0 - 0;
2297 r_view.frustum[4].normal[1] = 0 - 0;
2298 r_view.frustum[4].normal[2] = -1 - -nudge;
2299 r_view.frustum[4].dist = 0 - -2 * zNear * nudge;
2300 r_view.frustum[5].normal[0] = 0 + 0;
2301 r_view.frustum[5].normal[1] = 0 + 0;
2302 r_view.frustum[5].normal[2] = -1 + -nudge;
2303 r_view.frustum[5].dist = 0 + -2 * zNear * nudge;
2309 r_view.frustum[0].normal[0] = m[3] - m[0];
2310 r_view.frustum[0].normal[1] = m[7] - m[4];
2311 r_view.frustum[0].normal[2] = m[11] - m[8];
2312 r_view.frustum[0].dist = m[15] - m[12];
2314 r_view.frustum[1].normal[0] = m[3] + m[0];
2315 r_view.frustum[1].normal[1] = m[7] + m[4];
2316 r_view.frustum[1].normal[2] = m[11] + m[8];
2317 r_view.frustum[1].dist = m[15] + m[12];
2319 r_view.frustum[2].normal[0] = m[3] - m[1];
2320 r_view.frustum[2].normal[1] = m[7] - m[5];
2321 r_view.frustum[2].normal[2] = m[11] - m[9];
2322 r_view.frustum[2].dist = m[15] - m[13];
2324 r_view.frustum[3].normal[0] = m[3] + m[1];
2325 r_view.frustum[3].normal[1] = m[7] + m[5];
2326 r_view.frustum[3].normal[2] = m[11] + m[9];
2327 r_view.frustum[3].dist = m[15] + m[13];
2329 r_view.frustum[4].normal[0] = m[3] - m[2];
2330 r_view.frustum[4].normal[1] = m[7] - m[6];
2331 r_view.frustum[4].normal[2] = m[11] - m[10];
2332 r_view.frustum[4].dist = m[15] - m[14];
2334 r_view.frustum[5].normal[0] = m[3] + m[2];
2335 r_view.frustum[5].normal[1] = m[7] + m[6];
2336 r_view.frustum[5].normal[2] = m[11] + m[10];
2337 r_view.frustum[5].dist = m[15] + m[14];
2342 if (r_view.useperspective)
2344 slopex = 1.0 / r_view.frustum_x;
2345 slopey = 1.0 / r_view.frustum_y;
2346 VectorMA(r_view.forward, -slopex, r_view.left, r_view.frustum[0].normal);
2347 VectorMA(r_view.forward, slopex, r_view.left, r_view.frustum[1].normal);
2348 VectorMA(r_view.forward, -slopey, r_view.up , r_view.frustum[2].normal);
2349 VectorMA(r_view.forward, slopey, r_view.up , r_view.frustum[3].normal);
2350 VectorCopy(r_view.forward, r_view.frustum[4].normal);
2352 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
2353 VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, -1024 * slopex, r_view.left, -1024 * slopey, r_view.up, r_view.frustumcorner[0]);
2354 VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, 1024 * slopex, r_view.left, -1024 * slopey, r_view.up, r_view.frustumcorner[1]);
2355 VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, -1024 * slopex, r_view.left, 1024 * slopey, r_view.up, r_view.frustumcorner[2]);
2356 VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, 1024 * slopex, r_view.left, 1024 * slopey, r_view.up, r_view.frustumcorner[3]);
2358 r_view.frustum[0].dist = DotProduct (r_view.origin, r_view.frustum[0].normal);
2359 r_view.frustum[1].dist = DotProduct (r_view.origin, r_view.frustum[1].normal);
2360 r_view.frustum[2].dist = DotProduct (r_view.origin, r_view.frustum[2].normal);
2361 r_view.frustum[3].dist = DotProduct (r_view.origin, r_view.frustum[3].normal);
2362 r_view.frustum[4].dist = DotProduct (r_view.origin, r_view.frustum[4].normal) + r_refdef.nearclip;
2366 VectorScale(r_view.left, -r_view.ortho_x, r_view.frustum[0].normal);
2367 VectorScale(r_view.left, r_view.ortho_x, r_view.frustum[1].normal);
2368 VectorScale(r_view.up, -r_view.ortho_y, r_view.frustum[2].normal);
2369 VectorScale(r_view.up, r_view.ortho_y, r_view.frustum[3].normal);
2370 VectorCopy(r_view.forward, r_view.frustum[4].normal);
2371 r_view.frustum[0].dist = DotProduct (r_view.origin, r_view.frustum[0].normal) + r_view.ortho_x;
2372 r_view.frustum[1].dist = DotProduct (r_view.origin, r_view.frustum[1].normal) + r_view.ortho_x;
2373 r_view.frustum[2].dist = DotProduct (r_view.origin, r_view.frustum[2].normal) + r_view.ortho_y;
2374 r_view.frustum[3].dist = DotProduct (r_view.origin, r_view.frustum[3].normal) + r_view.ortho_y;
2375 r_view.frustum[4].dist = DotProduct (r_view.origin, r_view.frustum[4].normal) + r_refdef.nearclip;
2377 r_view.numfrustumplanes = 5;
2379 if (r_view.useclipplane)
2381 r_view.numfrustumplanes = 6;
2382 r_view.frustum[5] = r_view.clipplane;
2385 for (i = 0;i < r_view.numfrustumplanes;i++)
2386 PlaneClassify(r_view.frustum + i);
2388 // LordHavoc: note to all quake engine coders, Quake had a special case
2389 // for 90 degrees which assumed a square view (wrong), so I removed it,
2390 // Quake2 has it disabled as well.
2392 // rotate R_VIEWFORWARD right by FOV_X/2 degrees
2393 //RotatePointAroundVector( r_view.frustum[0].normal, r_view.up, r_view.forward, -(90 - r_refdef.fov_x / 2));
2394 //r_view.frustum[0].dist = DotProduct (r_view.origin, frustum[0].normal);
2395 //PlaneClassify(&frustum[0]);
2397 // rotate R_VIEWFORWARD left by FOV_X/2 degrees
2398 //RotatePointAroundVector( r_view.frustum[1].normal, r_view.up, r_view.forward, (90 - r_refdef.fov_x / 2));
2399 //r_view.frustum[1].dist = DotProduct (r_view.origin, frustum[1].normal);
2400 //PlaneClassify(&frustum[1]);
2402 // rotate R_VIEWFORWARD up by FOV_X/2 degrees
2403 //RotatePointAroundVector( r_view.frustum[2].normal, r_view.left, r_view.forward, -(90 - r_refdef.fov_y / 2));
2404 //r_view.frustum[2].dist = DotProduct (r_view.origin, frustum[2].normal);
2405 //PlaneClassify(&frustum[2]);
2407 // rotate R_VIEWFORWARD down by FOV_X/2 degrees
2408 //RotatePointAroundVector( r_view.frustum[3].normal, r_view.left, r_view.forward, (90 - r_refdef.fov_y / 2));
2409 //r_view.frustum[3].dist = DotProduct (r_view.origin, frustum[3].normal);
2410 //PlaneClassify(&frustum[3]);
2413 //VectorCopy(r_view.forward, r_view.frustum[4].normal);
2414 //r_view.frustum[4].dist = DotProduct (r_view.origin, frustum[4].normal) + r_nearclip.value;
2415 //PlaneClassify(&frustum[4]);
2418 void R_View_Update(void)
2420 R_View_SetFrustum();
2421 R_View_WorldVisibility(r_view.useclipplane);
2422 R_View_UpdateEntityVisible();
2425 void R_SetupView(void)
2427 if (!r_view.useperspective)
2428 GL_SetupView_Mode_Ortho(-r_view.ortho_x, -r_view.ortho_y, r_view.ortho_x, r_view.ortho_y, -r_refdef.farclip, r_refdef.farclip);
2429 else if (r_refdef.rtworldshadows || r_refdef.rtdlightshadows)
2430 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view.frustum_x, r_view.frustum_y, r_refdef.nearclip);
2432 GL_SetupView_Mode_Perspective(r_view.frustum_x, r_view.frustum_y, r_refdef.nearclip, r_refdef.farclip);
2434 GL_SetupView_Orientation_FromEntity(&r_view.matrix);
2436 if (r_view.useclipplane)
2438 // LordHavoc: couldn't figure out how to make this approach the
2439 vec_t dist = r_view.clipplane.dist - r_water_clippingplanebias.value;
2440 vec_t viewdist = DotProduct(r_view.origin, r_view.clipplane.normal);
2441 if (viewdist < r_view.clipplane.dist + r_water_clippingplanebias.value)
2442 dist = r_view.clipplane.dist;
2443 GL_SetupView_ApplyCustomNearClipPlane(r_view.clipplane.normal[0], r_view.clipplane.normal[1], r_view.clipplane.normal[2], dist);
2447 void R_ResetViewRendering2D(void)
2449 if (gl_support_fragment_shader)
2451 qglUseProgramObjectARB(0);CHECKGLERROR
2456 // GL is weird because it's bottom to top, r_view.y is top to bottom
2457 qglViewport(r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
2458 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
2459 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2460 GL_Color(1, 1, 1, 1);
2461 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2462 GL_BlendFunc(GL_ONE, GL_ZERO);
2463 GL_AlphaTest(false);
2464 GL_ScissorTest(false);
2465 GL_DepthMask(false);
2466 GL_DepthRange(0, 1);
2467 GL_DepthTest(false);
2468 R_Mesh_Matrix(&identitymatrix);
2469 R_Mesh_ResetTextureState();
2470 GL_PolygonOffset(0, 0);
2471 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
2472 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2473 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
2474 qglStencilMask(~0);CHECKGLERROR
2475 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
2476 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
2477 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
2480 void R_ResetViewRendering3D(void)
2482 if (gl_support_fragment_shader)
2484 qglUseProgramObjectARB(0);CHECKGLERROR
2489 // GL is weird because it's bottom to top, r_view.y is top to bottom
2490 qglViewport(r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
2492 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2493 GL_Color(1, 1, 1, 1);
2494 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2495 GL_BlendFunc(GL_ONE, GL_ZERO);
2496 GL_AlphaTest(false);
2497 GL_ScissorTest(true);
2499 GL_DepthRange(0, 1);
2501 R_Mesh_Matrix(&identitymatrix);
2502 R_Mesh_ResetTextureState();
2503 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
2504 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
2505 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2506 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
2507 qglStencilMask(~0);CHECKGLERROR
2508 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
2509 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
2510 GL_CullFace(r_view.cullface_back);
2514 R_Bloom_SetupShader(
2516 "// written by Forest 'LordHavoc' Hale\n"
2518 "// common definitions between vertex shader and fragment shader:\n"
2520 "#ifdef __GLSL_CG_DATA_TYPES\n"
2521 "#define myhalf half\n"
2522 "#define myhvec2 hvec2\n"
2523 "#define myhvec3 hvec3\n"
2524 "#define myhvec4 hvec4\n"
2526 "#define myhalf float\n"
2527 "#define myhvec2 vec2\n"
2528 "#define myhvec3 vec3\n"
2529 "#define myhvec4 vec4\n"
2532 "varying vec2 ScreenTexCoord;\n"
2533 "varying vec2 BloomTexCoord;\n"
2538 "// vertex shader specific:\n"
2539 "#ifdef VERTEX_SHADER\n"
2543 " ScreenTexCoord = vec2(gl_MultiTexCoord0);\n"
2544 " BloomTexCoord = vec2(gl_MultiTexCoord1);\n"
2545 " // transform vertex to camera space, using ftransform to match non-VS\n"
2547 " gl_Position = ftransform();\n"
2550 "#endif // VERTEX_SHADER\n"
2555 "// fragment shader specific:\n"
2556 "#ifdef FRAGMENT_SHADER\n"
2561 " myhvec3 color = myhvec3(texture2D(Texture_Screen, ScreenTexCoord));\n"
2562 " for (x = -BLUR_X;x <= BLUR_X;x++)
2563 " color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
2564 " color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
2565 " color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
2566 " color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
2568 " gl_FragColor = vec4(color);\n"
2571 "#endif // FRAGMENT_SHADER\n"
2574 void R_RenderScene(qboolean addwaterplanes);
2576 static void R_Water_StartFrame(void)
2579 int waterwidth, waterheight, texturewidth, textureheight;
2580 r_waterstate_waterplane_t *p;
2582 // set waterwidth and waterheight to the water resolution that will be
2583 // used (often less than the screen resolution for faster rendering)
2584 waterwidth = (int)bound(1, r_view.width * r_water_resolutionmultiplier.value, r_view.width);
2585 waterheight = (int)bound(1, r_view.height * r_water_resolutionmultiplier.value, r_view.height);
2587 // calculate desired texture sizes
2588 // can't use water if the card does not support the texture size
2589 if (!r_water.integer || waterwidth > gl_max_texture_size || waterheight > gl_max_texture_size)
2590 texturewidth = textureheight = waterwidth = waterheight = 0;
2591 else if (gl_support_arb_texture_non_power_of_two)
2593 texturewidth = waterwidth;
2594 textureheight = waterheight;
2598 for (texturewidth = 1;texturewidth < waterwidth ;texturewidth *= 2);
2599 for (textureheight = 1;textureheight < waterheight;textureheight *= 2);
2602 // allocate textures as needed
2603 if (r_waterstate.waterwidth != waterwidth || r_waterstate.waterheight != waterheight || r_waterstate.texturewidth != texturewidth || r_waterstate.textureheight != textureheight)
2605 r_waterstate.maxwaterplanes = MAX_WATERPLANES;
2606 for (i = 0, p = r_waterstate.waterplanes;i < r_waterstate.maxwaterplanes;i++, p++)
2608 if (p->texture_refraction)
2609 R_FreeTexture(p->texture_refraction);
2610 p->texture_refraction = NULL;
2611 if (p->texture_reflection)
2612 R_FreeTexture(p->texture_reflection);
2613 p->texture_reflection = NULL;
2615 memset(&r_waterstate, 0, sizeof(r_waterstate));
2616 r_waterstate.waterwidth = waterwidth;
2617 r_waterstate.waterheight = waterheight;
2618 r_waterstate.texturewidth = texturewidth;
2619 r_waterstate.textureheight = textureheight;
2622 if (r_waterstate.waterwidth)
2624 r_waterstate.enabled = true;
2626 // set up variables that will be used in shader setup
2627 r_waterstate.screenscale[0] = 0.5f * (float)waterwidth / (float)texturewidth;
2628 r_waterstate.screenscale[1] = 0.5f * (float)waterheight / (float)textureheight;
2629 r_waterstate.screencenter[0] = 0.5f * (float)waterwidth / (float)texturewidth;
2630 r_waterstate.screencenter[1] = 0.5f * (float)waterheight / (float)textureheight;
2633 r_waterstate.maxwaterplanes = MAX_WATERPLANES;
2634 r_waterstate.numwaterplanes = 0;
2637 static void R_Water_AddWaterPlane(msurface_t *surface)
2639 int triangleindex, planeindex;
2645 r_waterstate_waterplane_t *p;
2646 // just use the first triangle with a valid normal for any decisions
2647 VectorClear(normal);
2648 VectorClear(center);
2649 for (triangleindex = 0, e = rsurface.modelelement3i + surface->num_firsttriangle * 3;triangleindex < surface->num_triangles;triangleindex++, e += 3)
2651 Matrix4x4_Transform(&rsurface.matrix, rsurface.modelvertex3f + e[0]*3, vert[0]);
2652 Matrix4x4_Transform(&rsurface.matrix, rsurface.modelvertex3f + e[1]*3, vert[1]);
2653 Matrix4x4_Transform(&rsurface.matrix, rsurface.modelvertex3f + e[2]*3, vert[2]);
2654 TriangleNormal(vert[0], vert[1], vert[2], normal);
2655 if (VectorLength2(normal) >= 0.001)
2658 // now find the center of this surface
2659 for (triangleindex = 0, e = rsurface.modelelement3i + surface->num_firsttriangle * 3;triangleindex < surface->num_triangles*3;triangleindex++, e++)
2661 Matrix4x4_Transform(&rsurface.matrix, rsurface.modelvertex3f + e[0]*3, vert[0]);
2662 VectorAdd(center, vert[0], center);
2664 f = 1.0 / surface->num_triangles*3;
2665 VectorScale(center, f, center);
2667 // find a matching plane if there is one
2668 for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++)
2669 if (fabs(PlaneDiff(vert[0], &p->plane)) < 1 && fabs(PlaneDiff(vert[1], &p->plane)) < 1 && fabs(PlaneDiff(vert[2], &p->plane)) < 1)
2671 if (planeindex >= r_waterstate.maxwaterplanes)
2672 return; // nothing we can do, out of planes
2674 // if this triangle does not fit any known plane rendered this frame, add one
2675 if (planeindex >= r_waterstate.numwaterplanes)
2677 // store the new plane
2678 r_waterstate.numwaterplanes++;
2679 VectorCopy(normal, p->plane.normal);
2680 VectorNormalize(p->plane.normal);
2681 p->plane.dist = DotProduct(vert[0], p->plane.normal);
2682 PlaneClassify(&p->plane);
2683 // flip the plane if it does not face the viewer
2684 if (PlaneDiff(r_view.origin, &p->plane) < 0)
2686 VectorNegate(p->plane.normal, p->plane.normal);
2687 p->plane.dist *= -1;
2688 PlaneClassify(&p->plane);
2690 // clear materialflags and pvs
2691 p->materialflags = 0;
2692 p->pvsvalid = false;
2694 // merge this surface's materialflags into the waterplane
2695 p->materialflags |= surface->texture->currentframe->currentmaterialflags;
2696 // merge this surface's PVS into the waterplane
2697 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.worldmodel && r_refdef.worldmodel->brush.FatPVS)
2699 r_refdef.worldmodel->brush.FatPVS(r_refdef.worldmodel, r_view.origin, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
2704 static void R_Water_ProcessPlanes(void)
2706 r_view_t originalview;
2708 r_waterstate_waterplane_t *p;
2710 originalview = r_view;
2712 // make sure enough textures are allocated
2713 for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++)
2715 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
2717 if (!p->texture_refraction)
2718 p->texture_refraction = R_LoadTexture2D(r_main_texturepool, va("waterplane%i_refraction", planeindex), r_waterstate.texturewidth, r_waterstate.textureheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
2719 if (!p->texture_refraction)
2723 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
2725 if (!p->texture_reflection)
2726 p->texture_reflection = R_LoadTexture2D(r_main_texturepool, va("waterplane%i_reflection", planeindex), r_waterstate.texturewidth, r_waterstate.textureheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
2727 if (!p->texture_reflection)
2733 for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++)
2735 r_view.showdebug = false;
2736 r_view.width = r_waterstate.waterwidth;
2737 r_view.height = r_waterstate.waterheight;
2738 r_view.useclipplane = true;
2739 r_waterstate.renderingscene = true;
2741 // render the normal view scene and copy into texture
2742 // (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)
2743 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
2745 r_view.clipplane = p->plane;
2746 VectorNegate(r_view.clipplane.normal, r_view.clipplane.normal);
2747 r_view.clipplane.dist = -r_view.clipplane.dist;
2748 PlaneClassify(&r_view.clipplane);
2750 R_RenderScene(false);
2752 // copy view into the screen texture
2753 R_Mesh_TexBind(0, R_GetTexture(p->texture_refraction));
2754 GL_ActiveTexture(0);
2756 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
2759 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
2761 // render reflected scene and copy into texture
2762 Matrix4x4_Reflect(&r_view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
2763 r_view.clipplane = p->plane;
2764 // reverse the cullface settings for this render
2765 r_view.cullface_front = GL_FRONT;
2766 r_view.cullface_back = GL_BACK;
2767 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.num_pvsclusterbytes)
2769 r_view.usecustompvs = true;
2771 memcpy(r_viewcache.world_pvsbits, p->pvsbits, r_refdef.worldmodel->brush.num_pvsclusterbytes);
2773 memset(r_viewcache.world_pvsbits, 0xFF, r_refdef.worldmodel->brush.num_pvsclusterbytes);
2776 R_ResetViewRendering3D();
2779 R_RenderScene(false);
2781 R_Mesh_TexBind(0, R_GetTexture(p->texture_reflection));
2782 GL_ActiveTexture(0);
2784 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
2786 R_ResetViewRendering3D();
2790 r_view = originalview;
2791 r_waterstate.renderingscene = false;
2795 r_view = originalview;
2796 r_waterstate.renderingscene = false;
2797 Cvar_SetValueQuick(&r_water, 0);
2798 Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed! Turned off r_water.\n");
2802 void R_Bloom_StartFrame(void)
2804 int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight;
2806 // set bloomwidth and bloomheight to the bloom resolution that will be
2807 // used (often less than the screen resolution for faster rendering)
2808 r_bloomstate.bloomwidth = bound(1, r_bloom_resolution.integer, r_view.width);
2809 r_bloomstate.bloomheight = r_bloomstate.bloomwidth * r_view.height / r_view.width;
2810 r_bloomstate.bloomheight = bound(1, r_bloomstate.bloomheight, r_view.height);
2812 // calculate desired texture sizes
2813 if (gl_support_arb_texture_non_power_of_two)
2815 screentexturewidth = r_view.width;
2816 screentextureheight = r_view.height;
2817 bloomtexturewidth = r_bloomstate.bloomwidth;
2818 bloomtextureheight = r_bloomstate.bloomheight;
2822 for (screentexturewidth = 1;screentexturewidth < vid.width ;screentexturewidth *= 2);
2823 for (screentextureheight = 1;screentextureheight < vid.height ;screentextureheight *= 2);
2824 for (bloomtexturewidth = 1;bloomtexturewidth < r_bloomstate.bloomwidth ;bloomtexturewidth *= 2);
2825 for (bloomtextureheight = 1;bloomtextureheight < r_bloomstate.bloomheight;bloomtextureheight *= 2);
2830 screentexturewidth = screentextureheight = 0;
2832 else if (r_bloom.integer)
2837 screentexturewidth = screentextureheight = 0;
2838 bloomtexturewidth = bloomtextureheight = 0;
2841 if ((!bloomtexturewidth && !bloomtextureheight) || r_bloom_resolution.integer < 4 || r_bloom_blur.value < 1 || r_bloom_blur.value >= 512 || screentexturewidth > gl_max_texture_size || screentextureheight > gl_max_texture_size || bloomtexturewidth > gl_max_texture_size || bloomtextureheight > gl_max_texture_size)
2843 // can't use bloom if the parameters are too weird
2844 // can't use bloom if the card does not support the texture size
2845 if (r_bloomstate.texture_screen)
2846 R_FreeTexture(r_bloomstate.texture_screen);
2847 if (r_bloomstate.texture_bloom)
2848 R_FreeTexture(r_bloomstate.texture_bloom);
2849 memset(&r_bloomstate, 0, sizeof(r_bloomstate));
2853 r_bloomstate.enabled = true;
2854 r_bloomstate.hdr = r_hdr.integer != 0;
2856 // allocate textures as needed
2857 if (r_bloomstate.screentexturewidth != screentexturewidth || r_bloomstate.screentextureheight != screentextureheight)
2859 if (r_bloomstate.texture_screen)
2860 R_FreeTexture(r_bloomstate.texture_screen);
2861 r_bloomstate.texture_screen = NULL;
2862 r_bloomstate.screentexturewidth = screentexturewidth;
2863 r_bloomstate.screentextureheight = screentextureheight;
2864 if (r_bloomstate.screentexturewidth && r_bloomstate.screentextureheight)
2865 r_bloomstate.texture_screen = R_LoadTexture2D(r_main_texturepool, "screen", r_bloomstate.screentexturewidth, r_bloomstate.screentextureheight, NULL, TEXTYPE_RGBA, TEXF_FORCENEAREST | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
2867 if (r_bloomstate.bloomtexturewidth != bloomtexturewidth || r_bloomstate.bloomtextureheight != bloomtextureheight)
2869 if (r_bloomstate.texture_bloom)
2870 R_FreeTexture(r_bloomstate.texture_bloom);
2871 r_bloomstate.texture_bloom = NULL;
2872 r_bloomstate.bloomtexturewidth = bloomtexturewidth;
2873 r_bloomstate.bloomtextureheight = bloomtextureheight;
2874 if (r_bloomstate.bloomtexturewidth && r_bloomstate.bloomtextureheight)
2875 r_bloomstate.texture_bloom = R_LoadTexture2D(r_main_texturepool, "bloom", r_bloomstate.bloomtexturewidth, r_bloomstate.bloomtextureheight, NULL, TEXTYPE_RGBA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_ALWAYSPRECACHE, NULL);
2878 // set up a texcoord array for the full resolution screen image
2879 // (we have to keep this around to copy back during final render)
2880 r_bloomstate.screentexcoord2f[0] = 0;
2881 r_bloomstate.screentexcoord2f[1] = (float)r_view.height / (float)r_bloomstate.screentextureheight;
2882 r_bloomstate.screentexcoord2f[2] = (float)r_view.width / (float)r_bloomstate.screentexturewidth;
2883 r_bloomstate.screentexcoord2f[3] = (float)r_view.height / (float)r_bloomstate.screentextureheight;
2884 r_bloomstate.screentexcoord2f[4] = (float)r_view.width / (float)r_bloomstate.screentexturewidth;
2885 r_bloomstate.screentexcoord2f[5] = 0;
2886 r_bloomstate.screentexcoord2f[6] = 0;
2887 r_bloomstate.screentexcoord2f[7] = 0;
2889 // set up a texcoord array for the reduced resolution bloom image
2890 // (which will be additive blended over the screen image)
2891 r_bloomstate.bloomtexcoord2f[0] = 0;
2892 r_bloomstate.bloomtexcoord2f[1] = (float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
2893 r_bloomstate.bloomtexcoord2f[2] = (float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
2894 r_bloomstate.bloomtexcoord2f[3] = (float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
2895 r_bloomstate.bloomtexcoord2f[4] = (float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
2896 r_bloomstate.bloomtexcoord2f[5] = 0;
2897 r_bloomstate.bloomtexcoord2f[6] = 0;
2898 r_bloomstate.bloomtexcoord2f[7] = 0;
2901 void R_Bloom_CopyScreenTexture(float colorscale)
2903 r_refdef.stats.bloom++;
2905 R_ResetViewRendering2D();
2906 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
2907 R_Mesh_ColorPointer(NULL, 0, 0);
2908 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
2909 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
2911 // copy view into the screen texture
2912 GL_ActiveTexture(0);
2914 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
2915 r_refdef.stats.bloom_copypixels += r_view.width * r_view.height;
2917 // now scale it down to the bloom texture size
2919 qglViewport(r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
2920 GL_BlendFunc(GL_ONE, GL_ZERO);
2921 GL_Color(colorscale, colorscale, colorscale, 1);
2922 // TODO: optimize with multitexture or GLSL
2923 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2924 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2926 // we now have a bloom image in the framebuffer
2927 // copy it into the bloom image texture for later processing
2928 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2929 GL_ActiveTexture(0);
2931 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
2932 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2935 void R_Bloom_CopyHDRTexture(void)
2937 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2938 GL_ActiveTexture(0);
2940 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
2941 r_refdef.stats.bloom_copypixels += r_view.width * r_view.height;
2944 void R_Bloom_MakeTexture(void)
2947 float xoffset, yoffset, r, brighten;
2949 r_refdef.stats.bloom++;
2951 R_ResetViewRendering2D();
2952 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
2953 R_Mesh_ColorPointer(NULL, 0, 0);
2955 // we have a bloom image in the framebuffer
2957 qglViewport(r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
2959 for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
2962 r = bound(0, r_bloom_colorexponent.value / x, 1);
2963 GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
2964 GL_Color(r, r, r, 1);
2965 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2966 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
2967 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2968 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2970 // copy the vertically blurred bloom view to a texture
2971 GL_ActiveTexture(0);
2973 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
2974 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2977 range = r_bloom_blur.integer * r_bloomstate.bloomwidth / 320;
2978 brighten = r_bloom_brighten.value;
2980 brighten *= r_hdr_range.value;
2981 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2982 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.offsettexcoord2f, 0, 0);
2984 for (dir = 0;dir < 2;dir++)
2986 // blend on at multiple vertical offsets to achieve a vertical blur
2987 // TODO: do offset blends using GLSL
2988 GL_BlendFunc(GL_ONE, GL_ZERO);
2989 for (x = -range;x <= range;x++)
2991 if (!dir){xoffset = 0;yoffset = x;}
2992 else {xoffset = x;yoffset = 0;}
2993 xoffset /= (float)r_bloomstate.bloomtexturewidth;
2994 yoffset /= (float)r_bloomstate.bloomtextureheight;
2995 // compute a texcoord array with the specified x and y offset
2996 r_bloomstate.offsettexcoord2f[0] = xoffset+0;
2997 r_bloomstate.offsettexcoord2f[1] = yoffset+(float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
2998 r_bloomstate.offsettexcoord2f[2] = xoffset+(float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
2999 r_bloomstate.offsettexcoord2f[3] = yoffset+(float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
3000 r_bloomstate.offsettexcoord2f[4] = xoffset+(float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
3001 r_bloomstate.offsettexcoord2f[5] = yoffset+0;
3002 r_bloomstate.offsettexcoord2f[6] = xoffset+0;
3003 r_bloomstate.offsettexcoord2f[7] = yoffset+0;
3004 // this r value looks like a 'dot' particle, fading sharply to
3005 // black at the edges
3006 // (probably not realistic but looks good enough)
3007 //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
3008 //r = (dir ? 1.0f : brighten)/(range*2+1);
3009 r = (dir ? 1.0f : brighten)/(range*2+1)*(1 - x*x/(float)(range*range));
3010 GL_Color(r, r, r, 1);
3011 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3012 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
3013 GL_BlendFunc(GL_ONE, GL_ONE);
3016 // copy the vertically blurred bloom view to a texture
3017 GL_ActiveTexture(0);
3019 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
3020 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
3023 // apply subtract last
3024 // (just like it would be in a GLSL shader)
3025 if (r_bloom_colorsubtract.value > 0 && gl_support_ext_blend_subtract)
3027 GL_BlendFunc(GL_ONE, GL_ZERO);
3028 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
3029 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
3030 GL_Color(1, 1, 1, 1);
3031 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3032 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
3034 GL_BlendFunc(GL_ONE, GL_ONE);
3035 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
3036 R_Mesh_TexBind(0, R_GetTexture(r_texture_white));
3037 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
3038 GL_Color(r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, 1);
3039 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3040 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
3041 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
3043 // copy the darkened bloom view to a texture
3044 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
3045 GL_ActiveTexture(0);
3047 qglCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
3048 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
3052 void R_HDR_RenderBloomTexture(void)
3054 int oldwidth, oldheight;
3056 oldwidth = r_view.width;
3057 oldheight = r_view.height;
3058 r_view.width = r_bloomstate.bloomwidth;
3059 r_view.height = r_bloomstate.bloomheight;
3061 // TODO: support GL_EXT_framebuffer_object rather than reusing the framebuffer? it might improve SLI performance.
3062 // TODO: add exposure compensation features
3063 // TODO: add fp16 framebuffer support
3065 r_view.showdebug = false;
3066 r_view.colorscale = r_bloom_colorscale.value * r_hdr_scenebrightness.value;
3068 r_view.colorscale /= r_hdr_range.value;
3069 r_waterstate.numwaterplanes = 0;
3070 R_RenderScene(r_waterstate.enabled);
3071 r_view.showdebug = true;
3073 R_ResetViewRendering2D();
3075 R_Bloom_CopyHDRTexture();
3076 R_Bloom_MakeTexture();
3078 R_ResetViewRendering3D();
3081 if (r_timereport_active)
3082 R_TimeReport("clear");
3085 // restore the view settings
3086 r_view.width = oldwidth;
3087 r_view.height = oldheight;
3090 static void R_BlendView(void)
3092 if (r_bloomstate.enabled && r_bloomstate.hdr)
3094 // render high dynamic range bloom effect
3095 // the bloom texture was made earlier this render, so we just need to
3096 // blend it onto the screen...
3097 R_ResetViewRendering2D();
3098 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
3099 R_Mesh_ColorPointer(NULL, 0, 0);
3100 GL_Color(1, 1, 1, 1);
3101 GL_BlendFunc(GL_ONE, GL_ONE);
3102 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
3103 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
3104 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3105 r_refdef.stats.bloom_drawpixels += r_view.width * r_view.height;
3107 else if (r_bloomstate.enabled)
3109 // render simple bloom effect
3110 // copy the screen and shrink it and darken it for the bloom process
3111 R_Bloom_CopyScreenTexture(r_bloom_colorscale.value);
3112 // make the bloom texture
3113 R_Bloom_MakeTexture();
3114 // put the original screen image back in place and blend the bloom
3116 R_ResetViewRendering2D();
3117 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
3118 R_Mesh_ColorPointer(NULL, 0, 0);
3119 GL_Color(1, 1, 1, 1);
3120 GL_BlendFunc(GL_ONE, GL_ZERO);
3121 // do both in one pass if possible
3122 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
3123 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
3124 if (r_textureunits.integer >= 2 && gl_combine.integer)
3126 R_Mesh_TexCombine(1, GL_ADD, GL_ADD, 1, 1);
3127 R_Mesh_TexBind(1, R_GetTexture(r_bloomstate.texture_screen));
3128 R_Mesh_TexCoordPointer(1, 2, r_bloomstate.screentexcoord2f, 0, 0);
3132 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3133 r_refdef.stats.bloom_drawpixels += r_view.width * r_view.height;
3134 // now blend on the bloom texture
3135 GL_BlendFunc(GL_ONE, GL_ONE);
3136 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
3137 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
3139 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3140 r_refdef.stats.bloom_drawpixels += r_view.width * r_view.height;
3142 if (r_refdef.viewblend[3] >= (1.0f / 256.0f))
3144 // apply a color tint to the whole view
3145 R_ResetViewRendering2D();
3146 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
3147 R_Mesh_ColorPointer(NULL, 0, 0);
3148 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3149 GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
3150 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3154 void R_RenderScene(qboolean addwaterplanes);
3156 matrix4x4_t r_waterscrollmatrix;
3158 void R_UpdateVariables(void)
3162 r_refdef.farclip = 4096;
3163 if (r_refdef.worldmodel)
3164 r_refdef.farclip += VectorDistance(r_refdef.worldmodel->normalmins, r_refdef.worldmodel->normalmaxs);
3165 r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
3167 if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
3168 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
3169 r_refdef.polygonfactor = 0;
3170 r_refdef.polygonoffset = 0;
3171 r_refdef.shadowpolygonfactor = r_refdef.polygonfactor + r_shadow_polygonfactor.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
3172 r_refdef.shadowpolygonoffset = r_refdef.polygonoffset + r_shadow_polygonoffset.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
3174 r_refdef.rtworld = r_shadow_realtime_world.integer;
3175 r_refdef.rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
3176 r_refdef.rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer && r_dynamic.integer;
3177 r_refdef.rtdlightshadows = r_refdef.rtdlight && r_shadow_realtime_dlight_shadows.integer && gl_stencil;
3178 r_refdef.lightmapintensity = r_refdef.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
3179 if (r_showsurfaces.integer)
3181 r_refdef.rtworld = false;
3182 r_refdef.rtworldshadows = false;
3183 r_refdef.rtdlight = false;
3184 r_refdef.rtdlightshadows = false;
3185 r_refdef.lightmapintensity = 0;
3188 if (gamemode == GAME_NEHAHRA)
3190 if (gl_fogenable.integer)
3192 r_refdef.oldgl_fogenable = true;
3193 r_refdef.fog_density = gl_fogdensity.value;
3194 r_refdef.fog_red = gl_fogred.value;
3195 r_refdef.fog_green = gl_foggreen.value;
3196 r_refdef.fog_blue = gl_fogblue.value;
3198 else if (r_refdef.oldgl_fogenable)
3200 r_refdef.oldgl_fogenable = false;
3201 r_refdef.fog_density = 0;
3202 r_refdef.fog_red = 0;
3203 r_refdef.fog_green = 0;
3204 r_refdef.fog_blue = 0;
3207 if (r_refdef.fog_density)
3209 r_refdef.fogcolor[0] = bound(0.0f, r_refdef.fog_red , 1.0f);
3210 r_refdef.fogcolor[1] = bound(0.0f, r_refdef.fog_green, 1.0f);
3211 r_refdef.fogcolor[2] = bound(0.0f, r_refdef.fog_blue , 1.0f);
3213 if (r_refdef.fog_density)
3215 r_refdef.fogenabled = true;
3216 // this is the point where the fog reaches 0.9986 alpha, which we
3217 // consider a good enough cutoff point for the texture
3218 // (0.9986 * 256 == 255.6)
3219 r_refdef.fogrange = 400 / r_refdef.fog_density;
3220 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
3221 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
3222 // fog color was already set
3225 r_refdef.fogenabled = false;
3233 void R_RenderView(void)
3235 if (!r_refdef.entities/* || !r_refdef.worldmodel*/)
3236 return; //Host_Error ("R_RenderView: NULL worldmodel");
3238 R_Shadow_UpdateWorldLightSelection();
3240 R_Bloom_StartFrame();
3241 R_Water_StartFrame();
3244 if (r_timereport_active)
3245 R_TimeReport("setup");
3247 R_ResetViewRendering3D();
3250 if (r_timereport_active)
3251 R_TimeReport("clear");
3253 r_view.showdebug = true;
3255 // this produces a bloom texture to be used in R_BlendView() later
3257 R_HDR_RenderBloomTexture();
3259 r_view.colorscale = r_hdr_scenebrightness.value;
3260 r_waterstate.numwaterplanes = 0;
3261 R_RenderScene(r_waterstate.enabled);
3264 if (r_timereport_active)
3265 R_TimeReport("blendview");
3267 GL_Scissor(0, 0, vid.width, vid.height);
3268 GL_ScissorTest(false);
3272 extern void R_DrawLightningBeams (void);
3273 extern void VM_CL_AddPolygonsToMeshQueue (void);
3274 extern void R_DrawPortals (void);
3275 extern cvar_t cl_locs_show;
3276 static void R_DrawLocs(void);
3277 static void R_DrawEntityBBoxes(void);
3278 void R_RenderScene(qboolean addwaterplanes)
3282 R_ResetViewRendering3D();
3285 if (r_timereport_active)
3286 R_TimeReport("watervisibility");
3288 if (cl.csqc_vidvars.drawworld && r_refdef.worldmodel && r_refdef.worldmodel->DrawAddWaterPlanes)
3290 r_refdef.worldmodel->DrawAddWaterPlanes(r_refdef.worldentity);
3291 if (r_timereport_active)
3292 R_TimeReport("waterworld");
3295 // don't let sound skip if going slow
3296 if (r_refdef.extraupdate)
3299 R_DrawModelsAddWaterPlanes();
3300 if (r_timereport_active)
3301 R_TimeReport("watermodels");
3303 R_Water_ProcessPlanes();
3304 if (r_timereport_active)
3305 R_TimeReport("waterscenes");
3308 R_ResetViewRendering3D();
3310 // don't let sound skip if going slow
3311 if (r_refdef.extraupdate)
3314 R_MeshQueue_BeginScene();
3319 if (r_timereport_active)
3320 R_TimeReport("visibility");
3322 Matrix4x4_CreateTranslate(&r_waterscrollmatrix, sin(r_refdef.time) * 0.025 * r_waterscroll.value, sin(r_refdef.time * 0.8f) * 0.025 * r_waterscroll.value, 0);
3324 if (cl.csqc_vidvars.drawworld)
3326 // don't let sound skip if going slow
3327 if (r_refdef.extraupdate)
3330 if (r_refdef.worldmodel && r_refdef.worldmodel->DrawSky)
3332 r_refdef.worldmodel->DrawSky(r_refdef.worldentity);
3333 if (r_timereport_active)
3334 R_TimeReport("worldsky");
3337 if (R_DrawBrushModelsSky() && r_timereport_active)
3338 R_TimeReport("bmodelsky");
3341 if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.worldmodel && r_refdef.worldmodel->DrawDepth)
3343 r_refdef.worldmodel->DrawDepth(r_refdef.worldentity);
3344 if (r_timereport_active)
3345 R_TimeReport("worlddepth");
3347 if (r_depthfirst.integer >= 2)
3349 R_DrawModelsDepth();
3350 if (r_timereport_active)
3351 R_TimeReport("modeldepth");
3354 if (cl.csqc_vidvars.drawworld && r_refdef.worldmodel && r_refdef.worldmodel->Draw)
3356 r_refdef.worldmodel->Draw(r_refdef.worldentity);
3357 if (r_timereport_active)
3358 R_TimeReport("world");
3361 // don't let sound skip if going slow
3362 if (r_refdef.extraupdate)
3366 if (r_timereport_active)
3367 R_TimeReport("models");
3369 // don't let sound skip if going slow
3370 if (r_refdef.extraupdate)
3373 if (r_shadows.integer > 0 && r_refdef.lightmapintensity > 0)
3375 R_DrawModelShadows();
3377 R_ResetViewRendering3D();
3379 // don't let sound skip if going slow
3380 if (r_refdef.extraupdate)
3384 R_ShadowVolumeLighting(false);
3385 if (r_timereport_active)
3386 R_TimeReport("rtlights");
3388 // don't let sound skip if going slow
3389 if (r_refdef.extraupdate)
3392 if (cl.csqc_vidvars.drawworld)
3394 R_DrawLightningBeams();
3395 if (r_timereport_active)
3396 R_TimeReport("lightning");
3399 if (r_timereport_active)
3400 R_TimeReport("particles");
3403 if (r_timereport_active)
3404 R_TimeReport("explosions");
3407 if (gl_support_fragment_shader)
3409 qglUseProgramObjectARB(0);CHECKGLERROR
3411 VM_CL_AddPolygonsToMeshQueue();
3413 if (r_view.showdebug)
3415 if (cl_locs_show.integer)
3418 if (r_timereport_active)
3419 R_TimeReport("showlocs");
3422 if (r_drawportals.integer)
3425 if (r_timereport_active)
3426 R_TimeReport("portals");
3429 if (r_showbboxes.value > 0)
3431 R_DrawEntityBBoxes();
3432 if (r_timereport_active)
3433 R_TimeReport("bboxes");
3437 if (gl_support_fragment_shader)
3439 qglUseProgramObjectARB(0);CHECKGLERROR
3441 R_MeshQueue_RenderTransparent();
3442 if (r_timereport_active)
3443 R_TimeReport("drawtrans");
3445 if (gl_support_fragment_shader)
3447 qglUseProgramObjectARB(0);CHECKGLERROR
3450 if (r_view.showdebug && r_refdef.worldmodel && r_refdef.worldmodel->DrawDebug && (r_showtris.value > 0 || r_shownormals.value > 0 || r_showcollisionbrushes.value > 0))
3452 r_refdef.worldmodel->DrawDebug(r_refdef.worldentity);
3453 if (r_timereport_active)
3454 R_TimeReport("worlddebug");
3455 R_DrawModelsDebug();
3456 if (r_timereport_active)
3457 R_TimeReport("modeldebug");
3460 if (gl_support_fragment_shader)
3462 qglUseProgramObjectARB(0);CHECKGLERROR
3465 if (cl.csqc_vidvars.drawworld)
3468 if (r_timereport_active)
3469 R_TimeReport("coronas");
3472 // don't let sound skip if going slow
3473 if (r_refdef.extraupdate)
3476 R_ResetViewRendering2D();
3479 static const int bboxelements[36] =
3489 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
3492 float *v, *c, f1, f2, vertex3f[8*3], color4f[8*4];
3493 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3494 GL_DepthMask(false);
3495 GL_DepthRange(0, 1);
3496 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
3497 R_Mesh_Matrix(&identitymatrix);
3498 R_Mesh_ResetTextureState();
3500 vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2]; //
3501 vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
3502 vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
3503 vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
3504 vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
3505 vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
3506 vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
3507 vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
3508 R_FillColors(color4f, 8, cr, cg, cb, ca);
3509 if (r_refdef.fogenabled)
3511 for (i = 0, v = vertex3f, c = color4f;i < 8;i++, v += 3, c += 4)
3513 f1 = FogPoint_World(v);
3515 c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
3516 c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
3517 c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
3520 R_Mesh_VertexPointer(vertex3f, 0, 0);
3521 R_Mesh_ColorPointer(color4f, 0, 0);
3522 R_Mesh_ResetTextureState();
3523 R_Mesh_Draw(0, 8, 12, bboxelements, 0, 0);
3526 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3530 prvm_edict_t *edict;
3531 // this function draws bounding boxes of server entities
3535 for (i = 0;i < numsurfaces;i++)
3537 edict = PRVM_EDICT_NUM(surfacelist[i]);
3538 switch ((int)edict->fields.server->solid)
3540 case SOLID_NOT: Vector4Set(color, 1, 1, 1, 0.05);break;
3541 case SOLID_TRIGGER: Vector4Set(color, 1, 0, 1, 0.10);break;
3542 case SOLID_BBOX: Vector4Set(color, 0, 1, 0, 0.10);break;
3543 case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
3544 case SOLID_BSP: Vector4Set(color, 0, 0, 1, 0.05);break;
3545 default: Vector4Set(color, 0, 0, 0, 0.50);break;
3547 color[3] *= r_showbboxes.value;
3548 color[3] = bound(0, color[3], 1);
3549 GL_DepthTest(!r_showdisabledepthtest.integer);
3550 GL_CullFace(r_view.cullface_front);
3551 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
3556 static void R_DrawEntityBBoxes(void)
3559 prvm_edict_t *edict;
3561 // this function draws bounding boxes of server entities
3565 for (i = 0;i < prog->num_edicts;i++)
3567 edict = PRVM_EDICT_NUM(i);
3568 if (edict->priv.server->free)
3570 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
3571 R_MeshQueue_AddTransparent(center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)NULL);
3576 int nomodelelements[24] =
3588 float nomodelvertex3f[6*3] =
3598 float nomodelcolor4f[6*4] =
3600 0.0f, 0.0f, 0.5f, 1.0f,
3601 0.0f, 0.0f, 0.5f, 1.0f,
3602 0.0f, 0.5f, 0.0f, 1.0f,
3603 0.0f, 0.5f, 0.0f, 1.0f,
3604 0.5f, 0.0f, 0.0f, 1.0f,
3605 0.5f, 0.0f, 0.0f, 1.0f
3608 void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3613 // this is only called once per entity so numsurfaces is always 1, and
3614 // surfacelist is always {0}, so this code does not handle batches
3615 R_Mesh_Matrix(&ent->matrix);
3617 if (ent->flags & EF_ADDITIVE)
3619 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
3620 GL_DepthMask(false);
3622 else if (ent->alpha < 1)
3624 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3625 GL_DepthMask(false);
3629 GL_BlendFunc(GL_ONE, GL_ZERO);
3632 GL_DepthRange(0, (ent->flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
3633 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
3634 GL_DepthTest(!(ent->effects & EF_NODEPTHTEST));
3635 GL_CullFace((ent->effects & EF_DOUBLESIDED) ? GL_NONE : r_view.cullface_back);
3636 R_Mesh_VertexPointer(nomodelvertex3f, 0, 0);
3637 if (r_refdef.fogenabled)
3640 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
3641 R_Mesh_ColorPointer(color4f, 0, 0);
3642 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3643 f1 = FogPoint_World(org);
3645 for (i = 0, c = color4f;i < 6;i++, c += 4)
3647 c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
3648 c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
3649 c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
3653 else if (ent->alpha != 1)
3655 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
3656 R_Mesh_ColorPointer(color4f, 0, 0);
3657 for (i = 0, c = color4f;i < 6;i++, c += 4)
3661 R_Mesh_ColorPointer(nomodelcolor4f, 0, 0);
3662 R_Mesh_ResetTextureState();
3663 R_Mesh_Draw(0, 6, 8, nomodelelements, 0, 0);
3666 void R_DrawNoModel(entity_render_t *ent)
3669 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3670 //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
3671 R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_view.origin : org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
3673 // R_DrawNoModelCallback(ent, 0);
3676 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
3678 vec3_t right1, right2, diff, normal;
3680 VectorSubtract (org2, org1, normal);
3682 // calculate 'right' vector for start
3683 VectorSubtract (r_view.origin, org1, diff);
3684 CrossProduct (normal, diff, right1);
3685 VectorNormalize (right1);
3687 // calculate 'right' vector for end
3688 VectorSubtract (r_view.origin, org2, diff);
3689 CrossProduct (normal, diff, right2);
3690 VectorNormalize (right2);
3692 vert[ 0] = org1[0] + width * right1[0];
3693 vert[ 1] = org1[1] + width * right1[1];
3694 vert[ 2] = org1[2] + width * right1[2];
3695 vert[ 3] = org1[0] - width * right1[0];
3696 vert[ 4] = org1[1] - width * right1[1];
3697 vert[ 5] = org1[2] - width * right1[2];
3698 vert[ 6] = org2[0] - width * right2[0];
3699 vert[ 7] = org2[1] - width * right2[1];
3700 vert[ 8] = org2[2] - width * right2[2];
3701 vert[ 9] = org2[0] + width * right2[0];
3702 vert[10] = org2[1] + width * right2[1];
3703 vert[11] = org2[2] + width * right2[2];
3706 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
3708 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)
3713 if (r_refdef.fogenabled)
3714 fog = FogPoint_World(origin);
3716 R_Mesh_Matrix(&identitymatrix);
3717 GL_BlendFunc(blendfunc1, blendfunc2);
3723 GL_CullFace(r_view.cullface_front);
3726 GL_CullFace(r_view.cullface_back);
3728 GL_DepthMask(false);
3729 GL_DepthRange(0, depthshort ? 0.0625 : 1);
3730 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
3731 GL_DepthTest(!depthdisable);
3733 vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
3734 vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
3735 vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
3736 vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
3737 vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
3738 vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
3739 vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
3740 vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
3741 vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
3742 vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
3743 vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
3744 vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
3746 R_Mesh_VertexPointer(vertex3f, 0, 0);
3747 R_Mesh_ColorPointer(NULL, 0, 0);
3748 R_Mesh_ResetTextureState();
3749 R_Mesh_TexBind(0, R_GetTexture(texture));
3750 R_Mesh_TexCoordPointer(0, 2, spritetexcoord2f, 0, 0);
3751 // FIXME: fixed function path can't properly handle r_view.colorscale > 1
3752 GL_Color(cr * fog * r_view.colorscale, cg * fog * r_view.colorscale, cb * fog * r_view.colorscale, ca);
3753 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3755 if (blendfunc2 == GL_ONE_MINUS_SRC_ALPHA)
3757 R_Mesh_TexBind(0, R_GetTexture(fogtexture));
3758 GL_BlendFunc(blendfunc1, GL_ONE);
3760 GL_Color(r_refdef.fogcolor[0] * fog * r_view.colorscale, r_refdef.fogcolor[1] * fog * r_view.colorscale, r_refdef.fogcolor[2] * fog * r_view.colorscale, ca);
3761 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3765 int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
3770 VectorSet(v, x, y, z);
3771 for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
3772 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
3774 if (i == mesh->numvertices)
3776 if (mesh->numvertices < mesh->maxvertices)
3778 VectorCopy(v, vertex3f);
3779 mesh->numvertices++;
3781 return mesh->numvertices;
3787 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
3791 element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
3792 element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
3793 e = mesh->element3i + mesh->numtriangles * 3;
3794 for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
3796 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
3797 if (mesh->numtriangles < mesh->maxtriangles)
3802 mesh->numtriangles++;
3804 element[1] = element[2];
3808 void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
3812 element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
3813 element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
3814 e = mesh->element3i + mesh->numtriangles * 3;
3815 for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
3817 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
3818 if (mesh->numtriangles < mesh->maxtriangles)
3823 mesh->numtriangles++;
3825 element[1] = element[2];
3829 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
3830 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
3832 int planenum, planenum2;
3835 mplane_t *plane, *plane2;
3837 double temppoints[2][256*3];
3838 // figure out how large a bounding box we need to properly compute this brush
3840 for (w = 0;w < numplanes;w++)
3841 maxdist = max(maxdist, planes[w].dist);
3842 // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
3843 maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
3844 for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
3848 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
3849 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
3851 if (planenum2 == planenum)
3853 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);
3856 if (tempnumpoints < 3)
3858 // generate elements forming a triangle fan for this polygon
3859 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
3863 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)
3865 texturelayer_t *layer;
3866 layer = t->currentlayers + t->currentnumlayers++;
3868 layer->depthmask = depthmask;
3869 layer->blendfunc1 = blendfunc1;
3870 layer->blendfunc2 = blendfunc2;
3871 layer->texture = texture;
3872 layer->texmatrix = *matrix;
3873 layer->color[0] = r * r_view.colorscale;
3874 layer->color[1] = g * r_view.colorscale;
3875 layer->color[2] = b * r_view.colorscale;
3876 layer->color[3] = a;
3879 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
3882 index = parms[2] + r_refdef.time * parms[3];
3883 index -= floor(index);
3887 case Q3WAVEFUNC_NONE:
3888 case Q3WAVEFUNC_NOISE:
3889 case Q3WAVEFUNC_COUNT:
3892 case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
3893 case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
3894 case Q3WAVEFUNC_SAWTOOTH: f = index;break;
3895 case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
3896 case Q3WAVEFUNC_TRIANGLE:
3898 f = index - floor(index);
3909 return (float)(parms[0] + parms[1] * f);
3912 void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t)
3915 model_t *model = ent->model;
3918 q3shaderinfo_layer_tcmod_t *tcmod;
3920 // switch to an alternate material if this is a q1bsp animated material
3922 texture_t *texture = t;
3923 int s = ent->skinnum;
3924 if ((unsigned int)s >= (unsigned int)model->numskins)
3926 if (model->skinscenes)
3928 if (model->skinscenes[s].framecount > 1)
3929 s = model->skinscenes[s].firstframe + (unsigned int) (r_refdef.time * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
3931 s = model->skinscenes[s].firstframe;
3934 t = t + s * model->num_surfaces;
3937 // use an alternate animation if the entity's frame is not 0,
3938 // and only if the texture has an alternate animation
3939 if (ent->frame2 != 0 && t->anim_total[1])
3940 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(r_refdef.time * 5.0f) % t->anim_total[1]) : 0];
3942 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(r_refdef.time * 5.0f) % t->anim_total[0]) : 0];
3944 texture->currentframe = t;
3947 // update currentskinframe to be a qw skin or animation frame
3948 if ((i = ent->entitynumber - 1) >= 0 && i < cl.maxclients)
3950 if (strcmp(r_qwskincache[i], cl.scores[i].qw_skin))
3952 strlcpy(r_qwskincache[i], cl.scores[i].qw_skin, sizeof(r_qwskincache[i]));
3953 Con_DPrintf("loading skins/%s\n", r_qwskincache[i]);
3954 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);
3956 t->currentskinframe = r_qwskincache_skinframe[i];
3957 if (t->currentskinframe == NULL)
3958 t->currentskinframe = t->skinframes[(int)(t->skinframerate * (cl.time - ent->frame2time)) % t->numskinframes];
3960 else if (t->numskinframes >= 2)
3961 t->currentskinframe = t->skinframes[(int)(t->skinframerate * (cl.time - ent->frame2time)) % t->numskinframes];
3962 if (t->backgroundnumskinframes >= 2)
3963 t->backgroundcurrentskinframe = t->backgroundskinframes[(int)(t->backgroundskinframerate * (cl.time - ent->frame2time)) % t->backgroundnumskinframes];
3965 t->currentmaterialflags = t->basematerialflags;
3966 t->currentalpha = ent->alpha;
3967 if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_novis.integer))
3969 t->currentalpha *= r_wateralpha.value;
3971 * FIXME what is this supposed to do?
3972 // if rendering refraction/reflection, disable transparency
3973 if (r_waterstate.enabled && (t->currentalpha < 1 || (t->currentmaterialflags & MATERIALFLAG_ALPHA)))
3974 t->currentmaterialflags |= MATERIALFLAG_WATERSHADER;
3977 if(!r_waterstate.enabled)
3978 t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION);
3979 if (!(ent->flags & RENDER_LIGHT))
3980 t->currentmaterialflags |= MATERIALFLAG_FULLBRIGHT;
3981 if (ent->effects & EF_ADDITIVE)
3982 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
3983 else if (t->currentalpha < 1)
3984 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
3985 if (ent->effects & EF_DOUBLESIDED)
3986 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
3987 if (ent->effects & EF_NODEPTHTEST)
3988 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
3989 if (ent->flags & RENDER_VIEWMODEL)
3990 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
3991 if (t->backgroundnumskinframes && !(t->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED))
3992 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
3994 for (i = 0, tcmod = t->tcmods;i < Q3MAXTCMODS && (tcmod->tcmod || i < 1);i++, tcmod++)
3997 switch(tcmod->tcmod)
4001 if (t->currentmaterialflags & MATERIALFLAG_WATER && r_waterscroll.value != 0)
4002 matrix = r_waterscrollmatrix;
4004 matrix = identitymatrix;
4006 case Q3TCMOD_ENTITYTRANSLATE:
4007 // this is used in Q3 to allow the gamecode to control texcoord
4008 // scrolling on the entity, which is not supported in darkplaces yet.
4009 Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
4011 case Q3TCMOD_ROTATE:
4012 Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
4013 Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * r_refdef.time, 0, 0, 1);
4014 Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
4017 Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
4019 case Q3TCMOD_SCROLL:
4020 Matrix4x4_CreateTranslate(&matrix, tcmod->parms[0] * r_refdef.time, tcmod->parms[1] * r_refdef.time, 0);
4022 case Q3TCMOD_STRETCH:
4023 f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
4024 Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
4026 case Q3TCMOD_TRANSFORM:
4027 VectorSet(tcmat + 0, tcmod->parms[0], tcmod->parms[1], 0);
4028 VectorSet(tcmat + 3, tcmod->parms[2], tcmod->parms[3], 0);
4029 VectorSet(tcmat + 6, 0 , 0 , 1);
4030 VectorSet(tcmat + 9, tcmod->parms[4], tcmod->parms[5], 0);
4031 Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
4033 case Q3TCMOD_TURBULENT:
4034 // this is handled in the RSurf_PrepareVertices function
4035 matrix = identitymatrix;
4038 // either replace or concatenate the transformation
4040 t->currenttexmatrix = matrix;
4043 matrix4x4_t temp = t->currenttexmatrix;
4044 Matrix4x4_Concat(&t->currenttexmatrix, &matrix, &temp);
4048 t->colormapping = VectorLength2(ent->colormap_pantscolor) + VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f);
4049 t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
4050 t->glosstexture = r_texture_black;
4051 t->backgroundbasetexture = t->backgroundnumskinframes ? ((!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base) : r_texture_white;
4052 t->backgroundglosstexture = r_texture_black;
4053 t->specularpower = r_shadow_glossexponent.value;
4054 // TODO: store reference values for these in the texture?
4055 t->specularscale = 0;
4056 if (r_shadow_gloss.integer > 0)
4058 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
4060 if (r_shadow_glossintensity.value > 0)
4062 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
4063 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
4064 t->specularscale = r_shadow_glossintensity.value;
4067 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
4069 t->glosstexture = r_texture_white;
4070 t->backgroundglosstexture = r_texture_white;
4071 t->specularscale = r_shadow_gloss2intensity.value;
4075 // lightmaps mode looks bad with dlights using actual texturing, so turn
4076 // off the colormap and glossmap, but leave the normalmap on as it still
4077 // accurately represents the shading involved
4078 if (gl_lightmaps.integer && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
4080 t->basetexture = r_texture_white;
4081 t->specularscale = 0;
4084 t->currentpolygonfactor = r_refdef.polygonfactor + t->basepolygonfactor;
4085 t->currentpolygonoffset = r_refdef.polygonoffset + t->basepolygonoffset;
4086 // submodels are biased to avoid z-fighting with world surfaces that they
4087 // may be exactly overlapping (avoids z-fighting artifacts on certain
4088 // doors and things in Quake maps)
4089 if (ent->model->brush.submodel)
4091 t->currentpolygonfactor += r_polygonoffset_submodel_factor.value;
4092 t->currentpolygonoffset += r_polygonoffset_submodel_offset.value;
4095 VectorClear(t->dlightcolor);
4096 t->currentnumlayers = 0;
4097 if (!(t->currentmaterialflags & MATERIALFLAG_NODRAW))
4099 if (!(t->currentmaterialflags & MATERIALFLAG_SKY))
4101 int blendfunc1, blendfunc2, depthmask;
4102 if (t->currentmaterialflags & MATERIALFLAG_ADD)
4104 blendfunc1 = GL_SRC_ALPHA;
4105 blendfunc2 = GL_ONE;
4107 else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
4109 blendfunc1 = GL_SRC_ALPHA;
4110 blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
4112 else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
4114 blendfunc1 = t->customblendfunc[0];
4115 blendfunc2 = t->customblendfunc[1];
4119 blendfunc1 = GL_ONE;
4120 blendfunc2 = GL_ZERO;
4122 depthmask = !(t->currentmaterialflags & MATERIALFLAG_BLENDED);
4123 if (t->currentmaterialflags & (MATERIALFLAG_WATER | MATERIALFLAG_WALL))
4125 rtexture_t *currentbasetexture;
4127 if (r_refdef.fogenabled && (t->currentmaterialflags & MATERIALFLAG_BLENDED))
4128 layerflags |= TEXTURELAYERFLAG_FOGDARKEN;
4129 currentbasetexture = (VectorLength2(ent->colormap_pantscolor) + VectorLength2(ent->colormap_shirtcolor) < (1.0f / 1048576.0f) && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
4130 if (t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
4132 // fullbright is not affected by r_refdef.lightmapintensity
4133 R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_TEXTURE, currentbasetexture, &t->currenttexmatrix, ent->colormod[0], ent->colormod[1], ent->colormod[2], t->currentalpha);
4134 if (VectorLength2(ent->colormap_pantscolor) >= (1.0f / 1048576.0f) && t->currentskinframe->pants)
4135 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->pants, &t->currenttexmatrix, ent->colormap_pantscolor[0] * ent->colormod[0], ent->colormap_pantscolor[1] * ent->colormod[1], ent->colormap_pantscolor[2] * ent->colormod[2], t->currentalpha);
4136 if (VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->currentskinframe->shirt)
4137 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->shirt, &t->currenttexmatrix, ent->colormap_shirtcolor[0] * ent->colormod[0], ent->colormap_shirtcolor[1] * ent->colormod[1], ent->colormap_shirtcolor[2] * ent->colormod[2], t->currentalpha);
4142 // set the color tint used for lights affecting this surface
4143 VectorSet(t->dlightcolor, ent->colormod[0] * t->currentalpha, ent->colormod[1] * t->currentalpha, ent->colormod[2] * t->currentalpha);
4145 // q3bsp has no lightmap updates, so the lightstylevalue that
4146 // would normally be baked into the lightmap must be
4147 // applied to the color
4148 // FIXME: r_glsl 1 rendering doesn't support overbright lightstyles with this (the default light style is not overbright)
4149 if (ent->model->type == mod_brushq3)
4150 colorscale *= r_refdef.lightstylevalue[0] * (1.0f / 256.0f);
4151 colorscale *= r_refdef.lightmapintensity;
4152 R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE, currentbasetexture, &t->currenttexmatrix, ent->colormod[0] * colorscale, ent->colormod[1] * colorscale, ent->colormod[2] * colorscale, t->currentalpha);
4153 if (r_ambient.value >= (1.0f/64.0f))
4154 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, currentbasetexture, &t->currenttexmatrix, ent->colormod[0] * r_ambient.value * (1.0f / 64.0f), ent->colormod[1] * r_ambient.value * (1.0f / 64.0f), ent->colormod[2] * r_ambient.value * (1.0f / 64.0f), t->currentalpha);
4155 if (VectorLength2(ent->colormap_pantscolor) >= (1.0f / 1048576.0f) && t->currentskinframe->pants)
4157 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->currentskinframe->pants, &t->currenttexmatrix, ent->colormap_pantscolor[0] * ent->colormod[0] * colorscale, ent->colormap_pantscolor[1] * ent->colormod[1] * colorscale, ent->colormap_pantscolor[2] * ent->colormod[2] * colorscale, t->currentalpha);
4158 if (r_ambient.value >= (1.0f/64.0f))
4159 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->pants, &t->currenttexmatrix, ent->colormap_pantscolor[0] * ent->colormod[0] * r_ambient.value * (1.0f / 64.0f), ent->colormap_pantscolor[1] * ent->colormod[1] * r_ambient.value * (1.0f / 64.0f), ent->colormap_pantscolor[2] * ent->colormod[2] * r_ambient.value * (1.0f / 64.0f), t->currentalpha);
4161 if (VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->currentskinframe->shirt)
4163 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->currentskinframe->shirt, &t->currenttexmatrix, ent->colormap_shirtcolor[0] * ent->colormod[0] * colorscale, ent->colormap_shirtcolor[1] * ent->colormod[1] * colorscale, ent->colormap_shirtcolor[2] * ent->colormod[2] * colorscale, t->currentalpha);
4164 if (r_ambient.value >= (1.0f/64.0f))
4165 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->currentskinframe->shirt, &t->currenttexmatrix, ent->colormap_shirtcolor[0] * ent->colormod[0] * r_ambient.value * (1.0f / 64.0f), ent->colormap_shirtcolor[1] * ent->colormod[1] * r_ambient.value * (1.0f / 64.0f), ent->colormap_shirtcolor[2] * ent->colormod[2] * r_ambient.value * (1.0f / 64.0f), t->currentalpha);
4168 if (t->currentskinframe->glow != NULL)
4169 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->currentalpha);
4170 if (r_refdef.fogenabled && !(t->currentmaterialflags & MATERIALFLAG_ADD))
4172 // if this is opaque use alpha blend which will darken the earlier
4175 // if this is an alpha blended material, all the earlier passes
4176 // were darkened by fog already, so we only need to add the fog
4177 // color ontop through the fog mask texture
4179 // if this is an additive blended material, all the earlier passes
4180 // were darkened by fog already, and we should not add fog color
4181 // (because the background was not darkened, there is no fog color
4182 // that was lost behind it).
4183 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.fogcolor[1], r_refdef.fogcolor[2], t->currentalpha);
4190 void R_UpdateAllTextureInfo(entity_render_t *ent)
4194 for (i = 0;i < ent->model->num_texturesperskin;i++)
4195 R_UpdateTextureInfo(ent, ent->model->data_textures + i);
4198 rsurfacestate_t rsurface;
4200 void R_Mesh_ResizeArrays(int newvertices)
4203 if (rsurface.array_size >= newvertices)
4205 if (rsurface.array_modelvertex3f)
4206 Mem_Free(rsurface.array_modelvertex3f);
4207 rsurface.array_size = (newvertices + 1023) & ~1023;
4208 base = (float *)Mem_Alloc(r_main_mempool, rsurface.array_size * sizeof(float[33]));
4209 rsurface.array_modelvertex3f = base + rsurface.array_size * 0;
4210 rsurface.array_modelsvector3f = base + rsurface.array_size * 3;
4211 rsurface.array_modeltvector3f = base + rsurface.array_size * 6;
4212 rsurface.array_modelnormal3f = base + rsurface.array_size * 9;
4213 rsurface.array_deformedvertex3f = base + rsurface.array_size * 12;
4214 rsurface.array_deformedsvector3f = base + rsurface.array_size * 15;
4215 rsurface.array_deformedtvector3f = base + rsurface.array_size * 18;
4216 rsurface.array_deformednormal3f = base + rsurface.array_size * 21;
4217 rsurface.array_texcoord3f = base + rsurface.array_size * 24;
4218 rsurface.array_color4f = base + rsurface.array_size * 27;
4219 rsurface.array_generatedtexcoordtexture2f = base + rsurface.array_size * 31;
4222 void RSurf_CleanUp(void)
4225 if (rsurface.mode == RSURFMODE_GLSL)
4227 qglUseProgramObjectARB(0);CHECKGLERROR
4229 GL_AlphaTest(false);
4230 rsurface.mode = RSURFMODE_NONE;
4231 rsurface.uselightmaptexture = false;
4232 rsurface.texture = NULL;
4235 void RSurf_ActiveWorldEntity(void)
4237 model_t *model = r_refdef.worldmodel;
4239 if (rsurface.array_size < model->surfmesh.num_vertices)
4240 R_Mesh_ResizeArrays(model->surfmesh.num_vertices);
4241 rsurface.matrix = identitymatrix;
4242 rsurface.inversematrix = identitymatrix;
4243 R_Mesh_Matrix(&identitymatrix);
4244 VectorCopy(r_view.origin, rsurface.modelorg);
4245 VectorSet(rsurface.modellight_ambient, 0, 0, 0);
4246 VectorSet(rsurface.modellight_diffuse, 0, 0, 0);
4247 VectorSet(rsurface.modellight_lightdir, 0, 0, 1);
4248 VectorSet(rsurface.colormap_pantscolor, 0, 0, 0);
4249 VectorSet(rsurface.colormap_shirtcolor, 0, 0, 0);
4250 rsurface.frameblend[0].frame = 0;
4251 rsurface.frameblend[0].lerp = 1;
4252 rsurface.frameblend[1].frame = 0;
4253 rsurface.frameblend[1].lerp = 0;
4254 rsurface.frameblend[2].frame = 0;
4255 rsurface.frameblend[2].lerp = 0;
4256 rsurface.frameblend[3].frame = 0;
4257 rsurface.frameblend[3].lerp = 0;
4258 rsurface.modelvertex3f = model->surfmesh.data_vertex3f;
4259 rsurface.modelvertex3f_bufferobject = model->surfmesh.vbo;
4260 rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f;
4261 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
4262 rsurface.modelsvector3f_bufferobject = model->surfmesh.vbo;
4263 rsurface.modelsvector3f_bufferoffset = model->surfmesh.vbooffset_svector3f;
4264 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
4265 rsurface.modeltvector3f_bufferobject = model->surfmesh.vbo;
4266 rsurface.modeltvector3f_bufferoffset = model->surfmesh.vbooffset_tvector3f;
4267 rsurface.modelnormal3f = model->surfmesh.data_normal3f;
4268 rsurface.modelnormal3f_bufferobject = model->surfmesh.vbo;
4269 rsurface.modelnormal3f_bufferoffset = model->surfmesh.vbooffset_normal3f;
4270 rsurface.modellightmapcolor4f = model->surfmesh.data_lightmapcolor4f;
4271 rsurface.modellightmapcolor4f_bufferobject = model->surfmesh.vbo;
4272 rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.vbooffset_lightmapcolor4f;
4273 rsurface.modeltexcoordtexture2f = model->surfmesh.data_texcoordtexture2f;
4274 rsurface.modeltexcoordtexture2f_bufferobject = model->surfmesh.vbo;
4275 rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.vbooffset_texcoordtexture2f;
4276 rsurface.modeltexcoordlightmap2f = model->surfmesh.data_texcoordlightmap2f;
4277 rsurface.modeltexcoordlightmap2f_bufferobject = model->surfmesh.vbo;
4278 rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f;
4279 rsurface.modelelement3i = model->surfmesh.data_element3i;
4280 rsurface.modelelement3i_bufferobject = model->surfmesh.ebo;
4281 rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
4282 rsurface.modelnum_vertices = model->surfmesh.num_vertices;
4283 rsurface.modelnum_triangles = model->surfmesh.num_triangles;
4284 rsurface.modelsurfaces = model->data_surfaces;
4285 rsurface.generatedvertex = false;
4286 rsurface.vertex3f = rsurface.modelvertex3f;
4287 rsurface.vertex3f_bufferobject = rsurface.modelvertex3f_bufferobject;
4288 rsurface.vertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
4289 rsurface.svector3f = rsurface.modelsvector3f;
4290 rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject;
4291 rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
4292 rsurface.tvector3f = rsurface.modeltvector3f;
4293 rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject;
4294 rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
4295 rsurface.normal3f = rsurface.modelnormal3f;
4296 rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject;
4297 rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
4298 rsurface.texcoordtexture2f = rsurface.modeltexcoordtexture2f;
4301 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
4303 model_t *model = ent->model;
4305 if (rsurface.array_size < model->surfmesh.num_vertices)
4306 R_Mesh_ResizeArrays(model->surfmesh.num_vertices);
4307 rsurface.matrix = ent->matrix;
4308 rsurface.inversematrix = ent->inversematrix;
4309 R_Mesh_Matrix(&rsurface.matrix);
4310 Matrix4x4_Transform(&rsurface.inversematrix, r_view.origin, rsurface.modelorg);
4311 VectorCopy(ent->modellight_ambient, rsurface.modellight_ambient);
4312 VectorCopy(ent->modellight_diffuse, rsurface.modellight_diffuse);
4313 VectorCopy(ent->modellight_lightdir, rsurface.modellight_lightdir);
4314 VectorCopy(ent->colormap_pantscolor, rsurface.colormap_pantscolor);
4315 VectorCopy(ent->colormap_shirtcolor, rsurface.colormap_shirtcolor);
4316 rsurface.frameblend[0] = ent->frameblend[0];
4317 rsurface.frameblend[1] = ent->frameblend[1];
4318 rsurface.frameblend[2] = ent->frameblend[2];
4319 rsurface.frameblend[3] = ent->frameblend[3];
4320 if (model->surfmesh.isanimated && (rsurface.frameblend[0].lerp != 1 || rsurface.frameblend[0].frame != 0))
4324 rsurface.modelvertex3f = rsurface.array_modelvertex3f;
4325 rsurface.modelsvector3f = rsurface.array_modelsvector3f;
4326 rsurface.modeltvector3f = rsurface.array_modeltvector3f;
4327 rsurface.modelnormal3f = rsurface.array_modelnormal3f;
4328 Mod_Alias_GetMesh_Vertices(model, rsurface.frameblend, rsurface.array_modelvertex3f, rsurface.array_modelnormal3f, rsurface.array_modelsvector3f, rsurface.array_modeltvector3f);
4330 else if (wantnormals)
4332 rsurface.modelvertex3f = rsurface.array_modelvertex3f;
4333 rsurface.modelsvector3f = NULL;
4334 rsurface.modeltvector3f = NULL;
4335 rsurface.modelnormal3f = rsurface.array_modelnormal3f;
4336 Mod_Alias_GetMesh_Vertices(model, rsurface.frameblend, rsurface.array_modelvertex3f, rsurface.array_modelnormal3f, NULL, NULL);
4340 rsurface.modelvertex3f = rsurface.array_modelvertex3f;
4341 rsurface.modelsvector3f = NULL;
4342 rsurface.modeltvector3f = NULL;
4343 rsurface.modelnormal3f = NULL;
4344 Mod_Alias_GetMesh_Vertices(model, rsurface.frameblend, rsurface.array_modelvertex3f, NULL, NULL, NULL);
4346 rsurface.modelvertex3f_bufferobject = 0;
4347 rsurface.modelvertex3f_bufferoffset = 0;
4348 rsurface.modelsvector3f_bufferobject = 0;
4349 rsurface.modelsvector3f_bufferoffset = 0;
4350 rsurface.modeltvector3f_bufferobject = 0;
4351 rsurface.modeltvector3f_bufferoffset = 0;
4352 rsurface.modelnormal3f_bufferobject = 0;
4353 rsurface.modelnormal3f_bufferoffset = 0;
4354 rsurface.generatedvertex = true;
4358 rsurface.modelvertex3f = model->surfmesh.data_vertex3f;
4359 rsurface.modelvertex3f_bufferobject = model->surfmesh.vbo;
4360 rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f;
4361 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
4362 rsurface.modelsvector3f_bufferobject = model->surfmesh.vbo;
4363 rsurface.modelsvector3f_bufferoffset = model->surfmesh.vbooffset_svector3f;
4364 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
4365 rsurface.modeltvector3f_bufferobject = model->surfmesh.vbo;
4366 rsurface.modeltvector3f_bufferoffset = model->surfmesh.vbooffset_tvector3f;
4367 rsurface.modelnormal3f = model->surfmesh.data_normal3f;
4368 rsurface.modelnormal3f_bufferobject = model->surfmesh.vbo;
4369 rsurface.modelnormal3f_bufferoffset = model->surfmesh.vbooffset_normal3f;
4370 rsurface.generatedvertex = false;
4372 rsurface.modellightmapcolor4f = model->surfmesh.data_lightmapcolor4f;
4373 rsurface.modellightmapcolor4f_bufferobject = model->surfmesh.vbo;
4374 rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.vbooffset_lightmapcolor4f;
4375 rsurface.modeltexcoordtexture2f = model->surfmesh.data_texcoordtexture2f;
4376 rsurface.modeltexcoordtexture2f_bufferobject = model->surfmesh.vbo;
4377 rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.vbooffset_texcoordtexture2f;
4378 rsurface.modeltexcoordlightmap2f = model->surfmesh.data_texcoordlightmap2f;
4379 rsurface.modeltexcoordlightmap2f_bufferobject = model->surfmesh.vbo;
4380 rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f;
4381 rsurface.modelelement3i = model->surfmesh.data_element3i;
4382 rsurface.modelelement3i_bufferobject = model->surfmesh.ebo;
4383 rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
4384 rsurface.modelnum_vertices = model->surfmesh.num_vertices;
4385 rsurface.modelnum_triangles = model->surfmesh.num_triangles;
4386 rsurface.modelsurfaces = model->data_surfaces;
4387 rsurface.vertex3f = rsurface.modelvertex3f;
4388 rsurface.vertex3f_bufferobject = rsurface.modelvertex3f_bufferobject;
4389 rsurface.vertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
4390 rsurface.svector3f = rsurface.modelsvector3f;
4391 rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject;
4392 rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
4393 rsurface.tvector3f = rsurface.modeltvector3f;
4394 rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject;
4395 rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
4396 rsurface.normal3f = rsurface.modelnormal3f;
4397 rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject;
4398 rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
4399 rsurface.texcoordtexture2f = rsurface.modeltexcoordtexture2f;
4402 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
4403 void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generatetangents, int texturenumsurfaces, msurface_t **texturesurfacelist)
4406 int texturesurfaceindex;
4411 const float *v1, *in_tc;
4413 float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
4415 q3shaderinfo_deform_t *deform;
4416 // 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
4417 if (rsurface.generatedvertex)
4419 if (rsurface.texture->tcgen.tcgen == Q3TCGEN_ENVIRONMENT)
4420 generatenormals = true;
4421 for (i = 0;i < Q3MAXDEFORMS;i++)
4423 if (rsurface.texture->deforms[i].deform == Q3DEFORM_AUTOSPRITE)
4425 generatetangents = true;
4426 generatenormals = true;
4428 if (rsurface.texture->deforms[i].deform != Q3DEFORM_NONE)
4429 generatenormals = true;
4431 if (generatenormals && !rsurface.modelnormal3f)
4433 rsurface.normal3f = rsurface.modelnormal3f = rsurface.array_modelnormal3f;
4434 rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject = 0;
4435 rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset = 0;
4436 Mod_BuildNormals(0, rsurface.modelnum_vertices, rsurface.modelnum_triangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.array_modelnormal3f, r_smoothnormals_areaweighting.integer);
4438 if (generatetangents && !rsurface.modelsvector3f)
4440 rsurface.svector3f = rsurface.modelsvector3f = rsurface.array_modelsvector3f;
4441 rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject = 0;
4442 rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset = 0;
4443 rsurface.tvector3f = rsurface.modeltvector3f = rsurface.array_modeltvector3f;
4444 rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject = 0;
4445 rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset = 0;
4446 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);
4449 rsurface.vertex3f = rsurface.modelvertex3f;
4450 rsurface.vertex3f_bufferobject = rsurface.modelvertex3f_bufferobject;
4451 rsurface.vertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
4452 rsurface.svector3f = rsurface.modelsvector3f;
4453 rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject;
4454 rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
4455 rsurface.tvector3f = rsurface.modeltvector3f;
4456 rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject;
4457 rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
4458 rsurface.normal3f = rsurface.modelnormal3f;
4459 rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject;
4460 rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
4461 // if vertices are deformed (sprite flares and things in maps, possibly
4462 // water waves, bulges and other deformations), generate them into
4463 // rsurface.deform* arrays from whatever the rsurface.* arrays point to
4464 // (may be static model data or generated data for an animated model, or
4465 // the previous deform pass)
4466 for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform;deformindex++, deform++)
4468 switch (deform->deform)
4471 case Q3DEFORM_PROJECTIONSHADOW:
4472 case Q3DEFORM_TEXT0:
4473 case Q3DEFORM_TEXT1:
4474 case Q3DEFORM_TEXT2:
4475 case Q3DEFORM_TEXT3:
4476 case Q3DEFORM_TEXT4:
4477 case Q3DEFORM_TEXT5:
4478 case Q3DEFORM_TEXT6:
4479 case Q3DEFORM_TEXT7:
4482 case Q3DEFORM_AUTOSPRITE:
4483 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.forward, newforward);
4484 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.right, newright);
4485 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.up, newup);
4486 VectorNormalize(newforward);
4487 VectorNormalize(newright);
4488 VectorNormalize(newup);
4489 // make deformed versions of only the model vertices used by the specified surfaces
4490 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4492 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4493 // a single autosprite surface can contain multiple sprites...
4494 for (j = 0;j < surface->num_vertices - 3;j += 4)
4496 VectorClear(center);
4497 for (i = 0;i < 4;i++)
4498 VectorAdd(center, (rsurface.vertex3f + 3 * surface->num_firstvertex) + (j+i) * 3, center);
4499 VectorScale(center, 0.25f, center);
4500 VectorCopy((rsurface.normal3f + 3 * surface->num_firstvertex) + j*3, forward);
4501 VectorCopy((rsurface.svector3f + 3 * surface->num_firstvertex) + j*3, right);
4502 VectorCopy((rsurface.tvector3f + 3 * surface->num_firstvertex) + j*3, up);
4503 for (i = 0;i < 4;i++)
4505 VectorSubtract((rsurface.vertex3f + 3 * surface->num_firstvertex) + (j+i)*3, center, v);
4506 VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.array_deformedvertex3f + (surface->num_firstvertex+i+j) * 3);
4509 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);
4510 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);
4512 rsurface.vertex3f = rsurface.array_deformedvertex3f;
4513 rsurface.vertex3f_bufferobject = 0;
4514 rsurface.vertex3f_bufferoffset = 0;
4515 rsurface.svector3f = rsurface.array_deformedsvector3f;
4516 rsurface.svector3f_bufferobject = 0;
4517 rsurface.svector3f_bufferoffset = 0;
4518 rsurface.tvector3f = rsurface.array_deformedtvector3f;
4519 rsurface.tvector3f_bufferobject = 0;
4520 rsurface.tvector3f_bufferoffset = 0;
4521 rsurface.normal3f = rsurface.array_deformednormal3f;
4522 rsurface.normal3f_bufferobject = 0;
4523 rsurface.normal3f_bufferoffset = 0;
4525 case Q3DEFORM_AUTOSPRITE2:
4526 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.forward, newforward);
4527 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.right, newright);
4528 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.up, newup);
4529 VectorNormalize(newforward);
4530 VectorNormalize(newright);
4531 VectorNormalize(newup);
4532 // make deformed versions of only the model vertices used by the specified surfaces
4533 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4535 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4536 const float *v1, *v2;
4546 memset(shortest, 0, sizeof(shortest));
4547 // a single autosprite surface can contain multiple sprites...
4548 for (j = 0;j < surface->num_vertices - 3;j += 4)
4550 VectorClear(center);
4551 for (i = 0;i < 4;i++)
4552 VectorAdd(center, (rsurface.vertex3f + 3 * surface->num_firstvertex) + (j+i) * 3, center);
4553 VectorScale(center, 0.25f, center);
4554 // find the two shortest edges, then use them to define the
4555 // axis vectors for rotating around the central axis
4556 for (i = 0;i < 6;i++)
4558 v1 = rsurface.vertex3f + 3 * (surface->num_firstvertex + quadedges[i][0]);
4559 v2 = rsurface.vertex3f + 3 * (surface->num_firstvertex + quadedges[i][1]);
4561 Debug_PolygonBegin(NULL, 0, false, 0);
4562 Debug_PolygonVertex(v1[0], v1[1], v1[2], 0, 0, 1, 0, 0, 1);
4563 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);
4564 Debug_PolygonVertex(v2[0], v2[1], v2[2], 0, 0, 1, 0, 0, 1);
4567 l = VectorDistance2(v1, v2);
4568 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
4570 l += (1.0f / 1024.0f);
4571 if (shortest[0].length2 > l || i == 0)
4573 shortest[1] = shortest[0];
4574 shortest[0].length2 = l;
4575 shortest[0].v1 = v1;
4576 shortest[0].v2 = v2;
4578 else if (shortest[1].length2 > l || i == 1)
4580 shortest[1].length2 = l;
4581 shortest[1].v1 = v1;
4582 shortest[1].v2 = v2;
4585 VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
4586 VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
4588 Debug_PolygonBegin(NULL, 0, false, 0);
4589 Debug_PolygonVertex(start[0], start[1], start[2], 0, 0, 1, 1, 0, 1);
4590 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);
4591 Debug_PolygonVertex(end[0], end[1], end[2], 0, 0, 0, 1, 1, 1);
4594 // this calculates the right vector from the shortest edge
4595 // and the up vector from the edge midpoints
4596 VectorSubtract(shortest[0].v1, shortest[0].v2, right);
4597 VectorNormalize(right);
4598 VectorSubtract(end, start, up);
4599 VectorNormalize(up);
4600 // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
4601 //VectorSubtract(rsurface.modelorg, center, forward);
4602 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.forward, forward);
4603 VectorNegate(forward, forward);
4604 VectorReflect(forward, 0, up, forward);
4605 VectorNormalize(forward);
4606 CrossProduct(up, forward, newright);
4607 VectorNormalize(newright);
4609 Debug_PolygonBegin(NULL, 0, false, 0);
4610 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);
4611 Debug_PolygonVertex(center[0] + right[0] * 8, center[1] + right[1] * 8, center[2] + right[2] * 8, 0, 0, 0, 1, 0, 1);
4612 Debug_PolygonVertex(center[0] + up [0] * 8, center[1] + up [1] * 8, center[2] + up [2] * 8, 0, 0, 0, 0, 1, 1);
4616 Debug_PolygonBegin(NULL, 0, false, 0);
4617 Debug_PolygonVertex(center[0] + forward [0] * 8, center[1] + forward [1] * 8, center[2] + forward [2] * 8, 0, 0, 1, 0, 0, 1);
4618 Debug_PolygonVertex(center[0] + newright[0] * 8, center[1] + newright[1] * 8, center[2] + newright[2] * 8, 0, 0, 0, 1, 0, 1);
4619 Debug_PolygonVertex(center[0] + up [0] * 8, center[1] + up [1] * 8, center[2] + up [2] * 8, 0, 0, 0, 0, 1, 1);
4622 // rotate the quad around the up axis vector, this is made
4623 // especially easy by the fact we know the quad is flat,
4624 // so we only have to subtract the center position and
4625 // measure distance along the right vector, and then
4626 // multiply that by the newright vector and add back the
4628 // we also need to subtract the old position to undo the
4629 // displacement from the center, which we do with a
4630 // DotProduct, the subtraction/addition of center is also
4631 // optimized into DotProducts here
4632 l = DotProduct(right, center);
4633 for (i = 0;i < 4;i++)
4635 v1 = rsurface.vertex3f + 3 * (surface->num_firstvertex + j + i);
4636 f = DotProduct(right, v1) - l;
4637 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.array_deformedvertex3f + (surface->num_firstvertex+i+j) * 3);
4640 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);
4641 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);
4643 rsurface.vertex3f = rsurface.array_deformedvertex3f;
4644 rsurface.vertex3f_bufferobject = 0;
4645 rsurface.vertex3f_bufferoffset = 0;
4646 rsurface.svector3f = rsurface.array_deformedsvector3f;
4647 rsurface.svector3f_bufferobject = 0;
4648 rsurface.svector3f_bufferoffset = 0;
4649 rsurface.tvector3f = rsurface.array_deformedtvector3f;
4650 rsurface.tvector3f_bufferobject = 0;
4651 rsurface.tvector3f_bufferoffset = 0;
4652 rsurface.normal3f = rsurface.array_deformednormal3f;
4653 rsurface.normal3f_bufferobject = 0;
4654 rsurface.normal3f_bufferoffset = 0;
4656 case Q3DEFORM_NORMAL:
4657 // deform the normals to make reflections wavey
4658 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4660 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4661 for (j = 0;j < surface->num_vertices;j++)
4664 float *normal = (rsurface.array_deformednormal3f + 3 * surface->num_firstvertex) + j*3;
4665 VectorScale((rsurface.vertex3f + 3 * surface->num_firstvertex) + j*3, 0.98f, vertex);
4666 VectorCopy((rsurface.normal3f + 3 * surface->num_firstvertex) + j*3, normal);
4667 normal[0] += deform->parms[0] * noise4f( vertex[0], vertex[1], vertex[2], r_refdef.time * deform->parms[1]);
4668 normal[1] += deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], r_refdef.time * deform->parms[1]);
4669 normal[2] += deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], r_refdef.time * deform->parms[1]);
4670 VectorNormalize(normal);
4672 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);
4674 rsurface.svector3f = rsurface.array_deformedsvector3f;
4675 rsurface.svector3f_bufferobject = 0;
4676 rsurface.svector3f_bufferoffset = 0;
4677 rsurface.tvector3f = rsurface.array_deformedtvector3f;
4678 rsurface.tvector3f_bufferobject = 0;
4679 rsurface.tvector3f_bufferoffset = 0;
4680 rsurface.normal3f = rsurface.array_deformednormal3f;
4681 rsurface.normal3f_bufferobject = 0;
4682 rsurface.normal3f_bufferoffset = 0;
4685 // deform vertex array to make wavey water and flags and such
4686 waveparms[0] = deform->waveparms[0];
4687 waveparms[1] = deform->waveparms[1];
4688 waveparms[2] = deform->waveparms[2];
4689 waveparms[3] = deform->waveparms[3];
4690 // this is how a divisor of vertex influence on deformation
4691 animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
4692 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
4693 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4695 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4696 for (j = 0;j < surface->num_vertices;j++)
4698 float *vertex = (rsurface.array_deformedvertex3f + 3 * surface->num_firstvertex) + j*3;
4699 VectorCopy((rsurface.vertex3f + 3 * surface->num_firstvertex) + j*3, vertex);
4700 // if the wavefunc depends on time, evaluate it per-vertex
4703 waveparms[2] = deform->waveparms[2] + (vertex[0] + vertex[1] + vertex[2]) * animpos;
4704 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
4706 VectorMA(vertex, scale, (rsurface.normal3f + 3 * surface->num_firstvertex) + j*3, vertex);
4709 rsurface.vertex3f = rsurface.array_deformedvertex3f;
4710 rsurface.vertex3f_bufferobject = 0;
4711 rsurface.vertex3f_bufferoffset = 0;
4713 case Q3DEFORM_BULGE:
4714 // deform vertex array to make the surface have moving bulges
4715 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4717 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4718 for (j = 0;j < surface->num_vertices;j++)
4720 scale = sin((rsurface.modeltexcoordtexture2f[2 * (surface->num_firstvertex + j)] * deform->parms[0] + r_refdef.time * deform->parms[2])) * deform->parms[1];
4721 VectorMA(rsurface.vertex3f + 3 * (surface->num_firstvertex + j), scale, rsurface.normal3f + 3 * (surface->num_firstvertex + j), rsurface.array_deformedvertex3f + 3 * (surface->num_firstvertex + j));
4724 rsurface.vertex3f = rsurface.array_deformedvertex3f;
4725 rsurface.vertex3f_bufferobject = 0;
4726 rsurface.vertex3f_bufferoffset = 0;
4729 // deform vertex array
4730 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
4731 VectorScale(deform->parms, scale, waveparms);
4732 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4734 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4735 for (j = 0;j < surface->num_vertices;j++)
4736 VectorAdd(rsurface.vertex3f + 3 * (surface->num_firstvertex + j), waveparms, rsurface.array_deformedvertex3f + 3 * (surface->num_firstvertex + j));
4738 rsurface.vertex3f = rsurface.array_deformedvertex3f;
4739 rsurface.vertex3f_bufferobject = 0;
4740 rsurface.vertex3f_bufferoffset = 0;
4744 // generate texcoords based on the chosen texcoord source
4745 switch(rsurface.texture->tcgen.tcgen)
4748 case Q3TCGEN_TEXTURE:
4749 rsurface.texcoordtexture2f = rsurface.modeltexcoordtexture2f;
4750 rsurface.texcoordtexture2f_bufferobject = rsurface.modeltexcoordtexture2f_bufferobject;
4751 rsurface.texcoordtexture2f_bufferoffset = rsurface.modeltexcoordtexture2f_bufferoffset;
4753 case Q3TCGEN_LIGHTMAP:
4754 rsurface.texcoordtexture2f = rsurface.modeltexcoordlightmap2f;
4755 rsurface.texcoordtexture2f_bufferobject = rsurface.modeltexcoordlightmap2f_bufferobject;
4756 rsurface.texcoordtexture2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
4758 case Q3TCGEN_VECTOR:
4759 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4761 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4762 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)
4764 out_tc[0] = DotProduct(v1, rsurface.texture->tcgen.parms);
4765 out_tc[1] = DotProduct(v1, rsurface.texture->tcgen.parms + 3);
4768 rsurface.texcoordtexture2f = rsurface.array_generatedtexcoordtexture2f;
4769 rsurface.texcoordtexture2f_bufferobject = 0;
4770 rsurface.texcoordtexture2f_bufferoffset = 0;
4772 case Q3TCGEN_ENVIRONMENT:
4773 // make environment reflections using a spheremap
4774 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4776 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4777 const float *vertex = rsurface.modelvertex3f + 3 * surface->num_firstvertex;
4778 const float *normal = rsurface.modelnormal3f + 3 * surface->num_firstvertex;
4779 float *out_tc = rsurface.array_generatedtexcoordtexture2f + 2 * surface->num_firstvertex;
4780 for (j = 0;j < surface->num_vertices;j++, vertex += 3, normal += 3, out_tc += 2)
4782 float l, d, eyedir[3];
4783 VectorSubtract(rsurface.modelorg, vertex, eyedir);
4784 l = 0.5f / VectorLength(eyedir);
4785 d = DotProduct(normal, eyedir)*2;
4786 out_tc[0] = 0.5f + (normal[1]*d - eyedir[1])*l;
4787 out_tc[1] = 0.5f - (normal[2]*d - eyedir[2])*l;
4790 rsurface.texcoordtexture2f = rsurface.array_generatedtexcoordtexture2f;
4791 rsurface.texcoordtexture2f_bufferobject = 0;
4792 rsurface.texcoordtexture2f_bufferoffset = 0;
4795 // the only tcmod that needs software vertex processing is turbulent, so
4796 // check for it here and apply the changes if needed
4797 // and we only support that as the first one
4798 // (handling a mixture of turbulent and other tcmods would be problematic
4799 // without punting it entirely to a software path)
4800 if (rsurface.texture->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
4802 amplitude = rsurface.texture->tcmods[0].parms[1];
4803 animpos = rsurface.texture->tcmods[0].parms[2] + r_refdef.time * rsurface.texture->tcmods[0].parms[3];
4804 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4806 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4807 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)
4809 out_tc[0] = in_tc[0] + amplitude * sin(((v1[0] + v1[2]) * 1.0 / 1024.0f + animpos) * M_PI * 2);
4810 out_tc[1] = in_tc[1] + amplitude * sin(((v1[1] ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
4813 rsurface.texcoordtexture2f = rsurface.array_generatedtexcoordtexture2f;
4814 rsurface.texcoordtexture2f_bufferobject = 0;
4815 rsurface.texcoordtexture2f_bufferoffset = 0;
4817 rsurface.texcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
4818 rsurface.texcoordlightmap2f_bufferobject = rsurface.modeltexcoordlightmap2f_bufferobject;
4819 rsurface.texcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
4820 R_Mesh_VertexPointer(rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
4823 void RSurf_DrawBatch_Simple(int texturenumsurfaces, msurface_t **texturesurfacelist)
4826 const msurface_t *surface = texturesurfacelist[0];
4827 const msurface_t *surface2;
4832 // TODO: lock all array ranges before render, rather than on each surface
4833 if (texturenumsurfaces == 1)
4835 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
4836 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface.modelelement3i + 3 * surface->num_firsttriangle), rsurface.modelelement3i_bufferobject, (sizeof(int[3]) * surface->num_firsttriangle));
4838 else if (r_batchmode.integer == 2)
4840 #define MAXBATCHTRIANGLES 4096
4841 int batchtriangles = 0;
4842 int batchelements[MAXBATCHTRIANGLES*3];
4843 for (i = 0;i < texturenumsurfaces;i = j)
4845 surface = texturesurfacelist[i];
4847 if (surface->num_triangles > MAXBATCHTRIANGLES)
4849 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface.modelelement3i + 3 * surface->num_firsttriangle), rsurface.modelelement3i_bufferobject, (sizeof(int[3]) * surface->num_firsttriangle));
4852 memcpy(batchelements, rsurface.modelelement3i + 3 * surface->num_firsttriangle, surface->num_triangles * sizeof(int[3]));
4853 batchtriangles = surface->num_triangles;
4854 firstvertex = surface->num_firstvertex;
4855 endvertex = surface->num_firstvertex + surface->num_vertices;
4856 for (;j < texturenumsurfaces;j++)
4858 surface2 = texturesurfacelist[j];
4859 if (batchtriangles + surface2->num_triangles > MAXBATCHTRIANGLES)
4861 memcpy(batchelements + batchtriangles * 3, rsurface.modelelement3i + 3 * surface2->num_firsttriangle, surface2->num_triangles * sizeof(int[3]));
4862 batchtriangles += surface2->num_triangles;
4863 firstvertex = min(firstvertex, surface2->num_firstvertex);
4864 endvertex = max(endvertex, surface2->num_firstvertex + surface2->num_vertices);
4866 surface2 = texturesurfacelist[j-1];
4867 numvertices = endvertex - firstvertex;
4868 R_Mesh_Draw(firstvertex, numvertices, batchtriangles, batchelements, 0, 0);
4871 else if (r_batchmode.integer == 1)
4873 for (i = 0;i < texturenumsurfaces;i = j)
4875 surface = texturesurfacelist[i];
4876 for (j = i + 1, surface2 = surface + 1;j < texturenumsurfaces;j++, surface2++)
4877 if (texturesurfacelist[j] != surface2)
4879 surface2 = texturesurfacelist[j-1];
4880 numvertices = surface2->num_firstvertex + surface2->num_vertices - surface->num_firstvertex;
4881 numtriangles = surface2->num_firsttriangle + surface2->num_triangles - surface->num_firsttriangle;
4882 GL_LockArrays(surface->num_firstvertex, numvertices);
4883 R_Mesh_Draw(surface->num_firstvertex, numvertices, numtriangles, (rsurface.modelelement3i + 3 * surface->num_firsttriangle), rsurface.modelelement3i_bufferobject, (sizeof(int[3]) * surface->num_firsttriangle));
4888 for (i = 0;i < texturenumsurfaces;i++)
4890 surface = texturesurfacelist[i];
4891 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
4892 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface.modelelement3i + 3 * surface->num_firsttriangle), rsurface.modelelement3i_bufferobject, (sizeof(int[3]) * surface->num_firsttriangle));
4897 static void RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(int texturenumsurfaces, msurface_t **texturesurfacelist, int lightmaptexunit, int deluxemaptexunit, int refractiontexunit, int reflectiontexunit)
4899 int i, planeindex, vertexindex;
4903 r_waterstate_waterplane_t *p, *bestp;
4904 msurface_t *surface;
4905 if (r_waterstate.renderingscene)
4907 for (i = 0;i < texturenumsurfaces;i++)
4909 surface = texturesurfacelist[i];
4910 if (lightmaptexunit >= 0)
4911 R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
4912 if (deluxemaptexunit >= 0)
4913 R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
4914 // pick the closest matching water plane
4917 for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++)
4920 for (vertexindex = 0, v = rsurface.modelvertex3f + surface->num_firstvertex * 3;vertexindex < surface->num_vertices;vertexindex++, v += 3)
4922 Matrix4x4_Transform(&rsurface.matrix, v, vert);
4923 d += fabs(PlaneDiff(vert, &p->plane));
4925 if (bestd > d || !bestp)
4933 if (refractiontexunit >= 0)
4934 R_Mesh_TexBind(refractiontexunit, R_GetTexture(bestp->texture_refraction));
4935 if (reflectiontexunit >= 0)
4936 R_Mesh_TexBind(reflectiontexunit, R_GetTexture(bestp->texture_reflection));
4940 if (refractiontexunit >= 0)
4941 R_Mesh_TexBind(refractiontexunit, R_GetTexture(r_texture_black));
4942 if (reflectiontexunit >= 0)
4943 R_Mesh_TexBind(reflectiontexunit, R_GetTexture(r_texture_black));
4945 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
4946 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface.modelelement3i + 3 * surface->num_firsttriangle), rsurface.modelelement3i_bufferobject, (sizeof(int[3]) * surface->num_firsttriangle));
4950 static void RSurf_DrawBatch_WithLightmapSwitching(int texturenumsurfaces, msurface_t **texturesurfacelist, int lightmaptexunit, int deluxemaptexunit)
4954 const msurface_t *surface = texturesurfacelist[0];
4955 const msurface_t *surface2;
4960 // TODO: lock all array ranges before render, rather than on each surface
4961 if (texturenumsurfaces == 1)
4963 R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
4964 if (deluxemaptexunit >= 0)
4965 R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
4966 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
4967 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface.modelelement3i + 3 * surface->num_firsttriangle), rsurface.modelelement3i_bufferobject, (sizeof(int[3]) * surface->num_firsttriangle));
4969 else if (r_batchmode.integer == 2)
4971 #define MAXBATCHTRIANGLES 4096
4972 int batchtriangles = 0;
4973 int batchelements[MAXBATCHTRIANGLES*3];
4974 for (i = 0;i < texturenumsurfaces;i = j)
4976 surface = texturesurfacelist[i];
4977 R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
4978 if (deluxemaptexunit >= 0)
4979 R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
4981 if (surface->num_triangles > MAXBATCHTRIANGLES)
4983 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface.modelelement3i + 3 * surface->num_firsttriangle), rsurface.modelelement3i_bufferobject, (sizeof(int[3]) * surface->num_firsttriangle));
4986 memcpy(batchelements, rsurface.modelelement3i + 3 * surface->num_firsttriangle, surface->num_triangles * sizeof(int[3]));
4987 batchtriangles = surface->num_triangles;
4988 firstvertex = surface->num_firstvertex;
4989 endvertex = surface->num_firstvertex + surface->num_vertices;
4990 for (;j < texturenumsurfaces;j++)
4992 surface2 = texturesurfacelist[j];
4993 if (surface2->lightmaptexture != surface->lightmaptexture || batchtriangles + surface2->num_triangles > MAXBATCHTRIANGLES)
4995 memcpy(batchelements + batchtriangles * 3, rsurface.modelelement3i + 3 * surface2->num_firsttriangle, surface2->num_triangles * sizeof(int[3]));
4996 batchtriangles += surface2->num_triangles;
4997 firstvertex = min(firstvertex, surface2->num_firstvertex);
4998 endvertex = max(endvertex, surface2->num_firstvertex + surface2->num_vertices);
5000 surface2 = texturesurfacelist[j-1];
5001 numvertices = endvertex - firstvertex;
5002 R_Mesh_Draw(firstvertex, numvertices, batchtriangles, batchelements, 0, 0);
5005 else if (r_batchmode.integer == 1)
5008 Con_Printf("%s batch sizes ignoring lightmap:", rsurface.texture->name);
5009 for (i = 0;i < texturenumsurfaces;i = j)
5011 surface = texturesurfacelist[i];
5012 for (j = i + 1, surface2 = surface + 1;j < texturenumsurfaces;j++, surface2++)
5013 if (texturesurfacelist[j] != surface2)
5015 Con_Printf(" %i", j - i);
5018 Con_Printf("%s batch sizes honoring lightmap:", rsurface.texture->name);
5020 for (i = 0;i < texturenumsurfaces;i = j)
5022 surface = texturesurfacelist[i];
5023 R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
5024 if (deluxemaptexunit >= 0)
5025 R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
5026 for (j = i + 1, surface2 = surface + 1;j < texturenumsurfaces;j++, surface2++)
5027 if (texturesurfacelist[j] != surface2 || texturesurfacelist[j]->lightmaptexture != surface->lightmaptexture)
5030 Con_Printf(" %i", j - i);
5032 surface2 = texturesurfacelist[j-1];
5033 numvertices = surface2->num_firstvertex + surface2->num_vertices - surface->num_firstvertex;
5034 numtriangles = surface2->num_firsttriangle + surface2->num_triangles - surface->num_firsttriangle;
5035 GL_LockArrays(surface->num_firstvertex, numvertices);
5036 R_Mesh_Draw(surface->num_firstvertex, numvertices, numtriangles, (rsurface.modelelement3i + 3 * surface->num_firsttriangle), rsurface.modelelement3i_bufferobject, (sizeof(int[3]) * surface->num_firsttriangle));
5044 for (i = 0;i < texturenumsurfaces;i++)
5046 surface = texturesurfacelist[i];
5047 R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
5048 if (deluxemaptexunit >= 0)
5049 R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
5050 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
5051 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface.modelelement3i + 3 * surface->num_firsttriangle), rsurface.modelelement3i_bufferobject, (sizeof(int[3]) * surface->num_firsttriangle));
5056 static void RSurf_DrawBatch_ShowSurfaces(int texturenumsurfaces, msurface_t **texturesurfacelist)
5059 int texturesurfaceindex;
5060 if (r_showsurfaces.integer == 2)
5062 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
5064 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
5065 for (j = 0;j < surface->num_triangles;j++)
5067 float f = ((j + surface->num_firsttriangle) & 31) * (1.0f / 31.0f) * r_view.colorscale;
5068 GL_Color(f, f, f, 1);
5069 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, 1, (rsurface.modelelement3i + 3 * (j + surface->num_firsttriangle)), rsurface.modelelement3i_bufferobject, (sizeof(int[3]) * (j + surface->num_firsttriangle)));
5075 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
5077 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
5078 int k = (int)(((size_t)surface) / sizeof(msurface_t));
5079 GL_Color((k & 15) * (1.0f / 16.0f) * r_view.colorscale, ((k >> 4) & 15) * (1.0f / 16.0f) * r_view.colorscale, ((k >> 8) & 15) * (1.0f / 16.0f) * r_view.colorscale, 1);
5080 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
5081 R_Mesh_Draw(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, (rsurface.modelelement3i + 3 * surface->num_firsttriangle), rsurface.modelelement3i_bufferobject, (sizeof(int[3]) * surface->num_firsttriangle));
5086 static void RSurf_DrawBatch_GL11_ApplyFog(int texturenumsurfaces, msurface_t **texturesurfacelist)
5088 int texturesurfaceindex;
5092 if (rsurface.lightmapcolor4f)
5094 // generate color arrays for the surfaces in this list
5095 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
5097 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
5098 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)
5100 f = FogPoint_Model(v);
5110 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
5112 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
5113 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)
5115 f = FogPoint_Model(v);
5123 rsurface.lightmapcolor4f = rsurface.array_color4f;
5124 rsurface.lightmapcolor4f_bufferobject = 0;
5125 rsurface.lightmapcolor4f_bufferoffset = 0;
5128 static void RSurf_DrawBatch_GL11_ApplyColor(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a)
5130 int texturesurfaceindex;
5133 if (!rsurface.lightmapcolor4f)
5135 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
5137 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
5138 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)
5146 rsurface.lightmapcolor4f = rsurface.array_color4f;
5147 rsurface.lightmapcolor4f_bufferobject = 0;
5148 rsurface.lightmapcolor4f_bufferoffset = 0;
5151 static void RSurf_DrawBatch_GL11_Lightmap(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
5154 rsurface.lightmapcolor4f = NULL;
5155 rsurface.lightmapcolor4f_bufferobject = 0;
5156 rsurface.lightmapcolor4f_bufferoffset = 0;
5157 if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
5158 if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
5159 R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
5160 GL_Color(r, g, b, a);
5161 RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist, 0, -1);
5164 static void RSurf_DrawBatch_GL11_Unlit(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
5166 // TODO: optimize applyfog && applycolor case
5167 // just apply fog if necessary, and tint the fog color array if necessary
5168 rsurface.lightmapcolor4f = NULL;
5169 rsurface.lightmapcolor4f_bufferobject = 0;
5170 rsurface.lightmapcolor4f_bufferoffset = 0;
5171 if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
5172 if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
5173 R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
5174 GL_Color(r, g, b, a);
5175 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
5178 static void RSurf_DrawBatch_GL11_VertexColor(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
5180 int texturesurfaceindex;
5184 if (texturesurfacelist[0]->lightmapinfo && texturesurfacelist[0]->lightmapinfo->stainsamples)
5186 // generate color arrays for the surfaces in this list
5187 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
5189 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
5190 for (i = 0, c = rsurface.array_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
5192 if (surface->lightmapinfo->samples)
5194 const unsigned char *lm = surface->lightmapinfo->samples + (rsurface.modellightmapoffsets + surface->num_firstvertex)[i];
5195 float scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[0]] * (1.0f / 32768.0f);
5196 VectorScale(lm, scale, c);
5197 if (surface->lightmapinfo->styles[1] != 255)
5199 int size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
5201 scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[1]] * (1.0f / 32768.0f);
5202 VectorMA(c, scale, lm, c);
5203 if (surface->lightmapinfo->styles[2] != 255)
5206 scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[2]] * (1.0f / 32768.0f);
5207 VectorMA(c, scale, lm, c);
5208 if (surface->lightmapinfo->styles[3] != 255)
5211 scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[3]] * (1.0f / 32768.0f);
5212 VectorMA(c, scale, lm, c);
5222 rsurface.lightmapcolor4f = rsurface.array_color4f;
5223 rsurface.lightmapcolor4f_bufferobject = 0;
5224 rsurface.lightmapcolor4f_bufferoffset = 0;
5228 rsurface.lightmapcolor4f = rsurface.modellightmapcolor4f;
5229 rsurface.lightmapcolor4f_bufferobject = rsurface.modellightmapcolor4f_bufferobject;
5230 rsurface.lightmapcolor4f_bufferoffset = rsurface.modellightmapcolor4f_bufferoffset;
5232 if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
5233 if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
5234 R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
5235 GL_Color(r, g, b, a);
5236 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
5239 static void RSurf_DrawBatch_GL11_VertexShade(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
5241 int texturesurfaceindex;
5245 vec3_t ambientcolor;
5246 vec3_t diffusecolor;
5250 VectorCopy(rsurface.modellight_lightdir, lightdir);
5251 ambientcolor[0] = rsurface.modellight_ambient[0] * r * 0.5f;
5252 ambientcolor[1] = rsurface.modellight_ambient[1] * g * 0.5f;
5253 ambientcolor[2] = rsurface.modellight_ambient[2] * b * 0.5f;
5254 diffusecolor[0] = rsurface.modellight_diffuse[0] * r * 0.5f;
5255 diffusecolor[1] = rsurface.modellight_diffuse[1] * g * 0.5f;
5256 diffusecolor[2] = rsurface.modellight_diffuse[2] * b * 0.5f;
5257 if (VectorLength2(diffusecolor) > 0)
5259 // generate color arrays for the surfaces in this list
5260 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
5262 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
5263 int numverts = surface->num_vertices;
5264 v = rsurface.vertex3f + 3 * surface->num_firstvertex;
5265 c2 = rsurface.normal3f + 3 * surface->num_firstvertex;
5266 c = rsurface.array_color4f + 4 * surface->num_firstvertex;
5267 // q3-style directional shading
5268 for (i = 0;i < numverts;i++, v += 3, c2 += 3, c += 4)
5270 if ((f = DotProduct(c2, lightdir)) > 0)
5271 VectorMA(ambientcolor, f, diffusecolor, c);
5273 VectorCopy(ambientcolor, c);
5282 rsurface.lightmapcolor4f = rsurface.array_color4f;
5283 rsurface.lightmapcolor4f_bufferobject = 0;
5284 rsurface.lightmapcolor4f_bufferoffset = 0;
5288 r = ambientcolor[0];
5289 g = ambientcolor[1];
5290 b = ambientcolor[2];
5291 rsurface.lightmapcolor4f = NULL;
5292 rsurface.lightmapcolor4f_bufferobject = 0;
5293 rsurface.lightmapcolor4f_bufferoffset = 0;
5295 if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
5296 if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
5297 R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
5298 GL_Color(r, g, b, a);
5299 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
5303 static void RSurf_GL11_WaterTexCoords(int texturenumsurfaces, msurface_t **texturesurfacelist)
5305 int texturesurfaceindex;
5306 const msurface_t *surface;
5307 // compute texcoords for vertices (yes, these swim around the screen a bit unintentionally)
5308 // compute vertex alpha to fade between reflection and refraction if this is water
5309 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
5311 surface = texturesurfacelist[texturesurfaceindex];
5312 GL_TransformToScreenTexCoords(surface->num_vertices, rsurface.vertex3f + 3 * surface->num_firstvertex, rsurface.array_generatedtexcoordtexture2f + 2 * surface->num_firstvertex, r_waterstate.screenscale[0], r_waterstate.screenscale[1], r_waterstate.screencenter[0], r_waterstate.screencenter[1]);
5316 static void RSurf_GL11_WaterFresnelAlpha(int texturenumsurfaces, msurface_t **texturesurfacelist)
5318 int texturesurfaceindex;
5320 const msurface_t *surface;
5327 // compute texcoords for vertices (yes, these swim around the screen a bit unintentionally)
5328 // compute vertex alpha to fade between reflection and refraction if this is water
5329 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
5331 surface = texturesurfacelist[texturesurfaceindex];
5332 numverts = surface->num_vertices;
5333 v = rsurface.vertex3f + 3 * surface->num_firstvertex;
5334 n = rsurface.normal3f + 3 * surface->num_firstvertex;
5335 c2 = rsurface.array_color4f + 4 * surface->num_firstvertex;
5336 for (i = 0;i < numverts;i++, v += 3, n += 3, c2 += 4)
5338 VectorSubtract(rsurface.modelorg, v, dir);
5339 VectorNormalize(dir);
5340 Fresnel = pow(min(1.0f, 1.0f - DotProduct(dir, n)), 2.0f) * (rsurface.texture->reflectmax - rsurface.texture->reflectmin) + rsurface.texture->reflectmin;
5341 Vector4Set(c2, 1, 1, 1, Fresnel);
5346 static void R_DrawTextureSurfaceList_GL11_Water(int texturenumsurfaces, msurface_t **texturesurfacelist)
5348 // OpenGL 1.1 path - crusty old voodoo path
5351 if (rsurface.mode != RSURFMODE_MULTIPASS)
5352 rsurface.mode = RSURFMODE_MULTIPASS;
5353 RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist);
5354 R_Mesh_ColorPointer(NULL, 0, 0);
5355 water = (rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERSHADER) != 0;
5356 RSurf_GL11_WaterTexCoords(texturenumsurfaces, texturesurfacelist);
5358 RSurf_GL11_WaterFresnelAlpha(texturenumsurfaces, texturesurfacelist);
5359 // now draw the surfaces as refraction texture
5360 memset(&m, 0, sizeof(m));
5361 m.tex[0] = R_GetTexture(r_texture_white);
5362 m.pointer_texcoord[0] = rsurface.array_generatedtexcoordtexture2f;
5363 R_Mesh_TextureState(&m);
5364 RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(texturenumsurfaces, texturesurfacelist, -1, -1, 0, -1);
5367 // water also reflects before the normal render occurs, and uses a
5368 // vertex-controlled alpha blend between refraction and reflection
5369 GL_LockArrays(0, 0);
5370 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
5371 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5372 GL_DepthMask(false);
5373 RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(texturenumsurfaces, texturesurfacelist, -1, -1, -1, 0);
5375 GL_LockArrays(0, 0);
5379 static void R_DrawTextureSurfaceList_GL11_Reflection(int texturenumsurfaces, msurface_t **texturesurfacelist)
5381 // OpenGL 1.1 path - crusty old voodoo path
5384 if (rsurface.mode != RSURFMODE_MULTIPASS)
5385 rsurface.mode = RSURFMODE_MULTIPASS;
5386 RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist);
5387 R_Mesh_ColorPointer(NULL, 0, 0);
5388 water = (rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERSHADER) != 0;
5389 RSurf_GL11_WaterTexCoords(texturenumsurfaces, texturesurfacelist);
5390 // now draw the surfaces as refraction texture
5391 memset(&m, 0, sizeof(m));
5392 m.tex[0] = R_GetTexture(r_texture_white);
5393 m.pointer_texcoord[0] = rsurface.array_generatedtexcoordtexture2f;
5394 R_Mesh_TextureState(&m);
5395 RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(texturenumsurfaces, texturesurfacelist, -1, -1, -1, 0);
5396 GL_LockArrays(0, 0);
5401 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, msurface_t **texturesurfacelist)
5403 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
5404 GL_PolygonOffset(rsurface.texture->currentpolygonfactor, rsurface.texture->currentpolygonoffset);
5405 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
5406 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_view.cullface_back);
5407 if (rsurface.mode != RSURFMODE_SHOWSURFACES)
5409 rsurface.mode = RSURFMODE_SHOWSURFACES;
5411 GL_BlendFunc(GL_ONE, GL_ZERO);
5412 R_Mesh_ColorPointer(NULL, 0, 0);
5413 R_Mesh_ResetTextureState();
5415 RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
5416 RSurf_DrawBatch_ShowSurfaces(texturenumsurfaces, texturesurfacelist);
5419 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, msurface_t **texturesurfacelist)
5421 // transparent sky would be ridiculous
5422 if ((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED))
5424 if (rsurface.mode != RSURFMODE_SKY)
5426 if (rsurface.mode == RSURFMODE_GLSL)
5428 qglUseProgramObjectARB(0);CHECKGLERROR
5430 rsurface.mode = RSURFMODE_SKY;
5434 skyrendernow = false;
5436 // restore entity matrix
5437 R_Mesh_Matrix(&rsurface.matrix);
5439 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
5440 GL_PolygonOffset(rsurface.texture->currentpolygonfactor, rsurface.texture->currentpolygonoffset);
5441 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
5442 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_view.cullface_back);
5444 // LordHavoc: HalfLife maps have freaky skypolys so don't use
5445 // skymasking on them, and Quake3 never did sky masking (unlike
5446 // software Quake and software Quake2), so disable the sky masking
5447 // in Quake3 maps as it causes problems with q3map2 sky tricks,
5448 // and skymasking also looks very bad when noclipping outside the
5449 // level, so don't use it then either.
5450 if (r_refdef.worldmodel && r_refdef.worldmodel->type == mod_brushq1 && r_q1bsp_skymasking.integer && !r_viewcache.world_novis)
5452 GL_Color(r_refdef.fogcolor[0] * r_view.colorscale, r_refdef.fogcolor[1] * r_view.colorscale, r_refdef.fogcolor[2] * r_view.colorscale, 1);
5453 R_Mesh_ColorPointer(NULL, 0, 0);
5454 R_Mesh_ResetTextureState();
5455 if (skyrendermasked)
5457 // depth-only (masking)
5458 GL_ColorMask(0,0,0,0);
5459 // just to make sure that braindead drivers don't draw
5460 // anything despite that colormask...
5461 GL_BlendFunc(GL_ZERO, GL_ONE);
5466 GL_BlendFunc(GL_ONE, GL_ZERO);
5468 RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
5469 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
5470 if (skyrendermasked)
5471 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
5475 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, msurface_t **texturesurfacelist)
5477 if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION)))
5480 if (rsurface.mode != RSURFMODE_GLSL)
5482 rsurface.mode = RSURFMODE_GLSL;
5483 R_Mesh_ResetTextureState();
5486 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
5487 R_Mesh_TexBind(0, R_GetTexture(rsurface.texture->currentskinframe->nmap));
5488 R_Mesh_TexBind(1, R_GetTexture(rsurface.texture->basetexture));
5489 R_Mesh_TexBind(2, R_GetTexture(rsurface.texture->glosstexture));
5490 R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation));
5491 R_Mesh_TexBind(5, R_GetTexture(rsurface.texture->currentskinframe->pants));
5492 R_Mesh_TexBind(6, R_GetTexture(rsurface.texture->currentskinframe->shirt));
5493 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
5495 R_Mesh_TexBind(7, R_GetTexture(r_texture_grey128));
5496 R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
5497 R_Mesh_ColorPointer(NULL, 0, 0);
5499 else if (rsurface.uselightmaptexture)
5501 R_Mesh_TexBind(7, R_GetTexture(texturesurfacelist[0]->lightmaptexture));
5502 R_Mesh_TexBind(8, R_GetTexture(texturesurfacelist[0]->deluxemaptexture));
5503 R_Mesh_ColorPointer(NULL, 0, 0);
5507 R_Mesh_TexBind(7, R_GetTexture(r_texture_white));
5508 R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
5509 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
5511 R_Mesh_TexBind(9, R_GetTexture(rsurface.texture->currentskinframe->glow));
5512 R_Mesh_TexBind(11, R_GetTexture(r_texture_white)); // changed per surface
5513 R_Mesh_TexBind(12, R_GetTexture(r_texture_white)); // changed per surface
5515 if (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
5517 // render background
5518 GL_BlendFunc(GL_ONE, GL_ZERO);
5520 GL_AlphaTest(false);
5522 GL_Color(1, 1, 1, 1);
5523 R_Mesh_ColorPointer(NULL, 0, 0);
5525 R_SetupSurfaceShader(vec3_origin, rsurface.lightmode == 2, 1, 1, rsurface.texture->specularscale, RSURFPASS_BACKGROUND);
5526 if (r_glsl_permutation)
5528 RSurf_PrepareVerticesForBatch(true, true, texturenumsurfaces, texturesurfacelist);
5529 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
5530 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
5531 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
5532 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
5533 R_Mesh_TexCoordPointer(4, 2, rsurface.modeltexcoordlightmap2f, rsurface.modeltexcoordlightmap2f_bufferobject, rsurface.modeltexcoordlightmap2f_bufferoffset);
5534 RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(texturenumsurfaces, texturesurfacelist, -1, -1, r_glsl_permutation->loc_Texture_Refraction ? 11 : -1, r_glsl_permutation->loc_Texture_Reflection ? 12 : -1);
5537 GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
5538 GL_DepthMask(false);
5539 GL_AlphaTest((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
5540 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
5542 R_Mesh_TexBind(7, R_GetTexture(r_texture_grey128));
5543 R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
5544 R_Mesh_ColorPointer(NULL, 0, 0);
5546 else if (rsurface.uselightmaptexture)
5548 R_Mesh_TexBind(7, R_GetTexture(texturesurfacelist[0]->lightmaptexture));
5549 R_Mesh_TexBind(8, R_GetTexture(texturesurfacelist[0]->deluxemaptexture));
5550 R_Mesh_ColorPointer(NULL, 0, 0);
5554 R_Mesh_TexBind(7, R_GetTexture(r_texture_white));
5555 R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
5556 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
5558 R_Mesh_TexBind(11, R_GetTexture(r_texture_white)); // changed per surface
5559 R_Mesh_TexBind(12, R_GetTexture(r_texture_white)); // changed per surface
5562 R_SetupSurfaceShader(vec3_origin, rsurface.lightmode == 2, 1, 1, rsurface.texture->specularscale, RSURFPASS_BASE);
5563 if (!r_glsl_permutation)
5566 if (rsurface.lightmode == 2)
5567 RSurf_PrepareVerticesForBatch(true, r_glsl_permutation->loc_Texture_Normal >= 0, texturenumsurfaces, texturesurfacelist);
5569 RSurf_PrepareVerticesForBatch(r_glsl_permutation->loc_Texture_Normal >= 0, r_glsl_permutation->loc_Texture_Normal >= 0, texturenumsurfaces, texturesurfacelist);
5570 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
5571 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
5572 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
5573 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
5574 R_Mesh_TexCoordPointer(4, 2, rsurface.modeltexcoordlightmap2f, rsurface.modeltexcoordlightmap2f_bufferobject, rsurface.modeltexcoordlightmap2f_bufferoffset);
5575 GL_Color(rsurface.texture->currentlayers[0].color[0], rsurface.texture->currentlayers[0].color[1], rsurface.texture->currentlayers[0].color[2], rsurface.texture->currentlayers[0].color[3]);
5577 if (r_glsl_permutation->loc_Texture_Refraction >= 0)
5579 GL_BlendFunc(GL_ONE, GL_ZERO);
5581 GL_AlphaTest(false);
5584 if (rsurface.uselightmaptexture && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT))
5586 if (r_glsl_permutation->loc_Texture_Refraction >= 0 || r_glsl_permutation->loc_Texture_Reflection >= 0)
5587 RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(texturenumsurfaces, texturesurfacelist, 7, r_glsl_permutation->loc_Texture_Deluxemap >= 0 ? 8 : -1, r_glsl_permutation->loc_Texture_Refraction >= 0 ? 11 : -1, r_glsl_permutation->loc_Texture_Reflection >= 0 ? 12 : -1);
5589 RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist, 7, r_glsl_permutation->loc_Texture_Deluxemap >= 0 ? 8 : -1);
5593 if (r_glsl_permutation->loc_Texture_Refraction >= 0 || r_glsl_permutation->loc_Texture_Reflection >= 0)
5594 RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(texturenumsurfaces, texturesurfacelist, -1, -1, r_glsl_permutation->loc_Texture_Refraction >= 0 ? 11 : -1, r_glsl_permutation->loc_Texture_Reflection >= 0 ? 12 : -1);
5596 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
5598 if (rsurface.texture->backgroundnumskinframes && !(rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED))
5603 static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, msurface_t **texturesurfacelist)
5605 // OpenGL 1.3 path - anything not completely ancient
5606 int texturesurfaceindex;
5607 qboolean applycolor;
5611 const texturelayer_t *layer;
5612 if (rsurface.mode != RSURFMODE_MULTIPASS)
5613 rsurface.mode = RSURFMODE_MULTIPASS;
5614 RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist);
5617 if (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
5619 // render background
5620 GL_BlendFunc(GL_ONE, GL_ZERO);
5622 GL_AlphaTest(false);
5623 R_DrawTextureSurfaceList_GL11_Water(texturenumsurfaces, texturesurfacelist);
5627 for (layerindex = 0, layer = rsurface.texture->currentlayers;layerindex < rsurface.texture->currentnumlayers;layerindex++, layer++)
5630 int layertexrgbscale;
5631 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
5633 if (layerindex == 0)
5637 GL_AlphaTest(false);
5638 qglDepthFunc(GL_EQUAL);CHECKGLERROR
5641 GL_DepthMask(layer->depthmask);
5642 GL_BlendFunc(layer->blendfunc1, layer->blendfunc2);
5643 if ((layer->color[0] > 2 || layer->color[1] > 2 || layer->color[2] > 2) && (gl_combine.integer || layer->depthmask))
5645 layertexrgbscale = 4;
5646 VectorScale(layer->color, 0.25f, layercolor);
5648 else if ((layer->color[0] > 1 || layer->color[1] > 1 || layer->color[2] > 1) && (gl_combine.integer || layer->depthmask))
5650 layertexrgbscale = 2;
5651 VectorScale(layer->color, 0.5f, layercolor);
5655 layertexrgbscale = 1;
5656 VectorScale(layer->color, 1.0f, layercolor);
5658 layercolor[3] = layer->color[3];
5659 applycolor = layercolor[0] != 1 || layercolor[1] != 1 || layercolor[2] != 1 || layercolor[3] != 1;
5660 R_Mesh_ColorPointer(NULL, 0, 0);
5661 applyfog = (layer->flags & TEXTURELAYERFLAG_FOGDARKEN) != 0;
5662 switch (layer->type)
5664 case TEXTURELAYERTYPE_LITTEXTURE:
5665 memset(&m, 0, sizeof(m));
5666 m.tex[0] = R_GetTexture(r_texture_white);
5667 m.pointer_texcoord[0] = rsurface.modeltexcoordlightmap2f;
5668 m.pointer_texcoord_bufferobject[0] = rsurface.modeltexcoordlightmap2f_bufferobject;
5669 m.pointer_texcoord_bufferoffset[0] = rsurface.modeltexcoordlightmap2f_bufferoffset;
5670 m.tex[1] = R_GetTexture(layer->texture);
5671 m.texmatrix[1] = layer->texmatrix;
5672 m.texrgbscale[1] = layertexrgbscale;
5673 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
5674 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
5675 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
5676 R_Mesh_TextureState(&m);
5677 if (rsurface.lightmode == 2)
5678 RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
5679 else if (rsurface.uselightmaptexture)
5680 RSurf_DrawBatch_GL11_Lightmap(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
5682 RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
5684 case TEXTURELAYERTYPE_TEXTURE:
5685 memset(&m, 0, sizeof(m));
5686 m.tex[0] = R_GetTexture(layer->texture);
5687 m.texmatrix[0] = layer->texmatrix;
5688 m.texrgbscale[0] = layertexrgbscale;
5689 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
5690 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
5691 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
5692 R_Mesh_TextureState(&m);
5693 RSurf_DrawBatch_GL11_Unlit(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
5695 case TEXTURELAYERTYPE_FOG:
5696 memset(&m, 0, sizeof(m));
5697 m.texrgbscale[0] = layertexrgbscale;
5700 m.tex[0] = R_GetTexture(layer->texture);
5701 m.texmatrix[0] = layer->texmatrix;
5702 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
5703 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
5704 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
5706 R_Mesh_TextureState(&m);
5707 // generate a color array for the fog pass
5708 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
5709 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
5713 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
5714 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)
5716 f = 1 - FogPoint_Model(v);
5717 c[0] = layercolor[0];
5718 c[1] = layercolor[1];
5719 c[2] = layercolor[2];
5720 c[3] = f * layercolor[3];
5723 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
5726 Con_Printf("R_DrawTextureSurfaceList: unknown layer type %i\n", layer->type);
5728 GL_LockArrays(0, 0);
5731 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
5733 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
5734 GL_AlphaTest(false);
5738 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
5740 GL_BlendFunc(GL_ONE, GL_ONE);
5741 GL_DepthMask(false);
5742 R_DrawTextureSurfaceList_GL11_Reflection(texturenumsurfaces, texturesurfacelist);
5747 static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, msurface_t **texturesurfacelist)
5749 // OpenGL 1.1 - crusty old voodoo path
5750 int texturesurfaceindex;
5754 const texturelayer_t *layer;
5755 if (rsurface.mode != RSURFMODE_MULTIPASS)
5756 rsurface.mode = RSURFMODE_MULTIPASS;
5757 RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist);
5760 if (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
5762 // render background
5763 GL_BlendFunc(GL_ONE, GL_ZERO);
5765 GL_AlphaTest(false);
5766 R_DrawTextureSurfaceList_GL11_Water(texturenumsurfaces, texturesurfacelist);
5770 for (layerindex = 0, layer = rsurface.texture->currentlayers;layerindex < rsurface.texture->currentnumlayers;layerindex++, layer++)
5772 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
5774 if (layerindex == 0)
5778 GL_AlphaTest(false);
5779 qglDepthFunc(GL_EQUAL);CHECKGLERROR
5782 GL_DepthMask(layer->depthmask);
5783 GL_BlendFunc(layer->blendfunc1, layer->blendfunc2);
5784 R_Mesh_ColorPointer(NULL, 0, 0);
5785 applyfog = (layer->flags & TEXTURELAYERFLAG_FOGDARKEN) != 0;
5786 switch (layer->type)
5788 case TEXTURELAYERTYPE_LITTEXTURE:
5789 if (layer->blendfunc1 == GL_ONE && layer->blendfunc2 == GL_ZERO)
5791 // two-pass lit texture with 2x rgbscale
5792 // first the lightmap pass
5793 memset(&m, 0, sizeof(m));
5794 m.tex[0] = R_GetTexture(r_texture_white);
5795 m.pointer_texcoord[0] = rsurface.modeltexcoordlightmap2f;
5796 m.pointer_texcoord_bufferobject[0] = rsurface.modeltexcoordlightmap2f_bufferobject;
5797 m.pointer_texcoord_bufferoffset[0] = rsurface.modeltexcoordlightmap2f_bufferoffset;
5798 R_Mesh_TextureState(&m);
5799 if (rsurface.lightmode == 2)
5800 RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
5801 else if (rsurface.uselightmaptexture)
5802 RSurf_DrawBatch_GL11_Lightmap(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
5804 RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
5805 GL_LockArrays(0, 0);
5806 // then apply the texture to it
5807 GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
5808 memset(&m, 0, sizeof(m));
5809 m.tex[0] = R_GetTexture(layer->texture);
5810 m.texmatrix[0] = layer->texmatrix;
5811 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
5812 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
5813 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
5814 R_Mesh_TextureState(&m);
5815 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);
5819 // single pass vertex-lighting-only texture with 1x rgbscale and transparency support
5820 memset(&m, 0, sizeof(m));
5821 m.tex[0] = R_GetTexture(layer->texture);
5822 m.texmatrix[0] = layer->texmatrix;
5823 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
5824 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
5825 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
5826 R_Mesh_TextureState(&m);
5827 if (rsurface.lightmode == 2)
5828 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);
5830 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);
5833 case TEXTURELAYERTYPE_TEXTURE:
5834 // singletexture unlit texture with transparency support
5835 memset(&m, 0, sizeof(m));
5836 m.tex[0] = R_GetTexture(layer->texture);
5837 m.texmatrix[0] = layer->texmatrix;
5838 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
5839 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
5840 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
5841 R_Mesh_TextureState(&m);
5842 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);
5844 case TEXTURELAYERTYPE_FOG:
5845 // singletexture fogging
5846 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
5849 memset(&m, 0, sizeof(m));
5850 m.tex[0] = R_GetTexture(layer->texture);
5851 m.texmatrix[0] = layer->texmatrix;
5852 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
5853 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
5854 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
5855 R_Mesh_TextureState(&m);
5858 R_Mesh_ResetTextureState();
5859 // generate a color array for the fog pass
5860 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
5864 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
5865 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)
5867 f = 1 - FogPoint_Model(v);
5868 c[0] = layer->color[0];
5869 c[1] = layer->color[1];
5870 c[2] = layer->color[2];
5871 c[3] = f * layer->color[3];
5874 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
5877 Con_Printf("R_DrawTextureSurfaceList: unknown layer type %i\n", layer->type);
5879 GL_LockArrays(0, 0);
5882 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
5884 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
5885 GL_AlphaTest(false);
5889 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
5891 GL_BlendFunc(GL_ONE, GL_ONE);
5892 GL_DepthMask(false);
5893 R_DrawTextureSurfaceList_GL11_Reflection(texturenumsurfaces, texturesurfacelist);
5898 static void R_DrawTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly)
5900 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW)
5902 rsurface.rtlight = NULL;
5906 if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
5908 if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
5910 if (rsurface.mode != RSURFMODE_MULTIPASS)
5911 rsurface.mode = RSURFMODE_MULTIPASS;
5912 if (r_depthfirst.integer == 3)
5914 int i = (int)(texturesurfacelist[0] - rsurface.modelsurfaces);
5915 if (!r_view.showdebug)
5916 GL_Color(0, 0, 0, 1);
5918 GL_Color(((i >> 6) & 7) / 7.0f, ((i >> 3) & 7) / 7.0f, (i & 7) / 7.0f,1);
5922 GL_ColorMask(0,0,0,0);
5925 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
5926 GL_PolygonOffset(rsurface.texture->currentpolygonfactor, rsurface.texture->currentpolygonoffset);
5927 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_view.cullface_back);
5929 GL_BlendFunc(GL_ONE, GL_ZERO);
5931 GL_AlphaTest(false);
5932 R_Mesh_ColorPointer(NULL, 0, 0);
5933 R_Mesh_ResetTextureState();
5934 RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
5935 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
5936 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
5937 r_refdef.stats.entities_surfaces += texturenumsurfaces;
5939 else if (r_depthfirst.integer == 3)
5941 else if (!r_view.showdebug && (r_showsurfaces.integer || gl_lightmaps.integer))
5943 GL_Color(0, 0, 0, 1);
5944 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
5946 else if (r_showsurfaces.integer)
5948 if (rsurface.mode != RSURFMODE_MULTIPASS)
5949 rsurface.mode = RSURFMODE_MULTIPASS;
5950 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
5951 GL_PolygonOffset(rsurface.texture->currentpolygonfactor, rsurface.texture->currentpolygonoffset);
5953 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_view.cullface_back);
5954 GL_BlendFunc(GL_ONE, GL_ZERO);
5955 GL_DepthMask(writedepth);
5957 GL_AlphaTest(false);
5958 R_Mesh_ColorPointer(NULL, 0, 0);
5959 R_Mesh_ResetTextureState();
5960 RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
5961 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist);
5962 r_refdef.stats.entities_surfaces += texturenumsurfaces;
5964 else if (gl_lightmaps.integer)
5967 if (rsurface.mode != RSURFMODE_MULTIPASS)
5968 rsurface.mode = RSURFMODE_MULTIPASS;
5969 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
5971 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_view.cullface_back);
5972 GL_BlendFunc(GL_ONE, GL_ZERO);
5973 GL_DepthMask(writedepth);
5975 GL_AlphaTest(false);
5976 // use lightmode 0 (fullbright or lightmap) or 2 (model lighting)
5977 rsurface.lightmode = ((rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || rsurface.modeltexcoordlightmap2f != NULL) ? 0 : 2;
5978 R_Mesh_ColorPointer(NULL, 0, 0);
5979 memset(&m, 0, sizeof(m));
5980 m.tex[0] = R_GetTexture(r_texture_white);
5981 m.pointer_texcoord[0] = rsurface.modeltexcoordlightmap2f;
5982 m.pointer_texcoord_bufferobject[0] = rsurface.modeltexcoordlightmap2f_bufferobject;
5983 m.pointer_texcoord_bufferoffset[0] = rsurface.modeltexcoordlightmap2f_bufferoffset;
5984 R_Mesh_TextureState(&m);
5985 RSurf_PrepareVerticesForBatch(rsurface.lightmode == 2, false, texturenumsurfaces, texturesurfacelist);
5986 if (rsurface.lightmode == 2)
5987 RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
5988 else if (rsurface.uselightmaptexture)
5989 RSurf_DrawBatch_GL11_Lightmap(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
5991 RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
5992 r_refdef.stats.entities_surfaces += texturenumsurfaces;
5994 else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY)
5996 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
5997 r_refdef.stats.entities_surfaces += texturenumsurfaces;
5999 else if (rsurface.texture->currentnumlayers)
6001 // write depth for anything we skipped on the depth-only pass earlier
6002 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
6004 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
6005 GL_PolygonOffset(rsurface.texture->currentpolygonfactor, rsurface.texture->currentpolygonoffset);
6006 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
6007 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_view.cullface_back);
6008 GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
6009 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
6010 GL_AlphaTest((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
6011 // use lightmode 0 (fullbright or lightmap) or 2 (model lighting)
6012 rsurface.lightmode = ((rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || rsurface.modeltexcoordlightmap2f != NULL) ? 0 : 2;
6013 if (r_glsl.integer && gl_support_fragment_shader)
6014 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist);
6015 else if (gl_combine.integer && r_textureunits.integer >= 2)
6016 R_DrawTextureSurfaceList_GL13(texturenumsurfaces, texturesurfacelist);
6018 R_DrawTextureSurfaceList_GL11(texturenumsurfaces, texturesurfacelist);
6019 r_refdef.stats.entities_surfaces += texturenumsurfaces;
6022 GL_LockArrays(0, 0);
6025 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6028 int texturenumsurfaces, endsurface;
6030 msurface_t *surface;
6031 msurface_t *texturesurfacelist[1024];
6033 // if the model is static it doesn't matter what value we give for
6034 // wantnormals and wanttangents, so this logic uses only rules applicable
6035 // to a model, knowing that they are meaningless otherwise
6036 if (ent == r_refdef.worldentity)
6037 RSurf_ActiveWorldEntity();
6038 else if ((ent->effects & EF_FULLBRIGHT) || r_showsurfaces.integer || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f))
6039 RSurf_ActiveModelEntity(ent, false, false);
6041 RSurf_ActiveModelEntity(ent, true, r_glsl.integer && gl_support_fragment_shader);
6043 for (i = 0;i < numsurfaces;i = j)
6046 surface = rsurface.modelsurfaces + surfacelist[i];
6047 texture = surface->texture;
6048 R_UpdateTextureInfo(ent, texture);
6049 rsurface.texture = texture->currentframe;
6050 rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
6051 // scan ahead until we find a different texture
6052 endsurface = min(i + 1024, numsurfaces);
6053 texturenumsurfaces = 0;
6054 texturesurfacelist[texturenumsurfaces++] = surface;
6055 for (;j < endsurface;j++)
6057 surface = rsurface.modelsurfaces + surfacelist[j];
6058 if (texture != surface->texture || rsurface.uselightmaptexture != (surface->lightmaptexture != NULL))
6060 texturesurfacelist[texturenumsurfaces++] = surface;
6062 // render the range of surfaces
6063 R_DrawTextureSurfaceList(texturenumsurfaces, texturesurfacelist, true, false);
6069 void R_QueueSurfaceList(entity_render_t *ent, int numsurfaces, msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean addwaterplanes)
6072 vec3_t tempcenter, center;
6074 // if we're rendering water textures (extra scene renders), use a separate loop to avoid burdening the main one
6077 for (i = 0;i < numsurfaces;i++)
6078 if (surfacelist[i]->texture->currentframe->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION))
6079 R_Water_AddWaterPlane(surfacelist[i]);
6082 // break the surface list down into batches by texture and use of lightmapping
6083 for (i = 0;i < numsurfaces;i = j)
6086 // texture is the base texture pointer, rsurface.texture is the
6087 // current frame/skin the texture is directing us to use (for example
6088 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
6089 // use skin 1 instead)
6090 texture = surfacelist[i]->texture;
6091 rsurface.texture = texture->currentframe;
6092 rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
6093 if (!(rsurface.texture->currentmaterialflags & flagsmask))
6095 // if this texture is not the kind we want, skip ahead to the next one
6096 for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
6100 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
6102 // transparent surfaces get pushed off into the transparent queue
6103 const msurface_t *surface = surfacelist[i];
6106 tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
6107 tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
6108 tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
6109 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
6110 R_MeshQueue_AddTransparent(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_view.origin : center, R_DrawSurface_TransparentCallback, ent, surface - rsurface.modelsurfaces, rsurface.rtlight);
6114 // simply scan ahead until we find a different texture or lightmap state
6115 for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.uselightmaptexture == (surfacelist[j]->lightmaptexture != NULL);j++)
6117 // render the range of surfaces
6118 R_DrawTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly);
6123 float locboxvertex3f[6*4*3] =
6125 1,0,1, 1,0,0, 1,1,0, 1,1,1,
6126 0,1,1, 0,1,0, 0,0,0, 0,0,1,
6127 1,1,1, 1,1,0, 0,1,0, 0,1,1,
6128 0,0,1, 0,0,0, 1,0,0, 1,0,1,
6129 0,0,1, 1,0,1, 1,1,1, 0,1,1,
6130 1,0,0, 0,0,0, 0,1,0, 1,1,0
6133 int locboxelement3i[6*2*3] =
6143 void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6146 cl_locnode_t *loc = (cl_locnode_t *)ent;
6148 float vertex3f[6*4*3];
6150 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6151 GL_DepthMask(false);
6152 GL_DepthRange(0, 1);
6153 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
6155 GL_CullFace(GL_NONE);
6156 R_Mesh_Matrix(&identitymatrix);
6158 R_Mesh_VertexPointer(vertex3f, 0, 0);
6159 R_Mesh_ColorPointer(NULL, 0, 0);
6160 R_Mesh_ResetTextureState();
6163 GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_view.colorscale,
6164 ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_view.colorscale,
6165 ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_view.colorscale,
6166 surfacelist[0] < 0 ? 0.5f : 0.125f);
6168 if (VectorCompare(loc->mins, loc->maxs))
6170 VectorSet(size, 2, 2, 2);
6171 VectorMA(loc->mins, -0.5f, size, mins);
6175 VectorCopy(loc->mins, mins);
6176 VectorSubtract(loc->maxs, loc->mins, size);
6179 for (i = 0;i < 6*4*3;)
6180 for (j = 0;j < 3;j++, i++)
6181 vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
6183 R_Mesh_Draw(0, 6*4, 6*2, locboxelement3i, 0, 0);
6186 void R_DrawLocs(void)
6189 cl_locnode_t *loc, *nearestloc;
6191 nearestloc = CL_Locs_FindNearest(cl.movement_origin);
6192 for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
6194 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
6195 R_MeshQueue_AddTransparent(center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
6199 void R_DrawDebugModel(entity_render_t *ent)
6201 int i, j, k, l, flagsmask;
6202 const int *elements;
6204 msurface_t *surface;
6205 model_t *model = ent->model;
6208 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WATER | MATERIALFLAG_WALL;
6210 R_Mesh_ColorPointer(NULL, 0, 0);
6211 R_Mesh_ResetTextureState();
6212 GL_DepthRange(0, 1);
6213 GL_DepthTest(!r_showdisabledepthtest.integer);
6214 GL_DepthMask(false);
6215 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6217 if (r_showcollisionbrushes.value > 0 && model->brush.num_brushes)
6219 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
6220 for (i = 0, brush = model->brush.data_brushes + model->firstmodelbrush;i < model->nummodelbrushes;i++, brush++)
6222 if (brush->colbrushf && brush->colbrushf->numtriangles)
6224 R_Mesh_VertexPointer(brush->colbrushf->points->v, 0, 0);
6225 GL_Color((i & 31) * (1.0f / 32.0f) * r_view.colorscale, ((i >> 5) & 31) * (1.0f / 32.0f) * r_view.colorscale, ((i >> 10) & 31) * (1.0f / 32.0f) * r_view.colorscale, r_showcollisionbrushes.value);
6226 R_Mesh_Draw(0, brush->colbrushf->numpoints, brush->colbrushf->numtriangles, brush->colbrushf->elements, 0, 0);
6229 for (i = 0, surface = model->data_surfaces + model->firstmodelsurface;i < model->nummodelsurfaces;i++, surface++)
6231 if (surface->num_collisiontriangles)
6233 R_Mesh_VertexPointer(surface->data_collisionvertex3f, 0, 0);
6234 GL_Color((i & 31) * (1.0f / 32.0f) * r_view.colorscale, ((i >> 5) & 31) * (1.0f / 32.0f) * r_view.colorscale, ((i >> 10) & 31) * (1.0f / 32.0f) * r_view.colorscale, r_showcollisionbrushes.value);
6235 R_Mesh_Draw(0, surface->num_collisionvertices, surface->num_collisiontriangles, surface->data_collisionelement3i, 0, 0);
6240 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
6242 if (r_showtris.integer || r_shownormals.integer)
6244 if (r_showdisabledepthtest.integer)
6246 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6247 GL_DepthMask(false);
6251 GL_BlendFunc(GL_ONE, GL_ZERO);
6254 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
6256 if (ent == r_refdef.worldentity && !r_viewcache.world_surfacevisible[j])
6258 rsurface.texture = surface->texture->currentframe;
6259 if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
6261 RSurf_PrepareVerticesForBatch(true, true, 1, &surface);
6262 if (r_showtris.value > 0)
6264 if (!rsurface.texture->currentlayers->depthmask)
6265 GL_Color(r_view.colorscale, 0, 0, r_showtris.value);
6266 else if (ent == r_refdef.worldentity)
6267 GL_Color(r_view.colorscale, r_view.colorscale, r_view.colorscale, r_showtris.value);
6269 GL_Color(0, r_view.colorscale, 0, r_showtris.value);
6270 elements = (ent->model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);
6273 for (k = 0;k < surface->num_triangles;k++, elements += 3)
6275 #define GLVERTEXELEMENT(n) qglVertex3f(rsurface.vertex3f[elements[n]*3+0], rsurface.vertex3f[elements[n]*3+1], rsurface.vertex3f[elements[n]*3+2])
6276 GLVERTEXELEMENT(0);GLVERTEXELEMENT(1);
6277 GLVERTEXELEMENT(1);GLVERTEXELEMENT(2);
6278 GLVERTEXELEMENT(2);GLVERTEXELEMENT(0);
6283 if (r_shownormals.value > 0)
6285 GL_Color(r_view.colorscale, 0, 0, r_shownormals.value);
6287 for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
6289 VectorCopy(rsurface.vertex3f + l * 3, v);
6290 qglVertex3f(v[0], v[1], v[2]);
6291 VectorMA(v, 8, rsurface.svector3f + l * 3, v);
6292 qglVertex3f(v[0], v[1], v[2]);
6296 GL_Color(0, 0, r_view.colorscale, r_shownormals.value);
6298 for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
6300 VectorCopy(rsurface.vertex3f + l * 3, v);
6301 qglVertex3f(v[0], v[1], v[2]);
6302 VectorMA(v, 8, rsurface.tvector3f + l * 3, v);
6303 qglVertex3f(v[0], v[1], v[2]);
6307 GL_Color(0, r_view.colorscale, 0, r_shownormals.value);
6309 for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
6311 VectorCopy(rsurface.vertex3f + l * 3, v);
6312 qglVertex3f(v[0], v[1], v[2]);
6313 VectorMA(v, 8, rsurface.normal3f + l * 3, v);
6314 qglVertex3f(v[0], v[1], v[2]);
6321 rsurface.texture = NULL;
6325 extern void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface);
6326 void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean addwaterplanes, qboolean debug)
6328 int i, j, endj, f, flagsmask;
6329 int counttriangles = 0;
6330 msurface_t *surface, **surfacechain;
6332 model_t *model = r_refdef.worldmodel;
6333 const int maxsurfacelist = 1024;
6334 int numsurfacelist = 0;
6335 msurface_t *surfacelist[1024];
6339 RSurf_ActiveWorldEntity();
6341 // update light styles
6342 if (!skysurfaces && !depthonly && !addwaterplanes && model->brushq1.light_styleupdatechains)
6344 for (i = 0;i < model->brushq1.light_styles;i++)
6346 if (model->brushq1.light_stylevalue[i] != r_refdef.lightstylevalue[model->brushq1.light_style[i]])
6348 model->brushq1.light_stylevalue[i] = r_refdef.lightstylevalue[model->brushq1.light_style[i]];
6349 if ((surfacechain = model->brushq1.light_styleupdatechains[i]))
6350 for (;(surface = *surfacechain);surfacechain++)
6351 surface->cached_dlight = true;
6356 R_UpdateAllTextureInfo(r_refdef.worldentity);
6357 flagsmask = addwaterplanes ? (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) : (skysurfaces ? MATERIALFLAG_SKY : (MATERIALFLAG_WATER | MATERIALFLAG_WALL));
6361 R_DrawDebugModel(r_refdef.worldentity);
6367 rsurface.uselightmaptexture = false;
6368 rsurface.texture = NULL;
6370 j = model->firstmodelsurface;
6371 endj = j + model->nummodelsurfaces;
6374 // quickly skip over non-visible surfaces
6375 for (;j < endj && !r_viewcache.world_surfacevisible[j];j++)
6377 // quickly iterate over visible surfaces
6378 for (;j < endj && r_viewcache.world_surfacevisible[j];j++)
6380 // process this surface
6381 surface = model->data_surfaces + j;
6382 // if this surface fits the criteria, add it to the list
6383 if (surface->num_triangles)
6385 // if lightmap parameters changed, rebuild lightmap texture
6386 if (surface->cached_dlight)
6387 R_BuildLightMap(r_refdef.worldentity, surface);
6388 // add face to draw list
6389 surfacelist[numsurfacelist++] = surface;
6390 counttriangles += surface->num_triangles;
6391 if (numsurfacelist >= maxsurfacelist)
6393 R_QueueSurfaceList(r_refdef.worldentity, numsurfacelist, surfacelist, flagsmask, writedepth, depthonly, addwaterplanes);
6400 R_QueueSurfaceList(r_refdef.worldentity, numsurfacelist, surfacelist, flagsmask, writedepth, depthonly, addwaterplanes);
6401 r_refdef.stats.entities_triangles += counttriangles;
6405 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean addwaterplanes, qboolean debug)
6407 int i, f, flagsmask;
6408 int counttriangles = 0;
6409 msurface_t *surface, *endsurface, **surfacechain;
6411 model_t *model = ent->model;
6412 const int maxsurfacelist = 1024;
6413 int numsurfacelist = 0;
6414 msurface_t *surfacelist[1024];
6418 // if the model is static it doesn't matter what value we give for
6419 // wantnormals and wanttangents, so this logic uses only rules applicable
6420 // to a model, knowing that they are meaningless otherwise
6421 if (ent == r_refdef.worldentity)
6422 RSurf_ActiveWorldEntity();
6423 else if ((ent->effects & EF_FULLBRIGHT) || r_showsurfaces.integer || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f))
6424 RSurf_ActiveModelEntity(ent, false, false);
6426 RSurf_ActiveModelEntity(ent, true, r_glsl.integer && gl_support_fragment_shader && !depthonly);
6428 // update light styles
6429 if (!skysurfaces && !depthonly && !addwaterplanes && model->brushq1.light_styleupdatechains)
6431 for (i = 0;i < model->brushq1.light_styles;i++)
6433 if (model->brushq1.light_stylevalue[i] != r_refdef.lightstylevalue[model->brushq1.light_style[i]])
6435 model->brushq1.light_stylevalue[i] = r_refdef.lightstylevalue[model->brushq1.light_style[i]];
6436 if ((surfacechain = model->brushq1.light_styleupdatechains[i]))
6437 for (;(surface = *surfacechain);surfacechain++)
6438 surface->cached_dlight = true;
6443 R_UpdateAllTextureInfo(ent);
6444 flagsmask = addwaterplanes ? (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) : (skysurfaces ? MATERIALFLAG_SKY : (MATERIALFLAG_WATER | MATERIALFLAG_WALL));
6448 R_DrawDebugModel(ent);
6454 rsurface.uselightmaptexture = false;
6455 rsurface.texture = NULL;
6457 surface = model->data_surfaces + model->firstmodelsurface;
6458 endsurface = surface + model->nummodelsurfaces;
6459 for (;surface < endsurface;surface++)
6461 // if this surface fits the criteria, add it to the list
6462 if (surface->num_triangles)
6464 // if lightmap parameters changed, rebuild lightmap texture
6465 if (surface->cached_dlight)
6466 R_BuildLightMap(ent, surface);
6467 // add face to draw list
6468 surfacelist[numsurfacelist++] = surface;
6469 counttriangles += surface->num_triangles;
6470 if (numsurfacelist >= maxsurfacelist)
6472 R_QueueSurfaceList(ent, numsurfacelist, surfacelist, flagsmask, writedepth, depthonly, addwaterplanes);
6478 R_QueueSurfaceList(ent, numsurfacelist, surfacelist, flagsmask, writedepth, depthonly, addwaterplanes);
6479 r_refdef.stats.entities_triangles += counttriangles;