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(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"
529 " ModelViewProjectionPosition = gl_Position;\n"
532 " ModelViewProjectionPosition = gl_Position;\n"
534 "# ifdef USEREFLECTION\n"
535 " ModelViewProjectionPosition = gl_Position;\n"
541 "#endif // VERTEX_SHADER\n"
546 "// fragment shader specific:\n"
547 "#ifdef FRAGMENT_SHADER\n"
549 "// 13 textures, we can only use up to 16 on DX9-class hardware\n"
550 "uniform sampler2D Texture_Normal;\n"
551 "uniform sampler2D Texture_Color;\n"
552 "uniform sampler2D Texture_Gloss;\n"
553 "uniform samplerCube Texture_Cube;\n"
554 "uniform sampler2D Texture_Attenuation;\n"
555 "uniform sampler2D Texture_FogMask;\n"
556 "uniform sampler2D Texture_Pants;\n"
557 "uniform sampler2D Texture_Shirt;\n"
558 "uniform sampler2D Texture_Lightmap;\n"
559 "uniform sampler2D Texture_Deluxemap;\n"
560 "uniform sampler2D Texture_Glow;\n"
561 "uniform sampler2D Texture_Reflection;\n"
562 "uniform sampler2D Texture_Refraction;\n"
564 "uniform myhvec3 LightColor;\n"
565 "uniform myhvec3 AmbientColor;\n"
566 "uniform myhvec3 DiffuseColor;\n"
567 "uniform myhvec3 SpecularColor;\n"
568 "uniform myhvec3 Color_Pants;\n"
569 "uniform myhvec3 Color_Shirt;\n"
570 "uniform myhvec3 FogColor;\n"
572 "//#ifdef USEWATER\n"
573 "uniform vec4 DistortScaleRefractReflect;\n"
574 "uniform vec4 ScreenScaleRefractReflect;\n"
575 "uniform vec4 ScreenCenterRefractReflect;\n"
576 "uniform myhvec4 RefractColor;\n"
577 "uniform myhvec4 ReflectColor;\n"
578 "uniform myhalf ReflectFactor;\n"
579 "uniform myhalf ReflectOffset;\n"
581 "//# ifdef USEREFLECTION\n"
582 "//uniform vec4 DistortScaleRefractReflect;\n"
583 "//uniform vec4 ScreenScaleRefractReflect;\n"
584 "//uniform vec4 ScreenCenterRefractReflect;\n"
585 "//uniform myhvec3 ReflectColor;\n"
589 "uniform myhalf GlowScale;\n"
590 "uniform myhalf SceneBrightness;\n"
591 "#ifdef USECONTRASTBOOST\n"
592 "uniform myhalf ContrastBoostCoeff;\n"
595 "uniform float OffsetMapping_Scale;\n"
596 "uniform float OffsetMapping_Bias;\n"
597 "uniform float FogRangeRecip;\n"
599 "uniform myhalf AmbientScale;\n"
600 "uniform myhalf DiffuseScale;\n"
601 "uniform myhalf SpecularScale;\n"
602 "uniform myhalf SpecularPower;\n"
604 "#ifdef USEOFFSETMAPPING\n"
605 "vec2 OffsetMapping(vec2 TexCoord)\n"
607 "#ifdef USEOFFSETMAPPING_RELIEFMAPPING\n"
608 " // 14 sample relief mapping: linear search and then binary search\n"
609 " // this basically steps forward a small amount repeatedly until it finds\n"
610 " // itself inside solid, then jitters forward and back using decreasing\n"
611 " // amounts to find the impact\n"
612 " //vec3 OffsetVector = vec3(EyeVector.xy * ((1.0 / EyeVector.z) * OffsetMapping_Scale) * vec2(-1, 1), -1);\n"
613 " //vec3 OffsetVector = vec3(normalize(EyeVector.xy) * OffsetMapping_Scale * vec2(-1, 1), -1);\n"
614 " vec3 OffsetVector = vec3(normalize(EyeVector).xy * OffsetMapping_Scale * vec2(-1, 1), -1);\n"
615 " vec3 RT = vec3(TexCoord, 1);\n"
616 " OffsetVector *= 0.1;\n"
617 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
618 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
619 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
620 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
621 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
622 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
623 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
624 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
625 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
626 " RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) - 0.5);\n"
627 " RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) * 0.5 - 0.25);\n"
628 " RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) * 0.25 - 0.125);\n"
629 " RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) * 0.125 - 0.0625);\n"
630 " RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) * 0.0625 - 0.03125);\n"
633 " // 3 sample offset mapping (only 3 samples because of ATI Radeon 9500-9800/X300 limits)\n"
634 " // this basically moves forward the full distance, and then backs up based\n"
635 " // on height of samples\n"
636 " //vec2 OffsetVector = vec2(EyeVector.xy * ((1.0 / EyeVector.z) * OffsetMapping_Scale) * vec2(-1, 1));\n"
637 " //vec2 OffsetVector = vec2(normalize(EyeVector.xy) * OffsetMapping_Scale * vec2(-1, 1));\n"
638 " vec2 OffsetVector = vec2(normalize(EyeVector).xy * OffsetMapping_Scale * vec2(-1, 1));\n"
639 " TexCoord += OffsetVector;\n"
640 " OffsetVector *= 0.333;\n"
641 " TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
642 " TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
643 " TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
644 " return TexCoord;\n"
651 "#ifdef USEOFFSETMAPPING\n"
652 " // apply offsetmapping\n"
653 " vec2 TexCoordOffset = OffsetMapping(TexCoord);\n"
654 "#define TexCoord TexCoordOffset\n"
657 " // combine the diffuse textures (base, pants, shirt)\n"
658 " myhvec4 color = myhvec4(texture2D(Texture_Color, TexCoord));\n"
659 "#ifdef USECOLORMAPPING\n"
660 " color.rgb += myhvec3(texture2D(Texture_Pants, TexCoord)) * Color_Pants + myhvec3(texture2D(Texture_Shirt, TexCoord)) * Color_Shirt;\n"
666 "#ifdef MODE_LIGHTSOURCE\n"
669 " // calculate surface normal, light normal, and specular normal\n"
670 " // compute color intensity for the two textures (colormap and glossmap)\n"
671 " // scale by light color and attenuation as efficiently as possible\n"
672 " // (do as much scalar math as possible rather than vector math)\n"
673 "# ifdef USESPECULAR\n"
674 " myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5));\n"
675 " myhvec3 diffusenormal = myhvec3(normalize(LightVector));\n"
676 " myhvec3 specularnormal = normalize(diffusenormal + myhvec3(normalize(EyeVector)));\n"
678 " // calculate directional shading\n"
679 " 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"
681 "# ifdef USEDIFFUSE\n"
682 " myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5));\n"
683 " myhvec3 diffusenormal = myhvec3(normalize(LightVector));\n"
685 " // calculate directional shading\n"
686 " 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"
688 " // calculate directionless shading\n"
689 " color.rgb = color.rgb * LightColor * myhalf(texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0)));\n"
693 "# ifdef USECUBEFILTER\n"
694 " // apply light cubemap filter\n"
695 " //color.rgb *= normalize(CubeVector) * 0.5 + 0.5;//vec3(textureCube(Texture_Cube, CubeVector));\n"
696 " color.rgb *= myhvec3(textureCube(Texture_Cube, CubeVector));\n"
698 " color *= myhvec4(gl_Color);\n"
699 "#endif // MODE_LIGHTSOURCE\n"
704 "#ifdef MODE_LIGHTDIRECTION\n"
705 " // directional model lighting\n"
707 " // get the surface normal and light normal\n"
708 " myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5));\n"
709 " myhvec3 diffusenormal = myhvec3(LightVector);\n"
711 " // calculate directional shading\n"
712 " color.rgb *= AmbientColor + DiffuseColor * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0));\n"
713 "# ifdef USESPECULAR\n"
714 " myhvec3 specularnormal = normalize(diffusenormal + myhvec3(normalize(EyeVector)));\n"
715 " color.rgb += myhvec3(texture2D(Texture_Gloss, TexCoord)) * SpecularColor * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
717 " color *= myhvec4(gl_Color);\n"
718 "#endif // MODE_LIGHTDIRECTION\n"
723 "#ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
724 " // deluxemap lightmapping using light vectors in modelspace (evil q3map2)\n"
726 " // get the surface normal and light normal\n"
727 " myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5));\n"
729 " myhvec3 diffusenormal_modelspace = myhvec3(texture2D(Texture_Deluxemap, TexCoordLightmap)) - myhvec3(0.5);\n"
730 " myhvec3 diffusenormal = normalize(myhvec3(dot(diffusenormal_modelspace, myhvec3(VectorS)), dot(diffusenormal_modelspace, myhvec3(VectorT)), dot(diffusenormal_modelspace, myhvec3(VectorR))));\n"
731 " // calculate directional shading\n"
732 " myhvec3 tempcolor = color.rgb * (DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0)));\n"
733 "# ifdef USESPECULAR\n"
734 " myhvec3 specularnormal = myhvec3(normalize(diffusenormal + myhvec3(normalize(EyeVector))));\n"
735 " tempcolor += myhvec3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
738 " // apply lightmap color\n"
739 " color.rgb = myhvec4(tempcolor,1) * myhvec4(texture2D(Texture_Lightmap, TexCoordLightmap)) * myhvec4(gl_Color) + myhvec4(color.rgb * AmbientScale, 0);\n"
740 "#endif // MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
745 "#ifdef MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n"
746 " // deluxemap lightmapping using light vectors in tangentspace (hmap2 -light)\n"
748 " // get the surface normal and light normal\n"
749 " myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5));\n"
751 " myhvec3 diffusenormal = normalize(myhvec3(texture2D(Texture_Deluxemap, TexCoordLightmap)) - myhvec3(0.5));\n"
752 " // calculate directional shading\n"
753 " myhvec3 tempcolor = color.rgb * (DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0)));\n"
754 "# ifdef USESPECULAR\n"
755 " myhvec3 specularnormal = myhvec3(normalize(diffusenormal + myhvec3(normalize(EyeVector))));\n"
756 " tempcolor += myhvec3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
759 " // apply lightmap color\n"
760 " color = myhvec4(tempcolor, 1) * myhvec4(texture2D(Texture_Lightmap, TexCoordLightmap)) * myhvec4(gl_Color) + myhvec4(color.rgb * AmbientScale, 0);\n"
761 "#endif // MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n"
766 "#ifdef MODE_LIGHTMAP\n"
767 " // apply lightmap color\n"
768 " color *= myhvec4(texture2D(Texture_Lightmap, TexCoordLightmap)) * myhvec4(gl_Color) * myhvec4(myhvec3(DiffuseScale), 1) + myhvec4(myhvec3(AmbientScale), 0);\n"
769 "#endif // MODE_LIGHTMAP\n"
778 "#ifdef MODE_LIGHTSOURCE\n"
780 " color.rgb *= color.a;\n"
782 "# ifdef USEREFRACTION\n"
783 " color.rgb *= color.a;\n"
787 " vec4 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect * (1.0 / ModelViewProjectionPosition.w);\n"
788 " //vec4 ScreenTexCoord = (ModelViewProjectionPosition.xyxy + normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
789 " vec4 ScreenTexCoord = ModelViewProjectionPosition.xyxy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect + vec3(normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5))).xyxy * DistortScaleRefractReflect;\n"
790 " myhalf Fresnel = myhalf(pow(min(1.0, 1.0 - float(normalize(EyeVector).z)), 2.0)) * ReflectFactor + ReflectOffset;\n"
791 " 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"
793 "# ifdef USEREFRACTION\n"
794 " vec4 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect * (1.0 / ModelViewProjectionPosition.w);\n"
795 " //vec4 ScreenTexCoord = (ModelViewProjectionPosition.xyxy + normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
796 " vec4 ScreenTexCoord = ModelViewProjectionPosition.xyxy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect + vec3(normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5))).xyxy * DistortScaleRefractReflect;\n"
797 " color.rgb = mix(myhvec3(texture2D(Texture_Refraction, ScreenTexCoord.xy)) * RefractColor.rgb, color.rgb, color.a);\n"
799 "# ifdef USEREFLECTION\n"
800 " vec4 ScreenScaleRefractReflectIW = ScreenScaleRefractReflect * (1.0 / ModelViewProjectionPosition.w);\n"
801 " //vec4 ScreenTexCoord = (ModelViewProjectionPosition.xyxy + normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5)).xyxy * DistortScaleRefractReflect * 100) * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect;\n"
802 " vec4 ScreenTexCoord = ModelViewProjectionPosition.xyxy * ScreenScaleRefractReflectIW + ScreenCenterRefractReflect + vec3(normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5))).xyxy * DistortScaleRefractReflect;\n"
803 " color.rgb = mix(color.rgb, myhvec3(texture2D(Texture_Reflection, ScreenTexCoord.zw)) * ReflectColor.rgb, ReflectColor.a);\n"
808 " color.rgb += myhvec3(texture2D(Texture_Glow, TexCoord)) * GlowScale;\n"
813 " color.rgb = mix(FogColor, color.rgb, myhalf(texture2D(Texture_FogMask, myhvec2(length(EyeVectorModelSpace)*FogRangeRecip, 0.0))));\n"
816 "#ifdef USECONTRASTBOOST\n"
817 " color.rgb = color.rgb * SceneBrightness / (ContrastBoostCoeff * color.rgb + myhvec3(1, 1, 1));\n"
819 " color.rgb *= SceneBrightness;\n"
822 " gl_FragColor = vec4(color);\n"
825 "#endif // FRAGMENT_SHADER\n"
828 #define SHADERPERMUTATION_MODE_LIGHTMAP (1<<0) // (lightmap) use directional pixel shading from fixed light direction (q3bsp)
829 #define SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_MODELSPACE (1<<1) // (lightmap) use directional pixel shading from texture containing modelspace light directions (deluxemap)
830 #define SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_TANGENTSPACE (1<<2) // (lightmap) use directional pixel shading from texture containing tangentspace light directions (deluxemap)
831 #define SHADERPERMUTATION_MODE_LIGHTDIRECTION (1<<3) // (lightmap) use directional pixel shading from fixed light direction (q3bsp)
832 #define SHADERPERMUTATION_MODE_LIGHTSOURCE (1<<4) // (lightsource) use directional pixel shading from light source (rtlight)
833 #define SHADERPERMUTATION_WATER (1<<5) // normalmap-perturbed refraction of the background, performed behind the surface (the texture or material must be transparent to see it)
834 #define SHADERPERMUTATION_REFRACTION (1<<6) // normalmap-perturbed reflection of the scene infront of the surface, preformed as an overlay on the surface
835 #define SHADERPERMUTATION_REFLECTION (1<<7) // normalmap-perturbed reflection of the scene infront of the surface, preformed as an overlay on the surface
836 #define SHADERPERMUTATION_GLOW (1<<8) // (lightmap) blend in an additive glow texture
837 #define SHADERPERMUTATION_FOG (1<<9) // tint the color by fog color or black if using additive blend mode
838 #define SHADERPERMUTATION_COLORMAPPING (1<<10) // indicates this is a colormapped skin
839 #define SHADERPERMUTATION_DIFFUSE (1<<11) // (lightsource) whether to use directional shading
840 #define SHADERPERMUTATION_CONTRASTBOOST (1<<12) // r_glsl_contrastboost boosts the contrast at low color levels (similar to gamma)
841 #define SHADERPERMUTATION_SPECULAR (1<<13) // (lightsource or deluxemapping) render specular effects
842 #define SHADERPERMUTATION_CUBEFILTER (1<<14) // (lightsource) use cubemap light filter
843 #define SHADERPERMUTATION_OFFSETMAPPING (1<<15) // adjust texcoords to roughly simulate a displacement mapped surface
844 #define SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING (1<<16) // adjust texcoords to accurately simulate a displacement mapped surface (requires OFFSETMAPPING to also be set!)
846 #define SHADERPERMUTATION_INDICES (1<<17) // how many permutations are possible
847 #define SHADERPERMUTATION_MASK (SHADERPERMUTATION_INDICES - 1) // mask of valid indexing bits for r_glsl_permutations[] array
849 // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
850 const char *permutationinfo[][2] =
852 {"#define MODE_LIGHTMAP\n", " lightmap"},
853 {"#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
854 {"#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
855 {"#define MODE_LIGHTDIRECTION\n", " lightdirection"},
856 {"#define MODE_LIGHTSOURCE\n", " lightsource"},
857 {"#define USEWATER\n", " water"},
858 {"#define USEREFRACTION\n", " refraction"},
859 {"#define USEREFLECTION\n", " reflection"},
860 {"#define USEGLOW\n", " glow"},
861 {"#define USEFOG\n", " fog"},
862 {"#define USECOLORMAPPING\n", " colormapping"},
863 {"#define USEDIFFUSE\n", " diffuse"},
864 {"#define USECONTRASTBOOST\n", " contrastboost"},
865 {"#define USESPECULAR\n", " specular"},
866 {"#define USECUBEFILTER\n", " cubefilter"},
867 {"#define USEOFFSETMAPPING\n", " offsetmapping"},
868 {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
872 typedef struct r_glsl_permutation_s
874 // indicates if we have tried compiling this permutation already
876 // 0 if compilation failed
878 // locations of detected uniforms in program object, or -1 if not found
879 int loc_Texture_Normal;
880 int loc_Texture_Color;
881 int loc_Texture_Gloss;
882 int loc_Texture_Cube;
883 int loc_Texture_Attenuation;
884 int loc_Texture_FogMask;
885 int loc_Texture_Pants;
886 int loc_Texture_Shirt;
887 int loc_Texture_Lightmap;
888 int loc_Texture_Deluxemap;
889 int loc_Texture_Glow;
890 int loc_Texture_Refraction;
891 int loc_Texture_Reflection;
893 int loc_LightPosition;
898 int loc_FogRangeRecip;
899 int loc_AmbientScale;
900 int loc_DiffuseScale;
901 int loc_SpecularScale;
902 int loc_SpecularPower;
904 int loc_SceneBrightness; // or: Scenebrightness * ContrastBoost
905 int loc_OffsetMapping_Scale;
906 int loc_AmbientColor;
907 int loc_DiffuseColor;
908 int loc_SpecularColor;
910 int loc_ContrastBoostCoeff; // 1 - 1/ContrastBoost
911 int loc_DistortScaleRefractReflect;
912 int loc_ScreenScaleRefractReflect;
913 int loc_ScreenCenterRefractReflect;
914 int loc_RefractColor;
915 int loc_ReflectColor;
916 int loc_ReflectFactor;
917 int loc_ReflectOffset;
919 r_glsl_permutation_t;
921 // information about each possible shader permutation
922 r_glsl_permutation_t r_glsl_permutations[SHADERPERMUTATION_INDICES];
923 // currently selected permutation
924 r_glsl_permutation_t *r_glsl_permutation;
926 // these are additional flags used only by R_GLSL_CompilePermutation
927 #define SHADERTYPE_USES_VERTEXSHADER (1<<0)
928 #define SHADERTYPE_USES_GEOMETRYSHADER (1<<1)
929 #define SHADERTYPE_USES_FRAGMENTSHADER (1<<2)
931 static void R_GLSL_CompilePermutation(const char *filename, int permutation, int shadertype)
934 qboolean shaderfound;
935 r_glsl_permutation_t *p = r_glsl_permutations + permutation;
936 int vertstrings_count;
937 int geomstrings_count;
938 int fragstrings_count;
940 const char *vertstrings_list[32+1];
941 const char *geomstrings_list[32+1];
942 const char *fragstrings_list[32+1];
943 char permutationname[256];
948 vertstrings_list[0] = "#define VERTEX_SHADER\n";
949 geomstrings_list[0] = "#define GEOMETRY_SHADER\n";
950 fragstrings_list[0] = "#define FRAGMENT_SHADER\n";
951 vertstrings_count = 1;
952 geomstrings_count = 1;
953 fragstrings_count = 1;
954 permutationname[0] = 0;
955 for (i = 0;permutationinfo[i][0];i++)
957 if (permutation & (1<<i))
959 vertstrings_list[vertstrings_count++] = permutationinfo[i][0];
960 geomstrings_list[geomstrings_count++] = permutationinfo[i][0];
961 fragstrings_list[fragstrings_count++] = permutationinfo[i][0];
962 strlcat(permutationname, permutationinfo[i][1], sizeof(permutationname));
966 // keep line numbers correct
967 vertstrings_list[vertstrings_count++] = "\n";
968 geomstrings_list[geomstrings_count++] = "\n";
969 fragstrings_list[fragstrings_count++] = "\n";
972 shaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL);
976 Con_DPrint("from disk... ");
977 vertstrings_list[vertstrings_count++] = shaderstring;
978 geomstrings_list[geomstrings_count++] = shaderstring;
979 fragstrings_list[fragstrings_count++] = shaderstring;
982 else if (!strcmp(filename, "glsl/default.glsl"))
984 vertstrings_list[vertstrings_count++] = builtinshaderstring;
985 geomstrings_list[geomstrings_count++] = builtinshaderstring;
986 fragstrings_list[fragstrings_count++] = builtinshaderstring;
989 // clear any lists that are not needed by this shader
990 if (!(shadertype & SHADERTYPE_USES_VERTEXSHADER))
991 vertstrings_count = 0;
992 if (!(shadertype & SHADERTYPE_USES_GEOMETRYSHADER))
993 geomstrings_count = 0;
994 if (!(shadertype & SHADERTYPE_USES_FRAGMENTSHADER))
995 fragstrings_count = 0;
996 // compile the shader program
997 if (shaderfound && vertstrings_count + geomstrings_count + fragstrings_count)
998 p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
1002 qglUseProgramObjectARB(p->program);CHECKGLERROR
1003 // look up all the uniform variable names we care about, so we don't
1004 // have to look them up every time we set them
1005 p->loc_Texture_Normal = qglGetUniformLocationARB(p->program, "Texture_Normal");
1006 p->loc_Texture_Color = qglGetUniformLocationARB(p->program, "Texture_Color");
1007 p->loc_Texture_Gloss = qglGetUniformLocationARB(p->program, "Texture_Gloss");
1008 p->loc_Texture_Cube = qglGetUniformLocationARB(p->program, "Texture_Cube");
1009 p->loc_Texture_Attenuation = qglGetUniformLocationARB(p->program, "Texture_Attenuation");
1010 p->loc_Texture_FogMask = qglGetUniformLocationARB(p->program, "Texture_FogMask");
1011 p->loc_Texture_Pants = qglGetUniformLocationARB(p->program, "Texture_Pants");
1012 p->loc_Texture_Shirt = qglGetUniformLocationARB(p->program, "Texture_Shirt");
1013 p->loc_Texture_Lightmap = qglGetUniformLocationARB(p->program, "Texture_Lightmap");
1014 p->loc_Texture_Deluxemap = qglGetUniformLocationARB(p->program, "Texture_Deluxemap");
1015 p->loc_Texture_Glow = qglGetUniformLocationARB(p->program, "Texture_Glow");
1016 p->loc_Texture_Refraction = qglGetUniformLocationARB(p->program, "Texture_Refraction");
1017 p->loc_Texture_Reflection = qglGetUniformLocationARB(p->program, "Texture_Reflection");
1018 p->loc_FogColor = qglGetUniformLocationARB(p->program, "FogColor");
1019 p->loc_LightPosition = qglGetUniformLocationARB(p->program, "LightPosition");
1020 p->loc_EyePosition = qglGetUniformLocationARB(p->program, "EyePosition");
1021 p->loc_LightColor = qglGetUniformLocationARB(p->program, "LightColor");
1022 p->loc_Color_Pants = qglGetUniformLocationARB(p->program, "Color_Pants");
1023 p->loc_Color_Shirt = qglGetUniformLocationARB(p->program, "Color_Shirt");
1024 p->loc_FogRangeRecip = qglGetUniformLocationARB(p->program, "FogRangeRecip");
1025 p->loc_AmbientScale = qglGetUniformLocationARB(p->program, "AmbientScale");
1026 p->loc_DiffuseScale = qglGetUniformLocationARB(p->program, "DiffuseScale");
1027 p->loc_SpecularPower = qglGetUniformLocationARB(p->program, "SpecularPower");
1028 p->loc_SpecularScale = qglGetUniformLocationARB(p->program, "SpecularScale");
1029 p->loc_GlowScale = qglGetUniformLocationARB(p->program, "GlowScale");
1030 p->loc_SceneBrightness = qglGetUniformLocationARB(p->program, "SceneBrightness");
1031 p->loc_OffsetMapping_Scale = qglGetUniformLocationARB(p->program, "OffsetMapping_Scale");
1032 p->loc_AmbientColor = qglGetUniformLocationARB(p->program, "AmbientColor");
1033 p->loc_DiffuseColor = qglGetUniformLocationARB(p->program, "DiffuseColor");
1034 p->loc_SpecularColor = qglGetUniformLocationARB(p->program, "SpecularColor");
1035 p->loc_LightDir = qglGetUniformLocationARB(p->program, "LightDir");
1036 p->loc_ContrastBoostCoeff = qglGetUniformLocationARB(p->program, "ContrastBoostCoeff");
1037 p->loc_DistortScaleRefractReflect = qglGetUniformLocationARB(p->program, "DistortScaleRefractReflect");
1038 p->loc_ScreenScaleRefractReflect = qglGetUniformLocationARB(p->program, "ScreenScaleRefractReflect");
1039 p->loc_ScreenCenterRefractReflect = qglGetUniformLocationARB(p->program, "ScreenCenterRefractReflect");
1040 p->loc_RefractColor = qglGetUniformLocationARB(p->program, "RefractColor");
1041 p->loc_ReflectColor = qglGetUniformLocationARB(p->program, "ReflectColor");
1042 p->loc_ReflectFactor = qglGetUniformLocationARB(p->program, "ReflectFactor");
1043 p->loc_ReflectOffset = qglGetUniformLocationARB(p->program, "ReflectOffset");
1044 // initialize the samplers to refer to the texture units we use
1045 if (p->loc_Texture_Normal >= 0) qglUniform1iARB(p->loc_Texture_Normal, 0);
1046 if (p->loc_Texture_Color >= 0) qglUniform1iARB(p->loc_Texture_Color, 1);
1047 if (p->loc_Texture_Gloss >= 0) qglUniform1iARB(p->loc_Texture_Gloss, 2);
1048 if (p->loc_Texture_Cube >= 0) qglUniform1iARB(p->loc_Texture_Cube, 3);
1049 if (p->loc_Texture_FogMask >= 0) qglUniform1iARB(p->loc_Texture_FogMask, 4);
1050 if (p->loc_Texture_Pants >= 0) qglUniform1iARB(p->loc_Texture_Pants, 5);
1051 if (p->loc_Texture_Shirt >= 0) qglUniform1iARB(p->loc_Texture_Shirt, 6);
1052 if (p->loc_Texture_Lightmap >= 0) qglUniform1iARB(p->loc_Texture_Lightmap, 7);
1053 if (p->loc_Texture_Deluxemap >= 0) qglUniform1iARB(p->loc_Texture_Deluxemap, 8);
1054 if (p->loc_Texture_Glow >= 0) qglUniform1iARB(p->loc_Texture_Glow, 9);
1055 if (p->loc_Texture_Attenuation >= 0) qglUniform1iARB(p->loc_Texture_Attenuation, 10);
1056 if (p->loc_Texture_Refraction >= 0) qglUniform1iARB(p->loc_Texture_Refraction, 11);
1057 if (p->loc_Texture_Reflection >= 0) qglUniform1iARB(p->loc_Texture_Reflection, 12);
1059 qglUseProgramObjectARB(0);CHECKGLERROR
1060 if (developer.integer)
1061 Con_Printf("GLSL shader %s :%s compiled.\n", filename, permutationname);
1065 if (developer.integer)
1066 Con_Printf("GLSL shader %s :%s failed! source code line offset for above errors is %i.\n", permutationname, filename, -(vertstrings_count - 1));
1068 Con_Printf("GLSL shader %s :%s failed! some features may not work properly.\n", permutationname, filename);
1071 Mem_Free(shaderstring);
1074 void R_GLSL_Restart_f(void)
1077 for (i = 0;i < SHADERPERMUTATION_INDICES;i++)
1078 if (r_glsl_permutations[i].program)
1079 GL_Backend_FreeProgram(r_glsl_permutations[i].program);
1080 memset(r_glsl_permutations, 0, sizeof(r_glsl_permutations));
1083 void R_GLSL_DumpShader_f(void)
1087 qfile_t *file = FS_Open("glsl/default.glsl", "w", false, false);
1090 Con_Printf("failed to write to glsl/default.glsl\n");
1094 FS_Print(file, "// The engine may define the following macros:\n");
1095 FS_Print(file, "// #define VERTEX_SHADER\n// #define GEOMETRY_SHADER\n// #define FRAGMENT_SHADER\n");
1096 for (i = 0;permutationinfo[i][0];i++)
1097 FS_Printf(file, "// %s", permutationinfo[i][0]);
1098 FS_Print(file, "\n");
1099 FS_Print(file, builtinshaderstring);
1102 Con_Printf("glsl/default.glsl written\n");
1105 extern rtexture_t *r_shadow_attenuationgradienttexture;
1106 extern rtexture_t *r_shadow_attenuation2dtexture;
1107 extern rtexture_t *r_shadow_attenuation3dtexture;
1108 int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, float ambientscale, float diffusescale, float specularscale)
1110 // select a permutation of the lighting shader appropriate to this
1111 // combination of texture, entity, light source, and fogging, only use the
1112 // minimum features necessary to avoid wasting rendering time in the
1113 // fragment shader on features that are not being used
1114 const char *shaderfilename = NULL;
1115 unsigned int permutation = 0;
1116 unsigned int shadertype = 0;
1118 r_glsl_permutation = NULL;
1119 shaderfilename = "glsl/default.glsl";
1120 shadertype = SHADERTYPE_USES_VERTEXSHADER | SHADERTYPE_USES_FRAGMENTSHADER;
1121 // TODO: implement geometry-shader based shadow volumes someday
1122 if (rsurface.rtlight)
1125 permutation = SHADERPERMUTATION_MODE_LIGHTSOURCE;
1126 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1127 permutation |= SHADERPERMUTATION_CUBEFILTER;
1128 if (diffusescale > 0)
1129 permutation |= SHADERPERMUTATION_DIFFUSE;
1130 if (specularscale > 0)
1131 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1132 if (r_refdef.fogenabled)
1133 permutation |= SHADERPERMUTATION_FOG;
1134 if (rsurface.texture->colormapping)
1135 permutation |= SHADERPERMUTATION_COLORMAPPING;
1136 if (r_glsl_offsetmapping.integer)
1138 permutation |= SHADERPERMUTATION_OFFSETMAPPING;
1139 if (r_glsl_offsetmapping_reliefmapping.integer)
1140 permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
1142 if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
1143 permutation |= SHADERPERMUTATION_CONTRASTBOOST;
1144 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1145 permutation |= SHADERPERMUTATION_WATER;
1146 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
1147 permutation |= SHADERPERMUTATION_REFLECTION;
1149 else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
1151 // bright unshaded geometry
1152 permutation |= SHADERPERMUTATION_MODE_LIGHTMAP;
1153 if (rsurface.texture->currentskinframe->glow)
1154 permutation |= SHADERPERMUTATION_GLOW;
1155 if (r_refdef.fogenabled)
1156 permutation |= SHADERPERMUTATION_FOG;
1157 if (rsurface.texture->colormapping)
1158 permutation |= SHADERPERMUTATION_COLORMAPPING;
1159 if (r_glsl_offsetmapping.integer)
1161 permutation |= SHADERPERMUTATION_OFFSETMAPPING;
1162 if (r_glsl_offsetmapping_reliefmapping.integer)
1163 permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
1165 if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
1166 permutation |= SHADERPERMUTATION_CONTRASTBOOST;
1167 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1168 permutation |= SHADERPERMUTATION_WATER;
1169 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
1170 permutation |= SHADERPERMUTATION_REFLECTION;
1172 else if (modellighting)
1174 // directional model lighting
1175 permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTION;
1176 if (rsurface.texture->currentskinframe->glow)
1177 permutation |= SHADERPERMUTATION_GLOW;
1178 if (specularscale > 0)
1179 permutation |= SHADERPERMUTATION_SPECULAR;
1180 if (r_refdef.fogenabled)
1181 permutation |= SHADERPERMUTATION_FOG;
1182 if (rsurface.texture->colormapping)
1183 permutation |= SHADERPERMUTATION_COLORMAPPING;
1184 if (r_glsl_offsetmapping.integer)
1186 permutation |= SHADERPERMUTATION_OFFSETMAPPING;
1187 if (r_glsl_offsetmapping_reliefmapping.integer)
1188 permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
1190 if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
1191 permutation |= SHADERPERMUTATION_CONTRASTBOOST;
1192 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1193 permutation |= SHADERPERMUTATION_WATER;
1194 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
1195 permutation |= SHADERPERMUTATION_REFLECTION;
1200 if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping)
1202 // deluxemapping (light direction texture)
1203 if (rsurface.uselightmaptexture && r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping && r_refdef.worldmodel->brushq3.deluxemapping_modelspace)
1204 permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_MODELSPACE;
1206 permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1207 if (specularscale > 0)
1208 permutation |= SHADERPERMUTATION_SPECULAR;
1210 else if (r_glsl_deluxemapping.integer >= 2)
1212 // fake deluxemapping (uniform light direction in tangentspace)
1213 permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1214 if (specularscale > 0)
1215 permutation |= SHADERPERMUTATION_SPECULAR;
1219 // ordinary lightmapping
1220 permutation |= SHADERPERMUTATION_MODE_LIGHTMAP;
1222 if (rsurface.texture->currentskinframe->glow)
1223 permutation |= SHADERPERMUTATION_GLOW;
1224 if (r_refdef.fogenabled)
1225 permutation |= SHADERPERMUTATION_FOG;
1226 if (rsurface.texture->colormapping)
1227 permutation |= SHADERPERMUTATION_COLORMAPPING;
1228 if (r_glsl_offsetmapping.integer)
1230 permutation |= SHADERPERMUTATION_OFFSETMAPPING;
1231 if (r_glsl_offsetmapping_reliefmapping.integer)
1232 permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
1234 if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
1235 permutation |= SHADERPERMUTATION_CONTRASTBOOST;
1236 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1237 permutation |= SHADERPERMUTATION_WATER;
1238 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
1239 permutation |= SHADERPERMUTATION_REFLECTION;
1241 if (!r_glsl_permutations[permutation].program)
1243 if (!r_glsl_permutations[permutation].compiled)
1244 R_GLSL_CompilePermutation(shaderfilename, permutation, shadertype);
1245 if (!r_glsl_permutations[permutation].program)
1247 // remove features until we find a valid permutation
1249 for (i = (SHADERPERMUTATION_INDICES >> 1);;i>>=1)
1253 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");
1254 Cvar_SetValueQuick(&r_glsl, 0);
1255 return 0; // no bit left to clear
1257 // reduce i more quickly whenever it would not remove any bits
1258 if (!(permutation & i))
1261 if (!r_glsl_permutations[permutation].compiled)
1262 R_GLSL_CompilePermutation(shaderfilename, permutation, shadertype);
1263 if (r_glsl_permutations[permutation].program)
1268 r_glsl_permutation = r_glsl_permutations + permutation;
1270 qglUseProgramObjectARB(r_glsl_permutation->program);CHECKGLERROR
1271 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
1272 if (permutation & SHADERPERMUTATION_MODE_LIGHTSOURCE)
1274 if (r_glsl_permutation->loc_Texture_Cube >= 0 && rsurface.rtlight) R_Mesh_TexBindCubeMap(3, R_GetTexture(rsurface.rtlight->currentcubemap));
1275 if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
1276 if (permutation & SHADERPERMUTATION_DIFFUSE)
1278 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightColor, lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);
1279 if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, ambientscale);
1280 if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, diffusescale);
1281 if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, specularscale);
1285 // ambient only is simpler
1286 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightColor, lightcolorbase[0] * ambientscale, lightcolorbase[1] * ambientscale, lightcolorbase[2] * ambientscale);
1287 if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, 1);
1288 if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, 0);
1289 if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, 0);
1292 else if (permutation & SHADERPERMUTATION_MODE_LIGHTDIRECTION)
1294 if (r_glsl_permutation->loc_AmbientColor >= 0)
1295 qglUniform3fARB(r_glsl_permutation->loc_AmbientColor, rsurface.modellight_ambient[0] * ambientscale, rsurface.modellight_ambient[1] * ambientscale, rsurface.modellight_ambient[2] * ambientscale);
1296 if (r_glsl_permutation->loc_DiffuseColor >= 0)
1297 qglUniform3fARB(r_glsl_permutation->loc_DiffuseColor, rsurface.modellight_diffuse[0] * diffusescale, rsurface.modellight_diffuse[1] * diffusescale, rsurface.modellight_diffuse[2] * diffusescale);
1298 if (r_glsl_permutation->loc_SpecularColor >= 0)
1299 qglUniform3fARB(r_glsl_permutation->loc_SpecularColor, rsurface.modellight_diffuse[0] * specularscale, rsurface.modellight_diffuse[1] * specularscale, rsurface.modellight_diffuse[2] * specularscale);
1300 if (r_glsl_permutation->loc_LightDir >= 0)
1301 qglUniform3fARB(r_glsl_permutation->loc_LightDir, rsurface.modellight_lightdir[0], rsurface.modellight_lightdir[1], rsurface.modellight_lightdir[2]);
1305 if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, r_ambient.value * 2.0f / 128.0f);
1306 if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, r_refdef.lightmapintensity * 2.0f);
1307 if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, r_refdef.lightmapintensity * specularscale * 2.0f);
1309 nmap = rsurface.texture->currentskinframe->nmap;
1310 if (gl_lightmaps.integer)
1311 nmap = r_texture_blanknormalmap;
1312 if (r_glsl_permutation->loc_Texture_Normal >= 0) R_Mesh_TexBind(0, R_GetTexture(nmap));
1313 if (r_glsl_permutation->loc_Texture_Color >= 0) R_Mesh_TexBind(1, R_GetTexture(rsurface.texture->basetexture));
1314 if (r_glsl_permutation->loc_Texture_Gloss >= 0) R_Mesh_TexBind(2, R_GetTexture(rsurface.texture->glosstexture));
1315 //if (r_glsl_permutation->loc_Texture_Cube >= 0 && rsurface.rtlight) R_Mesh_TexBindCubeMap(3, R_GetTexture(rsurface.rtlight->currentcubemap));
1316 if (r_glsl_permutation->loc_Texture_Attenuation >= 0) R_Mesh_TexBind(10, R_GetTexture(r_shadow_attenuationgradienttexture));
1317 if (r_glsl_permutation->loc_Texture_FogMask >= 0) R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation));
1318 if (r_glsl_permutation->loc_Texture_Pants >= 0) R_Mesh_TexBind(5, R_GetTexture(rsurface.texture->currentskinframe->pants));
1319 if (r_glsl_permutation->loc_Texture_Shirt >= 0) R_Mesh_TexBind(6, R_GetTexture(rsurface.texture->currentskinframe->shirt));
1320 //if (r_glsl_permutation->loc_Texture_Lightmap >= 0) R_Mesh_TexBind(7, R_GetTexture(r_texture_white));
1321 //if (r_glsl_permutation->loc_Texture_Deluxemap >= 0) R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
1322 if (r_glsl_permutation->loc_Texture_Glow >= 0) R_Mesh_TexBind(9, R_GetTexture(rsurface.texture->currentskinframe->glow));
1323 if (r_glsl_permutation->loc_Texture_Refraction >= 0) R_Mesh_TexBind(11, R_GetTexture(r_texture_white)); // changed per surface
1324 if (r_glsl_permutation->loc_Texture_Reflection >= 0) R_Mesh_TexBind(12, R_GetTexture(r_texture_white)); // changed per surface
1325 if (r_glsl_permutation->loc_GlowScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_GlowScale, r_hdr_glowintensity.value);
1326 if (r_glsl_permutation->loc_ContrastBoostCoeff >= 0)
1328 // The formula used is actually:
1329 // color.rgb *= SceneBrightness;
1330 // color.rgb *= ContrastBoost / ((ContrastBoost - 1) * color.rgb + 1);
1331 // I simplify that to
1332 // color.rgb *= [[SceneBrightness * ContrastBoost]];
1333 // color.rgb /= [[(ContrastBoost - 1) / ContrastBoost]] * color.rgb + 1;
1335 // color.rgb = [[SceneBrightness * ContrastBoost]] / ([[(ContrastBoost - 1) * SceneBrightness]] + 1 / color.rgb);
1336 // and do [[calculations]] here in the engine
1337 qglUniform1fARB(r_glsl_permutation->loc_ContrastBoostCoeff, (r_glsl_contrastboost.value - 1) * r_view.colorscale);
1338 if (r_glsl_permutation->loc_SceneBrightness >= 0) qglUniform1fARB(r_glsl_permutation->loc_SceneBrightness, r_view.colorscale * r_glsl_contrastboost.value);
1341 if (r_glsl_permutation->loc_SceneBrightness >= 0) qglUniform1fARB(r_glsl_permutation->loc_SceneBrightness, r_view.colorscale);
1342 if (r_glsl_permutation->loc_FogColor >= 0)
1344 // additive passes are only darkened by fog, not tinted
1345 if (rsurface.rtlight || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ADD))
1346 qglUniform3fARB(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1348 qglUniform3fARB(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1350 if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_EyePosition, rsurface.modelorg[0], rsurface.modelorg[1], rsurface.modelorg[2]);
1351 if (r_glsl_permutation->loc_Color_Pants >= 0)
1353 if (rsurface.texture->currentskinframe->pants)
1354 qglUniform3fARB(r_glsl_permutation->loc_Color_Pants, rsurface.colormap_pantscolor[0], rsurface.colormap_pantscolor[1], rsurface.colormap_pantscolor[2]);
1356 qglUniform3fARB(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
1358 if (r_glsl_permutation->loc_Color_Shirt >= 0)
1360 if (rsurface.texture->currentskinframe->shirt)
1361 qglUniform3fARB(r_glsl_permutation->loc_Color_Shirt, rsurface.colormap_shirtcolor[0], rsurface.colormap_shirtcolor[1], rsurface.colormap_shirtcolor[2]);
1363 qglUniform3fARB(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
1365 if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1fARB(r_glsl_permutation->loc_FogRangeRecip, r_refdef.fograngerecip);
1366 if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularPower, rsurface.texture->specularpower);
1367 if (r_glsl_permutation->loc_OffsetMapping_Scale >= 0) qglUniform1fARB(r_glsl_permutation->loc_OffsetMapping_Scale, r_glsl_offsetmapping_scale.value);
1368 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);
1369 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]);
1370 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]);
1371 if (r_glsl_permutation->loc_RefractColor >= 0) qglUniform4fvARB(r_glsl_permutation->loc_RefractColor, 1, rsurface.texture->refractcolor4f);
1372 if (r_glsl_permutation->loc_ReflectColor >= 0) qglUniform4fvARB(r_glsl_permutation->loc_ReflectColor, 1, rsurface.texture->reflectcolor4f);
1373 if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1fARB(r_glsl_permutation->loc_ReflectFactor, rsurface.texture->reflectmax - rsurface.texture->reflectmin);
1374 if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1fARB(r_glsl_permutation->loc_ReflectOffset, rsurface.texture->reflectmin);
1379 #define SKINFRAME_HASH 1024
1383 int loadsequence; // incremented each level change
1384 memexpandablearray_t array;
1385 skinframe_t *hash[SKINFRAME_HASH];
1389 void R_SkinFrame_PrepareForPurge(void)
1391 r_skinframe.loadsequence++;
1392 // wrap it without hitting zero
1393 if (r_skinframe.loadsequence >= 200)
1394 r_skinframe.loadsequence = 1;
1397 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
1401 // mark the skinframe as used for the purging code
1402 skinframe->loadsequence = r_skinframe.loadsequence;
1405 void R_SkinFrame_Purge(void)
1409 for (i = 0;i < SKINFRAME_HASH;i++)
1411 for (s = r_skinframe.hash[i];s;s = s->next)
1413 if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
1415 if (s->base == r_texture_notexture) s->base = NULL;
1416 if (s->nmap == r_texture_blanknormalmap)s->nmap = NULL;
1417 if (s->merged == s->base) s->merged = NULL;
1418 if (s->stain ) R_FreeTexture(s->stain );s->stain = NULL;
1419 if (s->merged) R_FreeTexture(s->merged);s->merged = NULL;
1420 if (s->base ) R_FreeTexture(s->base );s->base = NULL;
1421 if (s->pants ) R_FreeTexture(s->pants );s->pants = NULL;
1422 if (s->shirt ) R_FreeTexture(s->shirt );s->shirt = NULL;
1423 if (s->nmap ) R_FreeTexture(s->nmap );s->nmap = NULL;
1424 if (s->gloss ) R_FreeTexture(s->gloss );s->gloss = NULL;
1425 if (s->glow ) R_FreeTexture(s->glow );s->glow = NULL;
1426 if (s->fog ) R_FreeTexture(s->fog );s->fog = NULL;
1427 s->loadsequence = 0;
1433 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qboolean add)
1437 char basename[MAX_QPATH];
1439 Image_StripImageExtension(name, basename, sizeof(basename));
1441 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
1442 for (item = r_skinframe.hash[hashindex];item;item = item->next)
1443 if (!strcmp(item->basename, basename) && item->textureflags == textureflags && item->comparewidth == comparewidth && item->compareheight == compareheight && item->comparecrc == comparecrc)
1449 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
1450 memset(item, 0, sizeof(*item));
1451 strlcpy(item->basename, basename, sizeof(item->basename));
1452 item->textureflags = textureflags;
1453 item->comparewidth = comparewidth;
1454 item->compareheight = compareheight;
1455 item->comparecrc = comparecrc;
1456 item->next = r_skinframe.hash[hashindex];
1457 r_skinframe.hash[hashindex] = item;
1459 R_SkinFrame_MarkUsed(item);
1463 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain)
1465 // FIXME: it should be possible to disable loading various layers using
1466 // cvars, to prevent wasted loading time and memory usage if the user does
1468 qboolean loadnormalmap = true;
1469 qboolean loadgloss = true;
1470 qboolean loadpantsandshirt = true;
1471 qboolean loadglow = true;
1473 unsigned char *pixels;
1474 unsigned char *bumppixels;
1475 unsigned char *basepixels = NULL;
1476 int basepixels_width;
1477 int basepixels_height;
1478 skinframe_t *skinframe;
1480 if (cls.state == ca_dedicated)
1483 // return an existing skinframe if already loaded
1484 // if loading of the first image fails, don't make a new skinframe as it
1485 // would cause all future lookups of this to be missing
1486 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
1487 if (skinframe && skinframe->base)
1490 basepixels = loadimagepixels(name, complain, 0, 0);
1491 if (basepixels == NULL)
1494 // we've got some pixels to store, so really allocate this new texture now
1496 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
1497 skinframe->stain = NULL;
1498 skinframe->merged = NULL;
1499 skinframe->base = r_texture_notexture;
1500 skinframe->pants = NULL;
1501 skinframe->shirt = NULL;
1502 skinframe->nmap = r_texture_blanknormalmap;
1503 skinframe->gloss = NULL;
1504 skinframe->glow = NULL;
1505 skinframe->fog = NULL;
1507 basepixels_width = image_width;
1508 basepixels_height = image_height;
1509 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);
1511 if (textureflags & TEXF_ALPHA)
1513 for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
1514 if (basepixels[j] < 255)
1516 if (j < basepixels_width * basepixels_height * 4)
1518 // has transparent pixels
1519 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
1520 for (j = 0;j < image_width * image_height * 4;j += 4)
1525 pixels[j+3] = basepixels[j+3];
1527 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);
1532 // _norm is the name used by tenebrae and has been adopted as standard
1535 if ((pixels = loadimagepixels(va("%s_norm", skinframe->basename), false, 0, 0)) != NULL)
1537 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);
1541 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixels(va("%s_bump", skinframe->basename), false, 0, 0)) != NULL)
1543 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
1544 Image_HeightmapToNormalmap(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
1545 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);
1547 Mem_Free(bumppixels);
1549 else if (r_shadow_bumpscale_basetexture.value > 0)
1551 pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
1552 Image_HeightmapToNormalmap(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
1553 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);
1557 // _luma is supported for tenebrae compatibility
1558 // (I think it's a very stupid name, but oh well)
1559 // _glow is the preferred name
1560 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;}
1561 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;}
1562 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;}
1563 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;}
1566 Mem_Free(basepixels);
1571 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)
1576 for (i = 0;i < width*height;i++)
1577 if (((unsigned char *)&palette[in[i]])[3] > 0)
1579 if (i == width*height)
1582 return R_LoadTexture2D (r_main_texturepool, name, width, height, in, TEXTYPE_PALETTE, textureflags, palette);
1585 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)
1588 unsigned char *temp1, *temp2;
1589 skinframe_t *skinframe;
1591 if (cls.state == ca_dedicated)
1594 // if already loaded just return it, otherwise make a new skinframe
1595 skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height*bitsperpixel/8) : 0, true);
1596 if (skinframe && skinframe->base)
1599 skinframe->stain = NULL;
1600 skinframe->merged = NULL;
1601 skinframe->base = r_texture_notexture;
1602 skinframe->pants = NULL;
1603 skinframe->shirt = NULL;
1604 skinframe->nmap = r_texture_blanknormalmap;
1605 skinframe->gloss = NULL;
1606 skinframe->glow = NULL;
1607 skinframe->fog = NULL;
1609 // if no data was provided, then clearly the caller wanted to get a blank skinframe
1613 if (bitsperpixel == 32)
1615 if (r_shadow_bumpscale_basetexture.value > 0)
1617 temp1 = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
1618 temp2 = temp1 + width * height * 4;
1619 Image_HeightmapToNormalmap(skindata, temp2, width, height, false, r_shadow_bumpscale_basetexture.value);
1620 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va("%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_RGBA, skinframe->textureflags | TEXF_ALPHA, NULL);
1623 skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_RGBA, skinframe->textureflags, NULL);
1624 if (textureflags & TEXF_ALPHA)
1626 for (i = 3;i < width * height * 4;i += 4)
1627 if (skindata[i] < 255)
1629 if (i < width * height * 4)
1631 unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
1632 memcpy(fogpixels, skindata, width * height * 4);
1633 for (i = 0;i < width * height * 4;i += 4)
1634 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
1635 skinframe->fog = R_LoadTexture2D(r_main_texturepool, va("%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_RGBA, skinframe->textureflags, NULL);
1636 Mem_Free(fogpixels);
1640 else if (bitsperpixel == 8)
1642 if (r_shadow_bumpscale_basetexture.value > 0)
1644 temp1 = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
1645 temp2 = temp1 + width * height * 4;
1646 if (bitsperpixel == 32)
1647 Image_HeightmapToNormalmap(skindata, temp2, width, height, false, r_shadow_bumpscale_basetexture.value);
1650 // use either a custom palette or the quake palette
1651 Image_Copy8bitRGBA(skindata, temp1, width * height, palette ? palette : palette_complete);
1652 Image_HeightmapToNormalmap(temp1, temp2, width, height, false, r_shadow_bumpscale_basetexture.value);
1654 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va("%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_RGBA, skinframe->textureflags | TEXF_ALPHA, NULL);
1657 // use either a custom palette, or the quake palette
1658 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
1659 if (!palette && loadglowtexture)
1660 skinframe->glow = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_glow", skinframe->basename), palette_onlyfullbrights, skinframe->textureflags, false); // glow
1661 if (!palette && loadpantsandshirt)
1663 skinframe->pants = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_pants", skinframe->basename), palette_pantsaswhite, skinframe->textureflags, false); // pants
1664 skinframe->shirt = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_shirt", skinframe->basename), palette_shirtaswhite, skinframe->textureflags, false); // shirt
1666 if (skinframe->pants || skinframe->shirt)
1667 skinframe->base = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_nospecial", skinframe->basename),loadglowtexture ? palette_nocolormapnofullbrights : palette_nocolormap, skinframe->textureflags, false); // no special colors
1668 if (textureflags & TEXF_ALPHA)
1670 // if not using a custom alphapalette, use the quake one
1672 alphapalette = palette_alpha;
1673 for (i = 0;i < width * height;i++)
1674 if (((unsigned char *)alphapalette)[skindata[i]*4+3] < 255)
1676 if (i < width * height)
1677 skinframe->fog = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_fog", skinframe->basename), alphapalette, skinframe->textureflags, true); // fog mask
1684 skinframe_t *R_SkinFrame_LoadMissing(void)
1686 skinframe_t *skinframe;
1688 if (cls.state == ca_dedicated)
1691 skinframe = R_SkinFrame_Find("missing", TEXF_PRECACHE, 0, 0, 0, true);
1692 skinframe->stain = NULL;
1693 skinframe->merged = NULL;
1694 skinframe->base = r_texture_notexture;
1695 skinframe->pants = NULL;
1696 skinframe->shirt = NULL;
1697 skinframe->nmap = r_texture_blanknormalmap;
1698 skinframe->gloss = NULL;
1699 skinframe->glow = NULL;
1700 skinframe->fog = NULL;
1705 void gl_main_start(void)
1710 r = (-1.0/256.0) * (FOGMASKTABLEWIDTH * FOGMASKTABLEWIDTH);
1711 for (x = 0;x < FOGMASKTABLEWIDTH;x++)
1713 alpha = 1 - exp(r / ((double)x*(double)x));
1714 if (x == FOGMASKTABLEWIDTH - 1)
1716 r_refdef.fogmasktable[x] = bound(0, alpha, 1);
1719 memset(r_qwskincache, 0, sizeof(r_qwskincache));
1720 memset(r_qwskincache_skinframe, 0, sizeof(r_qwskincache_skinframe));
1722 // set up r_skinframe loading system for textures
1723 memset(&r_skinframe, 0, sizeof(r_skinframe));
1724 r_skinframe.loadsequence = 1;
1725 Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
1727 r_main_texturepool = R_AllocTexturePool();
1728 R_BuildBlankTextures();
1730 if (gl_texturecubemap)
1733 R_BuildNormalizationCube();
1735 R_BuildFogTexture();
1736 memset(&r_bloomstate, 0, sizeof(r_bloomstate));
1737 memset(&r_waterstate, 0, sizeof(r_waterstate));
1738 memset(r_glsl_permutations, 0, sizeof(r_glsl_permutations));
1739 memset(&r_svbsp, 0, sizeof (r_svbsp));
1742 void gl_main_shutdown(void)
1744 memset(r_qwskincache, 0, sizeof(r_qwskincache));
1745 memset(r_qwskincache_skinframe, 0, sizeof(r_qwskincache_skinframe));
1747 // clear out the r_skinframe state
1748 Mem_ExpandableArray_FreeArray(&r_skinframe.array);
1749 memset(&r_skinframe, 0, sizeof(r_skinframe));
1752 Mem_Free(r_svbsp.nodes);
1753 memset(&r_svbsp, 0, sizeof (r_svbsp));
1754 R_FreeTexturePool(&r_main_texturepool);
1755 r_texture_blanknormalmap = NULL;
1756 r_texture_white = NULL;
1757 r_texture_grey128 = NULL;
1758 r_texture_black = NULL;
1759 r_texture_whitecube = NULL;
1760 r_texture_normalizationcube = NULL;
1761 memset(&r_bloomstate, 0, sizeof(r_bloomstate));
1762 memset(&r_waterstate, 0, sizeof(r_waterstate));
1766 extern void CL_ParseEntityLump(char *entitystring);
1767 void gl_main_newmap(void)
1769 // FIXME: move this code to client
1771 char *entities, entname[MAX_QPATH];
1774 strlcpy(entname, cl.worldmodel->name, sizeof(entname));
1775 l = (int)strlen(entname) - 4;
1776 if (l >= 0 && !strcmp(entname + l, ".bsp"))
1778 memcpy(entname + l, ".ent", 5);
1779 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
1781 CL_ParseEntityLump(entities);
1786 if (cl.worldmodel->brush.entities)
1787 CL_ParseEntityLump(cl.worldmodel->brush.entities);
1791 void GL_Main_Init(void)
1793 r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
1795 Cmd_AddCommand("r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
1796 Cmd_AddCommand("r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
1797 // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
1798 if (gamemode == GAME_NEHAHRA)
1800 Cvar_RegisterVariable (&gl_fogenable);
1801 Cvar_RegisterVariable (&gl_fogdensity);
1802 Cvar_RegisterVariable (&gl_fogred);
1803 Cvar_RegisterVariable (&gl_foggreen);
1804 Cvar_RegisterVariable (&gl_fogblue);
1805 Cvar_RegisterVariable (&gl_fogstart);
1806 Cvar_RegisterVariable (&gl_fogend);
1808 Cvar_RegisterVariable(&r_depthfirst);
1809 Cvar_RegisterVariable(&r_nearclip);
1810 Cvar_RegisterVariable(&r_showbboxes);
1811 Cvar_RegisterVariable(&r_showsurfaces);
1812 Cvar_RegisterVariable(&r_showtris);
1813 Cvar_RegisterVariable(&r_shownormals);
1814 Cvar_RegisterVariable(&r_showlighting);
1815 Cvar_RegisterVariable(&r_showshadowvolumes);
1816 Cvar_RegisterVariable(&r_showcollisionbrushes);
1817 Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
1818 Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
1819 Cvar_RegisterVariable(&r_showdisabledepthtest);
1820 Cvar_RegisterVariable(&r_drawportals);
1821 Cvar_RegisterVariable(&r_drawentities);
1822 Cvar_RegisterVariable(&r_cullentities_trace);
1823 Cvar_RegisterVariable(&r_cullentities_trace_samples);
1824 Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
1825 Cvar_RegisterVariable(&r_cullentities_trace_delay);
1826 Cvar_RegisterVariable(&r_drawviewmodel);
1827 Cvar_RegisterVariable(&r_speeds);
1828 Cvar_RegisterVariable(&r_fullbrights);
1829 Cvar_RegisterVariable(&r_wateralpha);
1830 Cvar_RegisterVariable(&r_dynamic);
1831 Cvar_RegisterVariable(&r_fullbright);
1832 Cvar_RegisterVariable(&r_shadows);
1833 Cvar_RegisterVariable(&r_shadows_throwdistance);
1834 Cvar_RegisterVariable(&r_q1bsp_skymasking);
1835 Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
1836 Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
1837 Cvar_RegisterVariable(&r_textureunits);
1838 Cvar_RegisterVariable(&r_glsl);
1839 Cvar_RegisterVariable(&r_glsl_offsetmapping);
1840 Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
1841 Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
1842 Cvar_RegisterVariable(&r_glsl_deluxemapping);
1843 Cvar_RegisterVariable(&r_water);
1844 Cvar_RegisterVariable(&r_water_resolutionmultiplier);
1845 Cvar_RegisterVariable(&r_water_clippingplanebias);
1846 Cvar_RegisterVariable(&r_water_refractdistort);
1847 Cvar_RegisterVariable(&r_water_reflectdistort);
1848 Cvar_RegisterVariable(&r_lerpsprites);
1849 Cvar_RegisterVariable(&r_lerpmodels);
1850 Cvar_RegisterVariable(&r_waterscroll);
1851 Cvar_RegisterVariable(&r_bloom);
1852 Cvar_RegisterVariable(&r_bloom_colorscale);
1853 Cvar_RegisterVariable(&r_bloom_brighten);
1854 Cvar_RegisterVariable(&r_bloom_blur);
1855 Cvar_RegisterVariable(&r_bloom_resolution);
1856 Cvar_RegisterVariable(&r_bloom_colorexponent);
1857 Cvar_RegisterVariable(&r_bloom_colorsubtract);
1858 Cvar_RegisterVariable(&r_hdr);
1859 Cvar_RegisterVariable(&r_hdr_scenebrightness);
1860 Cvar_RegisterVariable(&r_glsl_contrastboost);
1861 Cvar_RegisterVariable(&r_hdr_glowintensity);
1862 Cvar_RegisterVariable(&r_hdr_range);
1863 Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
1864 Cvar_RegisterVariable(&developer_texturelogging);
1865 Cvar_RegisterVariable(&gl_lightmaps);
1866 Cvar_RegisterVariable(&r_test);
1867 Cvar_RegisterVariable(&r_batchmode);
1868 if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
1869 Cvar_SetValue("r_fullbrights", 0);
1870 R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
1873 extern void R_Textures_Init(void);
1874 extern void GL_Draw_Init(void);
1875 extern void GL_Main_Init(void);
1876 extern void R_Shadow_Init(void);
1877 extern void R_Sky_Init(void);
1878 extern void GL_Surf_Init(void);
1879 extern void R_Light_Init(void);
1880 extern void R_Particles_Init(void);
1881 extern void R_Explosion_Init(void);
1882 extern void gl_backend_init(void);
1883 extern void Sbar_Init(void);
1884 extern void R_LightningBeams_Init(void);
1885 extern void Mod_RenderInit(void);
1887 void Render_Init(void)
1900 R_LightningBeams_Init();
1909 extern char *ENGINE_EXTENSIONS;
1912 VID_CheckExtensions();
1914 // LordHavoc: report supported extensions
1915 Con_DPrintf("\nQuakeC extensions for server and client: %s\nQuakeC extensions for menu: %s\n", vm_sv_extensions, vm_m_extensions );
1917 // clear to black (loading plaque will be seen over this)
1919 qglClearColor(0,0,0,1);CHECKGLERROR
1920 qglClear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
1923 int R_CullBox(const vec3_t mins, const vec3_t maxs)
1927 for (i = 0;i < r_view.numfrustumplanes;i++)
1929 // skip nearclip plane, it often culls portals when you are very close, and is almost never useful
1932 p = r_view.frustum + i;
1937 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
1941 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
1945 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
1949 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
1953 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
1957 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
1961 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
1965 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
1973 int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
1977 for (i = 0;i < numplanes;i++)
1984 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
1988 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
1992 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
1996 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
2000 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
2004 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
2008 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
2012 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
2020 //==================================================================================
2022 static void R_UpdateEntityLighting(entity_render_t *ent)
2024 vec3_t tempdiffusenormal;
2026 // fetch the lighting from the worldmodel data
2027 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));
2028 VectorClear(ent->modellight_diffuse);
2029 VectorClear(tempdiffusenormal);
2030 if ((ent->flags & RENDER_LIGHT) && r_refdef.worldmodel && r_refdef.worldmodel->brush.LightPoint)
2033 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2034 r_refdef.worldmodel->brush.LightPoint(r_refdef.worldmodel, org, ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal);
2037 VectorSet(ent->modellight_ambient, 1, 1, 1);
2039 // move the light direction into modelspace coordinates for lighting code
2040 Matrix4x4_Transform3x3(&ent->inversematrix, tempdiffusenormal, ent->modellight_lightdir);
2041 if(VectorLength2(ent->modellight_lightdir) > 0)
2043 VectorNormalize(ent->modellight_lightdir);
2047 VectorSet(ent->modellight_lightdir, 0, 0, 1); // have to set SOME valid vector here
2050 // scale ambient and directional light contributions according to rendering variables
2051 ent->modellight_ambient[0] *= ent->colormod[0] * r_refdef.lightmapintensity;
2052 ent->modellight_ambient[1] *= ent->colormod[1] * r_refdef.lightmapintensity;
2053 ent->modellight_ambient[2] *= ent->colormod[2] * r_refdef.lightmapintensity;
2054 ent->modellight_diffuse[0] *= ent->colormod[0] * r_refdef.lightmapintensity;
2055 ent->modellight_diffuse[1] *= ent->colormod[1] * r_refdef.lightmapintensity;
2056 ent->modellight_diffuse[2] *= ent->colormod[2] * r_refdef.lightmapintensity;
2059 static void R_View_UpdateEntityVisible (void)
2062 entity_render_t *ent;
2064 if (!r_drawentities.integer)
2067 renderimask = r_refdef.envmap ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL) : ((chase_active.integer || r_waterstate.renderingscene) ? RENDER_VIEWMODEL : RENDER_EXTERIORMODEL);
2068 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingVisibleLeafs)
2070 // worldmodel can check visibility
2071 for (i = 0;i < r_refdef.numentities;i++)
2073 ent = r_refdef.entities[i];
2074 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));
2076 if(r_cullentities_trace.integer)
2078 for (i = 0;i < r_refdef.numentities;i++)
2080 ent = r_refdef.entities[i];
2081 if(r_viewcache.entityvisible[i] && !(ent->effects & EF_NODEPTHTEST) && !(ent->flags & RENDER_VIEWMODEL) && !(ent->model && (ent->model->name[0] == '*')))
2083 if(Mod_CanSeeBox_Trace(r_cullentities_trace_samples.integer, r_cullentities_trace_enlarge.value, r_refdef.worldmodel, r_view.origin, ent->mins, ent->maxs))
2084 ent->last_trace_visibility = realtime;
2085 if(ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
2086 r_viewcache.entityvisible[i] = 0;
2093 // no worldmodel or it can't check visibility
2094 for (i = 0;i < r_refdef.numentities;i++)
2096 ent = r_refdef.entities[i];
2097 r_viewcache.entityvisible[i] = !(ent->flags & renderimask) && !R_CullBox(ent->mins, ent->maxs);
2101 // update entity lighting (even on hidden entities for r_shadows)
2102 for (i = 0;i < r_refdef.numentities;i++)
2103 R_UpdateEntityLighting(r_refdef.entities[i]);
2106 // only used if skyrendermasked, and normally returns false
2107 int R_DrawBrushModelsSky (void)
2110 entity_render_t *ent;
2112 if (!r_drawentities.integer)
2116 for (i = 0;i < r_refdef.numentities;i++)
2118 if (!r_viewcache.entityvisible[i])
2120 ent = r_refdef.entities[i];
2121 if (!ent->model || !ent->model->DrawSky)
2123 ent->model->DrawSky(ent);
2129 static void R_DrawNoModel(entity_render_t *ent);
2130 static void R_DrawModels(void)
2133 entity_render_t *ent;
2135 if (!r_drawentities.integer)
2138 for (i = 0;i < r_refdef.numentities;i++)
2140 if (!r_viewcache.entityvisible[i])
2142 ent = r_refdef.entities[i];
2143 r_refdef.stats.entities++;
2144 if (ent->model && ent->model->Draw != NULL)
2145 ent->model->Draw(ent);
2151 static void R_DrawModelsDepth(void)
2154 entity_render_t *ent;
2156 if (!r_drawentities.integer)
2159 for (i = 0;i < r_refdef.numentities;i++)
2161 if (!r_viewcache.entityvisible[i])
2163 ent = r_refdef.entities[i];
2164 r_refdef.stats.entities++;
2165 if (ent->model && ent->model->DrawDepth != NULL)
2166 ent->model->DrawDepth(ent);
2170 static void R_DrawModelsDebug(void)
2173 entity_render_t *ent;
2175 if (!r_drawentities.integer)
2178 for (i = 0;i < r_refdef.numentities;i++)
2180 if (!r_viewcache.entityvisible[i])
2182 ent = r_refdef.entities[i];
2183 r_refdef.stats.entities++;
2184 if (ent->model && ent->model->DrawDebug != NULL)
2185 ent->model->DrawDebug(ent);
2189 static void R_DrawModelsAddWaterPlanes(void)
2192 entity_render_t *ent;
2194 if (!r_drawentities.integer)
2197 for (i = 0;i < r_refdef.numentities;i++)
2199 if (!r_viewcache.entityvisible[i])
2201 ent = r_refdef.entities[i];
2202 r_refdef.stats.entities++;
2203 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
2204 ent->model->DrawAddWaterPlanes(ent);
2208 static void R_View_SetFrustum(void)
2211 double slopex, slopey;
2213 // break apart the view matrix into vectors for various purposes
2214 Matrix4x4_ToVectors(&r_view.matrix, r_view.forward, r_view.left, r_view.up, r_view.origin);
2215 VectorNegate(r_view.left, r_view.right);
2218 r_view.frustum[0].normal[0] = 0 - 1.0 / r_view.frustum_x;
2219 r_view.frustum[0].normal[1] = 0 - 0;
2220 r_view.frustum[0].normal[2] = -1 - 0;
2221 r_view.frustum[1].normal[0] = 0 + 1.0 / r_view.frustum_x;
2222 r_view.frustum[1].normal[1] = 0 + 0;
2223 r_view.frustum[1].normal[2] = -1 + 0;
2224 r_view.frustum[2].normal[0] = 0 - 0;
2225 r_view.frustum[2].normal[1] = 0 - 1.0 / r_view.frustum_y;
2226 r_view.frustum[2].normal[2] = -1 - 0;
2227 r_view.frustum[3].normal[0] = 0 + 0;
2228 r_view.frustum[3].normal[1] = 0 + 1.0 / r_view.frustum_y;
2229 r_view.frustum[3].normal[2] = -1 + 0;
2233 zNear = r_refdef.nearclip;
2234 nudge = 1.0 - 1.0 / (1<<23);
2235 r_view.frustum[4].normal[0] = 0 - 0;
2236 r_view.frustum[4].normal[1] = 0 - 0;
2237 r_view.frustum[4].normal[2] = -1 - -nudge;
2238 r_view.frustum[4].dist = 0 - -2 * zNear * nudge;
2239 r_view.frustum[5].normal[0] = 0 + 0;
2240 r_view.frustum[5].normal[1] = 0 + 0;
2241 r_view.frustum[5].normal[2] = -1 + -nudge;
2242 r_view.frustum[5].dist = 0 + -2 * zNear * nudge;
2248 r_view.frustum[0].normal[0] = m[3] - m[0];
2249 r_view.frustum[0].normal[1] = m[7] - m[4];
2250 r_view.frustum[0].normal[2] = m[11] - m[8];
2251 r_view.frustum[0].dist = m[15] - m[12];
2253 r_view.frustum[1].normal[0] = m[3] + m[0];
2254 r_view.frustum[1].normal[1] = m[7] + m[4];
2255 r_view.frustum[1].normal[2] = m[11] + m[8];
2256 r_view.frustum[1].dist = m[15] + m[12];
2258 r_view.frustum[2].normal[0] = m[3] - m[1];
2259 r_view.frustum[2].normal[1] = m[7] - m[5];
2260 r_view.frustum[2].normal[2] = m[11] - m[9];
2261 r_view.frustum[2].dist = m[15] - m[13];
2263 r_view.frustum[3].normal[0] = m[3] + m[1];
2264 r_view.frustum[3].normal[1] = m[7] + m[5];
2265 r_view.frustum[3].normal[2] = m[11] + m[9];
2266 r_view.frustum[3].dist = m[15] + m[13];
2268 r_view.frustum[4].normal[0] = m[3] - m[2];
2269 r_view.frustum[4].normal[1] = m[7] - m[6];
2270 r_view.frustum[4].normal[2] = m[11] - m[10];
2271 r_view.frustum[4].dist = m[15] - m[14];
2273 r_view.frustum[5].normal[0] = m[3] + m[2];
2274 r_view.frustum[5].normal[1] = m[7] + m[6];
2275 r_view.frustum[5].normal[2] = m[11] + m[10];
2276 r_view.frustum[5].dist = m[15] + m[14];
2281 if (r_view.useperspective)
2283 slopex = 1.0 / r_view.frustum_x;
2284 slopey = 1.0 / r_view.frustum_y;
2285 VectorMA(r_view.forward, -slopex, r_view.left, r_view.frustum[0].normal);
2286 VectorMA(r_view.forward, slopex, r_view.left, r_view.frustum[1].normal);
2287 VectorMA(r_view.forward, -slopey, r_view.up , r_view.frustum[2].normal);
2288 VectorMA(r_view.forward, slopey, r_view.up , r_view.frustum[3].normal);
2289 VectorCopy(r_view.forward, r_view.frustum[4].normal);
2291 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
2292 VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, -1024 * slopex, r_view.left, -1024 * slopey, r_view.up, r_view.frustumcorner[0]);
2293 VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, 1024 * slopex, r_view.left, -1024 * slopey, r_view.up, r_view.frustumcorner[1]);
2294 VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, -1024 * slopex, r_view.left, 1024 * slopey, r_view.up, r_view.frustumcorner[2]);
2295 VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, 1024 * slopex, r_view.left, 1024 * slopey, r_view.up, r_view.frustumcorner[3]);
2297 r_view.frustum[0].dist = DotProduct (r_view.origin, r_view.frustum[0].normal);
2298 r_view.frustum[1].dist = DotProduct (r_view.origin, r_view.frustum[1].normal);
2299 r_view.frustum[2].dist = DotProduct (r_view.origin, r_view.frustum[2].normal);
2300 r_view.frustum[3].dist = DotProduct (r_view.origin, r_view.frustum[3].normal);
2301 r_view.frustum[4].dist = DotProduct (r_view.origin, r_view.frustum[4].normal) + r_refdef.nearclip;
2305 VectorScale(r_view.left, -r_view.ortho_x, r_view.frustum[0].normal);
2306 VectorScale(r_view.left, r_view.ortho_x, r_view.frustum[1].normal);
2307 VectorScale(r_view.up, -r_view.ortho_y, r_view.frustum[2].normal);
2308 VectorScale(r_view.up, r_view.ortho_y, r_view.frustum[3].normal);
2309 VectorCopy(r_view.forward, r_view.frustum[4].normal);
2310 r_view.frustum[0].dist = DotProduct (r_view.origin, r_view.frustum[0].normal) + r_view.ortho_x;
2311 r_view.frustum[1].dist = DotProduct (r_view.origin, r_view.frustum[1].normal) + r_view.ortho_x;
2312 r_view.frustum[2].dist = DotProduct (r_view.origin, r_view.frustum[2].normal) + r_view.ortho_y;
2313 r_view.frustum[3].dist = DotProduct (r_view.origin, r_view.frustum[3].normal) + r_view.ortho_y;
2314 r_view.frustum[4].dist = DotProduct (r_view.origin, r_view.frustum[4].normal) + r_refdef.nearclip;
2316 r_view.numfrustumplanes = 5;
2318 if (r_view.useclipplane)
2320 r_view.numfrustumplanes = 6;
2321 r_view.frustum[5] = r_view.clipplane;
2324 for (i = 0;i < r_view.numfrustumplanes;i++)
2325 PlaneClassify(r_view.frustum + i);
2327 // LordHavoc: note to all quake engine coders, Quake had a special case
2328 // for 90 degrees which assumed a square view (wrong), so I removed it,
2329 // Quake2 has it disabled as well.
2331 // rotate R_VIEWFORWARD right by FOV_X/2 degrees
2332 //RotatePointAroundVector( r_view.frustum[0].normal, r_view.up, r_view.forward, -(90 - r_refdef.fov_x / 2));
2333 //r_view.frustum[0].dist = DotProduct (r_view.origin, frustum[0].normal);
2334 //PlaneClassify(&frustum[0]);
2336 // rotate R_VIEWFORWARD left by FOV_X/2 degrees
2337 //RotatePointAroundVector( r_view.frustum[1].normal, r_view.up, r_view.forward, (90 - r_refdef.fov_x / 2));
2338 //r_view.frustum[1].dist = DotProduct (r_view.origin, frustum[1].normal);
2339 //PlaneClassify(&frustum[1]);
2341 // rotate R_VIEWFORWARD up by FOV_X/2 degrees
2342 //RotatePointAroundVector( r_view.frustum[2].normal, r_view.left, r_view.forward, -(90 - r_refdef.fov_y / 2));
2343 //r_view.frustum[2].dist = DotProduct (r_view.origin, frustum[2].normal);
2344 //PlaneClassify(&frustum[2]);
2346 // rotate R_VIEWFORWARD down by FOV_X/2 degrees
2347 //RotatePointAroundVector( r_view.frustum[3].normal, r_view.left, r_view.forward, (90 - r_refdef.fov_y / 2));
2348 //r_view.frustum[3].dist = DotProduct (r_view.origin, frustum[3].normal);
2349 //PlaneClassify(&frustum[3]);
2352 //VectorCopy(r_view.forward, r_view.frustum[4].normal);
2353 //r_view.frustum[4].dist = DotProduct (r_view.origin, frustum[4].normal) + r_nearclip.value;
2354 //PlaneClassify(&frustum[4]);
2357 void R_View_Update(void)
2359 R_View_SetFrustum();
2360 R_View_WorldVisibility(r_view.useclipplane);
2361 R_View_UpdateEntityVisible();
2364 void R_SetupView(void)
2366 if (!r_view.useperspective)
2367 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);
2368 else if (r_refdef.rtworldshadows || r_refdef.rtdlightshadows)
2369 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view.frustum_x, r_view.frustum_y, r_refdef.nearclip);
2371 GL_SetupView_Mode_Perspective(r_view.frustum_x, r_view.frustum_y, r_refdef.nearclip, r_refdef.farclip);
2373 GL_SetupView_Orientation_FromEntity(&r_view.matrix);
2375 if (r_view.useclipplane)
2377 // LordHavoc: couldn't figure out how to make this approach the
2378 vec_t dist = r_view.clipplane.dist - r_water_clippingplanebias.value;
2379 vec_t viewdist = DotProduct(r_view.origin, r_view.clipplane.normal);
2380 if (viewdist < r_view.clipplane.dist + r_water_clippingplanebias.value)
2381 dist = r_view.clipplane.dist;
2382 GL_SetupView_ApplyCustomNearClipPlane(r_view.clipplane.normal[0], r_view.clipplane.normal[1], r_view.clipplane.normal[2], dist);
2386 void R_ResetViewRendering2D(void)
2388 if (gl_support_fragment_shader)
2390 qglUseProgramObjectARB(0);CHECKGLERROR
2395 // GL is weird because it's bottom to top, r_view.y is top to bottom
2396 qglViewport(r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
2397 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
2398 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2399 GL_Color(1, 1, 1, 1);
2400 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2401 GL_BlendFunc(GL_ONE, GL_ZERO);
2402 GL_AlphaTest(false);
2403 GL_ScissorTest(false);
2404 GL_DepthMask(false);
2405 GL_DepthRange(0, 1);
2406 GL_DepthTest(false);
2407 R_Mesh_Matrix(&identitymatrix);
2408 R_Mesh_ResetTextureState();
2409 GL_PolygonOffset(0, 0);
2410 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
2411 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2412 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
2413 qglStencilMask(~0);CHECKGLERROR
2414 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
2415 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
2416 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
2419 void R_ResetViewRendering3D(void)
2421 if (gl_support_fragment_shader)
2423 qglUseProgramObjectARB(0);CHECKGLERROR
2428 // GL is weird because it's bottom to top, r_view.y is top to bottom
2429 qglViewport(r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
2431 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2432 GL_Color(1, 1, 1, 1);
2433 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2434 GL_BlendFunc(GL_ONE, GL_ZERO);
2435 GL_AlphaTest(false);
2436 GL_ScissorTest(true);
2438 GL_DepthRange(0, 1);
2440 R_Mesh_Matrix(&identitymatrix);
2441 R_Mesh_ResetTextureState();
2442 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
2443 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
2444 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2445 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
2446 qglStencilMask(~0);CHECKGLERROR
2447 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
2448 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
2449 GL_CullFace(r_view.cullface_back);
2453 R_Bloom_SetupShader(
2455 "// written by Forest 'LordHavoc' Hale\n"
2457 "// common definitions between vertex shader and fragment shader:\n"
2459 "#ifdef __GLSL_CG_DATA_TYPES\n"
2460 "#define myhalf half\n"
2461 "#define myhvec2 hvec2\n"
2462 "#define myhvec3 hvec3\n"
2463 "#define myhvec4 hvec4\n"
2465 "#define myhalf float\n"
2466 "#define myhvec2 vec2\n"
2467 "#define myhvec3 vec3\n"
2468 "#define myhvec4 vec4\n"
2471 "varying vec2 ScreenTexCoord;\n"
2472 "varying vec2 BloomTexCoord;\n"
2477 "// vertex shader specific:\n"
2478 "#ifdef VERTEX_SHADER\n"
2482 " ScreenTexCoord = vec2(gl_MultiTexCoord0);\n"
2483 " BloomTexCoord = vec2(gl_MultiTexCoord1);\n"
2484 " // transform vertex to camera space, using ftransform to match non-VS\n"
2486 " gl_Position = ftransform();\n"
2489 "#endif // VERTEX_SHADER\n"
2494 "// fragment shader specific:\n"
2495 "#ifdef FRAGMENT_SHADER\n"
2500 " myhvec3 color = myhvec3(texture2D(Texture_Screen, ScreenTexCoord));\n"
2501 " for (x = -BLUR_X;x <= BLUR_X;x++)
2502 " color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
2503 " color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
2504 " color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
2505 " color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
2507 " gl_FragColor = vec4(color);\n"
2510 "#endif // FRAGMENT_SHADER\n"
2513 void R_RenderScene(qboolean addwaterplanes);
2515 static void R_Water_StartFrame(void)
2518 int waterwidth, waterheight, texturewidth, textureheight;
2519 r_waterstate_waterplane_t *p;
2521 // set waterwidth and waterheight to the water resolution that will be
2522 // used (often less than the screen resolution for faster rendering)
2523 waterwidth = (int)bound(1, r_view.width * r_water_resolutionmultiplier.value, r_view.width);
2524 waterheight = (int)bound(1, r_view.height * r_water_resolutionmultiplier.value, r_view.height);
2526 // calculate desired texture sizes
2527 // can't use water if the card does not support the texture size
2528 if (!r_water.integer || waterwidth > gl_max_texture_size || waterheight > gl_max_texture_size)
2529 texturewidth = textureheight = waterwidth = waterheight = 0;
2530 else if (gl_support_arb_texture_non_power_of_two)
2532 texturewidth = waterwidth;
2533 textureheight = waterheight;
2537 for (texturewidth = 1;texturewidth < waterwidth ;texturewidth *= 2);
2538 for (textureheight = 1;textureheight < waterheight;textureheight *= 2);
2541 // allocate textures as needed
2542 if (r_waterstate.waterwidth != waterwidth || r_waterstate.waterheight != waterheight || r_waterstate.texturewidth != texturewidth || r_waterstate.textureheight != textureheight)
2544 r_waterstate.maxwaterplanes = MAX_WATERPLANES;
2545 for (i = 0, p = r_waterstate.waterplanes;i < r_waterstate.maxwaterplanes;i++, p++)
2547 if (p->texture_refraction)
2548 R_FreeTexture(p->texture_refraction);
2549 p->texture_refraction = NULL;
2550 if (p->texture_reflection)
2551 R_FreeTexture(p->texture_reflection);
2552 p->texture_reflection = NULL;
2554 memset(&r_waterstate, 0, sizeof(r_waterstate));
2555 r_waterstate.waterwidth = waterwidth;
2556 r_waterstate.waterheight = waterheight;
2557 r_waterstate.texturewidth = texturewidth;
2558 r_waterstate.textureheight = textureheight;
2561 if (r_waterstate.waterwidth)
2563 r_waterstate.enabled = true;
2565 // set up variables that will be used in shader setup
2566 r_waterstate.screenscale[0] = 0.5f * (float)waterwidth / (float)texturewidth;
2567 r_waterstate.screenscale[1] = 0.5f * (float)waterheight / (float)textureheight;
2568 r_waterstate.screencenter[0] = 0.5f * (float)waterwidth / (float)texturewidth;
2569 r_waterstate.screencenter[1] = 0.5f * (float)waterheight / (float)textureheight;
2572 r_waterstate.maxwaterplanes = MAX_WATERPLANES;
2573 r_waterstate.numwaterplanes = 0;
2576 static void R_Water_AddWaterPlane(msurface_t *surface)
2578 int triangleindex, planeindex;
2584 r_waterstate_waterplane_t *p;
2585 // just use the first triangle with a valid normal for any decisions
2586 VectorClear(normal);
2587 VectorClear(center);
2588 for (triangleindex = 0, e = rsurface.modelelement3i + surface->num_firsttriangle * 3;triangleindex < surface->num_triangles;triangleindex++, e += 3)
2590 Matrix4x4_Transform(&rsurface.matrix, rsurface.modelvertex3f + e[0]*3, vert[0]);
2591 Matrix4x4_Transform(&rsurface.matrix, rsurface.modelvertex3f + e[1]*3, vert[1]);
2592 Matrix4x4_Transform(&rsurface.matrix, rsurface.modelvertex3f + e[2]*3, vert[2]);
2593 TriangleNormal(vert[0], vert[1], vert[2], normal);
2594 if (VectorLength2(normal) >= 0.001)
2597 // now find the center of this surface
2598 for (triangleindex = 0, e = rsurface.modelelement3i + surface->num_firsttriangle * 3;triangleindex < surface->num_triangles*3;triangleindex++, e++)
2600 Matrix4x4_Transform(&rsurface.matrix, rsurface.modelvertex3f + e[0]*3, vert[0]);
2601 VectorAdd(center, vert[0], center);
2603 f = 1.0 / surface->num_triangles*3;
2604 VectorScale(center, f, center);
2606 // find a matching plane if there is one
2607 for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++)
2608 if (fabs(PlaneDiff(vert[0], &p->plane)) < 1 && fabs(PlaneDiff(vert[1], &p->plane)) < 1 && fabs(PlaneDiff(vert[2], &p->plane)) < 1)
2610 if (planeindex >= r_waterstate.maxwaterplanes)
2611 return; // nothing we can do, out of planes
2613 // if this triangle does not fit any known plane rendered this frame, add one
2614 if (planeindex >= r_waterstate.numwaterplanes)
2616 // store the new plane
2617 r_waterstate.numwaterplanes++;
2618 VectorCopy(normal, p->plane.normal);
2619 VectorNormalize(p->plane.normal);
2620 p->plane.dist = DotProduct(vert[0], p->plane.normal);
2621 PlaneClassify(&p->plane);
2622 // flip the plane if it does not face the viewer
2623 if (PlaneDiff(r_view.origin, &p->plane) < 0)
2625 VectorNegate(p->plane.normal, p->plane.normal);
2626 p->plane.dist *= -1;
2627 PlaneClassify(&p->plane);
2629 // clear materialflags and pvs
2630 p->materialflags = 0;
2631 p->pvsvalid = false;
2633 // merge this surface's materialflags into the waterplane
2634 p->materialflags |= surface->texture->currentframe->currentmaterialflags;
2635 // merge this surface's PVS into the waterplane
2636 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.worldmodel && r_refdef.worldmodel->brush.FatPVS)
2638 r_refdef.worldmodel->brush.FatPVS(r_refdef.worldmodel, r_view.origin, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
2643 static void R_Water_ProcessPlanes(void)
2645 r_view_t originalview;
2647 r_waterstate_waterplane_t *p;
2649 originalview = r_view;
2651 // make sure enough textures are allocated
2652 for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++)
2654 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
2656 if (!p->texture_refraction)
2657 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);
2658 if (!p->texture_refraction)
2662 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
2664 if (!p->texture_reflection)
2665 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);
2666 if (!p->texture_reflection)
2672 for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++)
2674 r_view.showdebug = false;
2675 r_view.width = r_waterstate.waterwidth;
2676 r_view.height = r_waterstate.waterheight;
2677 r_view.useclipplane = true;
2678 r_waterstate.renderingscene = true;
2680 // render the normal view scene and copy into texture
2681 // (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)
2682 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
2684 r_view.clipplane = p->plane;
2685 VectorNegate(r_view.clipplane.normal, r_view.clipplane.normal);
2686 r_view.clipplane.dist = -r_view.clipplane.dist;
2687 PlaneClassify(&r_view.clipplane);
2689 R_RenderScene(false);
2691 // copy view into the screen texture
2692 R_Mesh_TexBind(0, R_GetTexture(p->texture_refraction));
2693 GL_ActiveTexture(0);
2695 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
2698 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
2700 // render reflected scene and copy into texture
2701 Matrix4x4_Reflect(&r_view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
2702 r_view.clipplane = p->plane;
2703 // reverse the cullface settings for this render
2704 r_view.cullface_front = GL_FRONT;
2705 r_view.cullface_back = GL_BACK;
2706 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.num_pvsclusterbytes)
2708 r_view.usecustompvs = true;
2710 memcpy(r_viewcache.world_pvsbits, p->pvsbits, r_refdef.worldmodel->brush.num_pvsclusterbytes);
2712 memset(r_viewcache.world_pvsbits, 0xFF, r_refdef.worldmodel->brush.num_pvsclusterbytes);
2715 R_ResetViewRendering3D();
2718 R_RenderScene(false);
2720 R_Mesh_TexBind(0, R_GetTexture(p->texture_reflection));
2721 GL_ActiveTexture(0);
2723 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
2725 R_ResetViewRendering3D();
2729 r_view = originalview;
2730 r_waterstate.renderingscene = false;
2734 r_view = originalview;
2735 r_waterstate.renderingscene = false;
2736 Cvar_SetValueQuick(&r_water, 0);
2737 Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed! Turned off r_water.\n");
2741 void R_Bloom_StartFrame(void)
2743 int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight;
2745 // set bloomwidth and bloomheight to the bloom resolution that will be
2746 // used (often less than the screen resolution for faster rendering)
2747 r_bloomstate.bloomwidth = bound(1, r_bloom_resolution.integer, r_view.width);
2748 r_bloomstate.bloomheight = r_bloomstate.bloomwidth * r_view.height / r_view.width;
2749 r_bloomstate.bloomheight = bound(1, r_bloomstate.bloomheight, r_view.height);
2751 // calculate desired texture sizes
2752 if (gl_support_arb_texture_non_power_of_two)
2754 screentexturewidth = r_view.width;
2755 screentextureheight = r_view.height;
2756 bloomtexturewidth = r_bloomstate.bloomwidth;
2757 bloomtextureheight = r_bloomstate.bloomheight;
2761 for (screentexturewidth = 1;screentexturewidth < vid.width ;screentexturewidth *= 2);
2762 for (screentextureheight = 1;screentextureheight < vid.height ;screentextureheight *= 2);
2763 for (bloomtexturewidth = 1;bloomtexturewidth < r_bloomstate.bloomwidth ;bloomtexturewidth *= 2);
2764 for (bloomtextureheight = 1;bloomtextureheight < r_bloomstate.bloomheight;bloomtextureheight *= 2);
2769 screentexturewidth = screentextureheight = 0;
2771 else if (r_bloom.integer)
2776 screentexturewidth = screentextureheight = 0;
2777 bloomtexturewidth = bloomtextureheight = 0;
2780 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)
2782 // can't use bloom if the parameters are too weird
2783 // can't use bloom if the card does not support the texture size
2784 if (r_bloomstate.texture_screen)
2785 R_FreeTexture(r_bloomstate.texture_screen);
2786 if (r_bloomstate.texture_bloom)
2787 R_FreeTexture(r_bloomstate.texture_bloom);
2788 memset(&r_bloomstate, 0, sizeof(r_bloomstate));
2792 r_bloomstate.enabled = true;
2793 r_bloomstate.hdr = r_hdr.integer != 0;
2795 // allocate textures as needed
2796 if (r_bloomstate.screentexturewidth != screentexturewidth || r_bloomstate.screentextureheight != screentextureheight)
2798 if (r_bloomstate.texture_screen)
2799 R_FreeTexture(r_bloomstate.texture_screen);
2800 r_bloomstate.texture_screen = NULL;
2801 r_bloomstate.screentexturewidth = screentexturewidth;
2802 r_bloomstate.screentextureheight = screentextureheight;
2803 if (r_bloomstate.screentexturewidth && r_bloomstate.screentextureheight)
2804 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);
2806 if (r_bloomstate.bloomtexturewidth != bloomtexturewidth || r_bloomstate.bloomtextureheight != bloomtextureheight)
2808 if (r_bloomstate.texture_bloom)
2809 R_FreeTexture(r_bloomstate.texture_bloom);
2810 r_bloomstate.texture_bloom = NULL;
2811 r_bloomstate.bloomtexturewidth = bloomtexturewidth;
2812 r_bloomstate.bloomtextureheight = bloomtextureheight;
2813 if (r_bloomstate.bloomtexturewidth && r_bloomstate.bloomtextureheight)
2814 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);
2817 // set up a texcoord array for the full resolution screen image
2818 // (we have to keep this around to copy back during final render)
2819 r_bloomstate.screentexcoord2f[0] = 0;
2820 r_bloomstate.screentexcoord2f[1] = (float)r_view.height / (float)r_bloomstate.screentextureheight;
2821 r_bloomstate.screentexcoord2f[2] = (float)r_view.width / (float)r_bloomstate.screentexturewidth;
2822 r_bloomstate.screentexcoord2f[3] = (float)r_view.height / (float)r_bloomstate.screentextureheight;
2823 r_bloomstate.screentexcoord2f[4] = (float)r_view.width / (float)r_bloomstate.screentexturewidth;
2824 r_bloomstate.screentexcoord2f[5] = 0;
2825 r_bloomstate.screentexcoord2f[6] = 0;
2826 r_bloomstate.screentexcoord2f[7] = 0;
2828 // set up a texcoord array for the reduced resolution bloom image
2829 // (which will be additive blended over the screen image)
2830 r_bloomstate.bloomtexcoord2f[0] = 0;
2831 r_bloomstate.bloomtexcoord2f[1] = (float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
2832 r_bloomstate.bloomtexcoord2f[2] = (float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
2833 r_bloomstate.bloomtexcoord2f[3] = (float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
2834 r_bloomstate.bloomtexcoord2f[4] = (float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
2835 r_bloomstate.bloomtexcoord2f[5] = 0;
2836 r_bloomstate.bloomtexcoord2f[6] = 0;
2837 r_bloomstate.bloomtexcoord2f[7] = 0;
2840 void R_Bloom_CopyScreenTexture(float colorscale)
2842 r_refdef.stats.bloom++;
2844 R_ResetViewRendering2D();
2845 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
2846 R_Mesh_ColorPointer(NULL, 0, 0);
2847 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
2848 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
2850 // copy view into the screen texture
2851 GL_ActiveTexture(0);
2853 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
2854 r_refdef.stats.bloom_copypixels += r_view.width * r_view.height;
2856 // now scale it down to the bloom texture size
2858 qglViewport(r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
2859 GL_BlendFunc(GL_ONE, GL_ZERO);
2860 GL_Color(colorscale, colorscale, colorscale, 1);
2861 // TODO: optimize with multitexture or GLSL
2862 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2863 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2865 // we now have a bloom image in the framebuffer
2866 // copy it into the bloom image texture for later processing
2867 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2868 GL_ActiveTexture(0);
2870 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
2871 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2874 void R_Bloom_CopyHDRTexture(void)
2876 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2877 GL_ActiveTexture(0);
2879 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
2880 r_refdef.stats.bloom_copypixels += r_view.width * r_view.height;
2883 void R_Bloom_MakeTexture(void)
2886 float xoffset, yoffset, r, brighten;
2888 r_refdef.stats.bloom++;
2890 R_ResetViewRendering2D();
2891 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
2892 R_Mesh_ColorPointer(NULL, 0, 0);
2894 // we have a bloom image in the framebuffer
2896 qglViewport(r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
2898 for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
2901 r = bound(0, r_bloom_colorexponent.value / x, 1);
2902 GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
2903 GL_Color(r, r, r, 1);
2904 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2905 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
2906 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2907 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2909 // copy the vertically blurred bloom view to a texture
2910 GL_ActiveTexture(0);
2912 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
2913 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2916 range = r_bloom_blur.integer * r_bloomstate.bloomwidth / 320;
2917 brighten = r_bloom_brighten.value;
2919 brighten *= r_hdr_range.value;
2920 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2921 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.offsettexcoord2f, 0, 0);
2923 for (dir = 0;dir < 2;dir++)
2925 // blend on at multiple vertical offsets to achieve a vertical blur
2926 // TODO: do offset blends using GLSL
2927 GL_BlendFunc(GL_ONE, GL_ZERO);
2928 for (x = -range;x <= range;x++)
2930 if (!dir){xoffset = 0;yoffset = x;}
2931 else {xoffset = x;yoffset = 0;}
2932 xoffset /= (float)r_bloomstate.bloomtexturewidth;
2933 yoffset /= (float)r_bloomstate.bloomtextureheight;
2934 // compute a texcoord array with the specified x and y offset
2935 r_bloomstate.offsettexcoord2f[0] = xoffset+0;
2936 r_bloomstate.offsettexcoord2f[1] = yoffset+(float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
2937 r_bloomstate.offsettexcoord2f[2] = xoffset+(float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
2938 r_bloomstate.offsettexcoord2f[3] = yoffset+(float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
2939 r_bloomstate.offsettexcoord2f[4] = xoffset+(float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
2940 r_bloomstate.offsettexcoord2f[5] = yoffset+0;
2941 r_bloomstate.offsettexcoord2f[6] = xoffset+0;
2942 r_bloomstate.offsettexcoord2f[7] = yoffset+0;
2943 // this r value looks like a 'dot' particle, fading sharply to
2944 // black at the edges
2945 // (probably not realistic but looks good enough)
2946 //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
2947 //r = (dir ? 1.0f : brighten)/(range*2+1);
2948 r = (dir ? 1.0f : brighten)/(range*2+1)*(1 - x*x/(float)(range*range));
2949 GL_Color(r, r, r, 1);
2950 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2951 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2952 GL_BlendFunc(GL_ONE, GL_ONE);
2955 // copy the vertically blurred bloom view to a texture
2956 GL_ActiveTexture(0);
2958 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
2959 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2962 // apply subtract last
2963 // (just like it would be in a GLSL shader)
2964 if (r_bloom_colorsubtract.value > 0 && gl_support_ext_blend_subtract)
2966 GL_BlendFunc(GL_ONE, GL_ZERO);
2967 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2968 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
2969 GL_Color(1, 1, 1, 1);
2970 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2971 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2973 GL_BlendFunc(GL_ONE, GL_ONE);
2974 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2975 R_Mesh_TexBind(0, R_GetTexture(r_texture_white));
2976 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
2977 GL_Color(r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, 1);
2978 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2979 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2980 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2982 // copy the darkened bloom view to a texture
2983 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2984 GL_ActiveTexture(0);
2986 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
2987 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2991 void R_HDR_RenderBloomTexture(void)
2993 int oldwidth, oldheight;
2995 oldwidth = r_view.width;
2996 oldheight = r_view.height;
2997 r_view.width = r_bloomstate.bloomwidth;
2998 r_view.height = r_bloomstate.bloomheight;
3000 // TODO: support GL_EXT_framebuffer_object rather than reusing the framebuffer? it might improve SLI performance.
3001 // TODO: add exposure compensation features
3002 // TODO: add fp16 framebuffer support
3004 r_view.showdebug = false;
3005 r_view.colorscale = r_bloom_colorscale.value * r_hdr_scenebrightness.value;
3007 r_view.colorscale /= r_hdr_range.value;
3008 r_waterstate.numwaterplanes = 0;
3009 R_RenderScene(r_waterstate.enabled);
3010 r_view.showdebug = true;
3012 R_ResetViewRendering2D();
3014 R_Bloom_CopyHDRTexture();
3015 R_Bloom_MakeTexture();
3017 R_ResetViewRendering3D();
3020 if (r_timereport_active)
3021 R_TimeReport("clear");
3024 // restore the view settings
3025 r_view.width = oldwidth;
3026 r_view.height = oldheight;
3029 static void R_BlendView(void)
3031 if (r_bloomstate.enabled && r_bloomstate.hdr)
3033 // render high dynamic range bloom effect
3034 // the bloom texture was made earlier this render, so we just need to
3035 // blend it onto the screen...
3036 R_ResetViewRendering2D();
3037 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
3038 R_Mesh_ColorPointer(NULL, 0, 0);
3039 GL_Color(1, 1, 1, 1);
3040 GL_BlendFunc(GL_ONE, GL_ONE);
3041 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
3042 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
3043 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3044 r_refdef.stats.bloom_drawpixels += r_view.width * r_view.height;
3046 else if (r_bloomstate.enabled)
3048 // render simple bloom effect
3049 // copy the screen and shrink it and darken it for the bloom process
3050 R_Bloom_CopyScreenTexture(r_bloom_colorscale.value);
3051 // make the bloom texture
3052 R_Bloom_MakeTexture();
3053 // put the original screen image back in place and blend the bloom
3055 R_ResetViewRendering2D();
3056 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
3057 R_Mesh_ColorPointer(NULL, 0, 0);
3058 GL_Color(1, 1, 1, 1);
3059 GL_BlendFunc(GL_ONE, GL_ZERO);
3060 // do both in one pass if possible
3061 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
3062 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
3063 if (r_textureunits.integer >= 2 && gl_combine.integer)
3065 R_Mesh_TexCombine(1, GL_ADD, GL_ADD, 1, 1);
3066 R_Mesh_TexBind(1, R_GetTexture(r_bloomstate.texture_screen));
3067 R_Mesh_TexCoordPointer(1, 2, r_bloomstate.screentexcoord2f, 0, 0);
3071 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3072 r_refdef.stats.bloom_drawpixels += r_view.width * r_view.height;
3073 // now blend on the bloom texture
3074 GL_BlendFunc(GL_ONE, GL_ONE);
3075 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
3076 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
3078 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3079 r_refdef.stats.bloom_drawpixels += r_view.width * r_view.height;
3081 if (r_refdef.viewblend[3] >= (1.0f / 256.0f))
3083 // apply a color tint to the whole view
3084 R_ResetViewRendering2D();
3085 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
3086 R_Mesh_ColorPointer(NULL, 0, 0);
3087 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3088 GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
3089 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3093 void R_RenderScene(qboolean addwaterplanes);
3095 matrix4x4_t r_waterscrollmatrix;
3097 void R_UpdateVariables(void)
3101 r_refdef.farclip = 4096;
3102 if (r_refdef.worldmodel)
3103 r_refdef.farclip += VectorDistance(r_refdef.worldmodel->normalmins, r_refdef.worldmodel->normalmaxs);
3104 r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
3106 if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
3107 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
3108 r_refdef.polygonfactor = 0;
3109 r_refdef.polygonoffset = 0;
3110 r_refdef.shadowpolygonfactor = r_refdef.polygonfactor + r_shadow_polygonfactor.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
3111 r_refdef.shadowpolygonoffset = r_refdef.polygonoffset + r_shadow_polygonoffset.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
3113 r_refdef.rtworld = r_shadow_realtime_world.integer;
3114 r_refdef.rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
3115 r_refdef.rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer && r_dynamic.integer;
3116 r_refdef.rtdlightshadows = r_refdef.rtdlight && r_shadow_realtime_dlight_shadows.integer && gl_stencil;
3117 r_refdef.lightmapintensity = r_refdef.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
3118 if (r_showsurfaces.integer)
3120 r_refdef.rtworld = false;
3121 r_refdef.rtworldshadows = false;
3122 r_refdef.rtdlight = false;
3123 r_refdef.rtdlightshadows = false;
3124 r_refdef.lightmapintensity = 0;
3127 if (gamemode == GAME_NEHAHRA)
3129 if (gl_fogenable.integer)
3131 r_refdef.oldgl_fogenable = true;
3132 r_refdef.fog_density = gl_fogdensity.value;
3133 r_refdef.fog_red = gl_fogred.value;
3134 r_refdef.fog_green = gl_foggreen.value;
3135 r_refdef.fog_blue = gl_fogblue.value;
3137 else if (r_refdef.oldgl_fogenable)
3139 r_refdef.oldgl_fogenable = false;
3140 r_refdef.fog_density = 0;
3141 r_refdef.fog_red = 0;
3142 r_refdef.fog_green = 0;
3143 r_refdef.fog_blue = 0;
3146 if (r_refdef.fog_density)
3148 r_refdef.fogcolor[0] = bound(0.0f, r_refdef.fog_red , 1.0f);
3149 r_refdef.fogcolor[1] = bound(0.0f, r_refdef.fog_green, 1.0f);
3150 r_refdef.fogcolor[2] = bound(0.0f, r_refdef.fog_blue , 1.0f);
3152 if (r_refdef.fog_density)
3154 r_refdef.fogenabled = true;
3155 // this is the point where the fog reaches 0.9986 alpha, which we
3156 // consider a good enough cutoff point for the texture
3157 // (0.9986 * 256 == 255.6)
3158 r_refdef.fogrange = 400 / r_refdef.fog_density;
3159 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
3160 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
3161 // fog color was already set
3164 r_refdef.fogenabled = false;
3172 void R_RenderView(void)
3174 if (!r_refdef.entities/* || !r_refdef.worldmodel*/)
3175 return; //Host_Error ("R_RenderView: NULL worldmodel");
3177 R_Shadow_UpdateWorldLightSelection();
3179 R_Bloom_StartFrame();
3180 R_Water_StartFrame();
3183 if (r_timereport_active)
3184 R_TimeReport("setup");
3186 R_ResetViewRendering3D();
3189 if (r_timereport_active)
3190 R_TimeReport("clear");
3192 r_view.showdebug = true;
3194 // this produces a bloom texture to be used in R_BlendView() later
3196 R_HDR_RenderBloomTexture();
3198 r_view.colorscale = r_hdr_scenebrightness.value;
3199 r_waterstate.numwaterplanes = 0;
3200 R_RenderScene(r_waterstate.enabled);
3203 if (r_timereport_active)
3204 R_TimeReport("blendview");
3206 GL_Scissor(0, 0, vid.width, vid.height);
3207 GL_ScissorTest(false);
3211 extern void R_DrawLightningBeams (void);
3212 extern void VM_CL_AddPolygonsToMeshQueue (void);
3213 extern void R_DrawPortals (void);
3214 extern cvar_t cl_locs_show;
3215 static void R_DrawLocs(void);
3216 static void R_DrawEntityBBoxes(void);
3217 void R_RenderScene(qboolean addwaterplanes)
3221 R_ResetViewRendering3D();
3224 if (r_timereport_active)
3225 R_TimeReport("watervisibility");
3227 if (cl.csqc_vidvars.drawworld && r_refdef.worldmodel && r_refdef.worldmodel->DrawAddWaterPlanes)
3229 r_refdef.worldmodel->DrawAddWaterPlanes(r_refdef.worldentity);
3230 if (r_timereport_active)
3231 R_TimeReport("waterworld");
3234 // don't let sound skip if going slow
3235 if (r_refdef.extraupdate)
3238 R_DrawModelsAddWaterPlanes();
3239 if (r_timereport_active)
3240 R_TimeReport("watermodels");
3242 R_Water_ProcessPlanes();
3243 if (r_timereport_active)
3244 R_TimeReport("waterscenes");
3247 R_ResetViewRendering3D();
3249 // don't let sound skip if going slow
3250 if (r_refdef.extraupdate)
3253 R_MeshQueue_BeginScene();
3258 if (r_timereport_active)
3259 R_TimeReport("visibility");
3261 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);
3263 if (cl.csqc_vidvars.drawworld)
3265 // don't let sound skip if going slow
3266 if (r_refdef.extraupdate)
3269 if (r_refdef.worldmodel && r_refdef.worldmodel->DrawSky)
3271 r_refdef.worldmodel->DrawSky(r_refdef.worldentity);
3272 if (r_timereport_active)
3273 R_TimeReport("worldsky");
3276 if (R_DrawBrushModelsSky() && r_timereport_active)
3277 R_TimeReport("bmodelsky");
3280 if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.worldmodel && r_refdef.worldmodel->DrawDepth)
3282 r_refdef.worldmodel->DrawDepth(r_refdef.worldentity);
3283 if (r_timereport_active)
3284 R_TimeReport("worlddepth");
3286 if (r_depthfirst.integer >= 2)
3288 R_DrawModelsDepth();
3289 if (r_timereport_active)
3290 R_TimeReport("modeldepth");
3293 if (cl.csqc_vidvars.drawworld && r_refdef.worldmodel && r_refdef.worldmodel->Draw)
3295 r_refdef.worldmodel->Draw(r_refdef.worldentity);
3296 if (r_timereport_active)
3297 R_TimeReport("world");
3300 // don't let sound skip if going slow
3301 if (r_refdef.extraupdate)
3305 if (r_timereport_active)
3306 R_TimeReport("models");
3308 // don't let sound skip if going slow
3309 if (r_refdef.extraupdate)
3312 if (r_shadows.integer > 0 && r_refdef.lightmapintensity > 0)
3314 R_DrawModelShadows();
3316 R_ResetViewRendering3D();
3318 // don't let sound skip if going slow
3319 if (r_refdef.extraupdate)
3323 R_ShadowVolumeLighting(false);
3324 if (r_timereport_active)
3325 R_TimeReport("rtlights");
3327 // don't let sound skip if going slow
3328 if (r_refdef.extraupdate)
3331 if (cl.csqc_vidvars.drawworld)
3333 R_DrawLightningBeams();
3334 if (r_timereport_active)
3335 R_TimeReport("lightning");
3338 if (r_timereport_active)
3339 R_TimeReport("particles");
3342 if (r_timereport_active)
3343 R_TimeReport("explosions");
3346 if (gl_support_fragment_shader)
3348 qglUseProgramObjectARB(0);CHECKGLERROR
3350 VM_CL_AddPolygonsToMeshQueue();
3352 if (r_view.showdebug)
3354 if (cl_locs_show.integer)
3357 if (r_timereport_active)
3358 R_TimeReport("showlocs");
3361 if (r_drawportals.integer)
3364 if (r_timereport_active)
3365 R_TimeReport("portals");
3368 if (r_showbboxes.value > 0)
3370 R_DrawEntityBBoxes();
3371 if (r_timereport_active)
3372 R_TimeReport("bboxes");
3376 if (gl_support_fragment_shader)
3378 qglUseProgramObjectARB(0);CHECKGLERROR
3380 R_MeshQueue_RenderTransparent();
3381 if (r_timereport_active)
3382 R_TimeReport("drawtrans");
3384 if (gl_support_fragment_shader)
3386 qglUseProgramObjectARB(0);CHECKGLERROR
3389 if (r_view.showdebug && r_refdef.worldmodel && r_refdef.worldmodel->DrawDebug && (r_showtris.value > 0 || r_shownormals.value > 0 || r_showcollisionbrushes.value > 0))
3391 r_refdef.worldmodel->DrawDebug(r_refdef.worldentity);
3392 if (r_timereport_active)
3393 R_TimeReport("worlddebug");
3394 R_DrawModelsDebug();
3395 if (r_timereport_active)
3396 R_TimeReport("modeldebug");
3399 if (gl_support_fragment_shader)
3401 qglUseProgramObjectARB(0);CHECKGLERROR
3404 if (cl.csqc_vidvars.drawworld)
3407 if (r_timereport_active)
3408 R_TimeReport("coronas");
3411 // don't let sound skip if going slow
3412 if (r_refdef.extraupdate)
3415 R_ResetViewRendering2D();
3418 static const int bboxelements[36] =
3428 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
3431 float *v, *c, f1, f2, vertex3f[8*3], color4f[8*4];
3432 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3433 GL_DepthMask(false);
3434 GL_DepthRange(0, 1);
3435 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
3436 R_Mesh_Matrix(&identitymatrix);
3437 R_Mesh_ResetTextureState();
3439 vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2]; //
3440 vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
3441 vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
3442 vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
3443 vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
3444 vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
3445 vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
3446 vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
3447 R_FillColors(color4f, 8, cr, cg, cb, ca);
3448 if (r_refdef.fogenabled)
3450 for (i = 0, v = vertex3f, c = color4f;i < 8;i++, v += 3, c += 4)
3452 f1 = FogPoint_World(v);
3454 c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
3455 c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
3456 c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
3459 R_Mesh_VertexPointer(vertex3f, 0, 0);
3460 R_Mesh_ColorPointer(color4f, 0, 0);
3461 R_Mesh_ResetTextureState();
3462 R_Mesh_Draw(0, 8, 12, bboxelements, 0, 0);
3465 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3469 prvm_edict_t *edict;
3470 // this function draws bounding boxes of server entities
3474 for (i = 0;i < numsurfaces;i++)
3476 edict = PRVM_EDICT_NUM(surfacelist[i]);
3477 switch ((int)edict->fields.server->solid)
3479 case SOLID_NOT: Vector4Set(color, 1, 1, 1, 0.05);break;
3480 case SOLID_TRIGGER: Vector4Set(color, 1, 0, 1, 0.10);break;
3481 case SOLID_BBOX: Vector4Set(color, 0, 1, 0, 0.10);break;
3482 case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
3483 case SOLID_BSP: Vector4Set(color, 0, 0, 1, 0.05);break;
3484 default: Vector4Set(color, 0, 0, 0, 0.50);break;
3486 color[3] *= r_showbboxes.value;
3487 color[3] = bound(0, color[3], 1);
3488 GL_DepthTest(!r_showdisabledepthtest.integer);
3489 GL_CullFace(r_view.cullface_front);
3490 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
3495 static void R_DrawEntityBBoxes(void)
3498 prvm_edict_t *edict;
3500 // this function draws bounding boxes of server entities
3504 for (i = 0;i < prog->num_edicts;i++)
3506 edict = PRVM_EDICT_NUM(i);
3507 if (edict->priv.server->free)
3509 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
3510 R_MeshQueue_AddTransparent(center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)NULL);
3515 int nomodelelements[24] =
3527 float nomodelvertex3f[6*3] =
3537 float nomodelcolor4f[6*4] =
3539 0.0f, 0.0f, 0.5f, 1.0f,
3540 0.0f, 0.0f, 0.5f, 1.0f,
3541 0.0f, 0.5f, 0.0f, 1.0f,
3542 0.0f, 0.5f, 0.0f, 1.0f,
3543 0.5f, 0.0f, 0.0f, 1.0f,
3544 0.5f, 0.0f, 0.0f, 1.0f
3547 void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
3552 // this is only called once per entity so numsurfaces is always 1, and
3553 // surfacelist is always {0}, so this code does not handle batches
3554 R_Mesh_Matrix(&ent->matrix);
3556 if (ent->flags & EF_ADDITIVE)
3558 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
3559 GL_DepthMask(false);
3561 else if (ent->alpha < 1)
3563 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3564 GL_DepthMask(false);
3568 GL_BlendFunc(GL_ONE, GL_ZERO);
3571 GL_DepthRange(0, (ent->flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
3572 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
3573 GL_DepthTest(!(ent->effects & EF_NODEPTHTEST));
3574 GL_CullFace((ent->effects & EF_DOUBLESIDED) ? GL_NONE : r_view.cullface_back);
3575 R_Mesh_VertexPointer(nomodelvertex3f, 0, 0);
3576 if (r_refdef.fogenabled)
3579 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
3580 R_Mesh_ColorPointer(color4f, 0, 0);
3581 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3582 f1 = FogPoint_World(org);
3584 for (i = 0, c = color4f;i < 6;i++, c += 4)
3586 c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
3587 c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
3588 c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
3592 else if (ent->alpha != 1)
3594 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
3595 R_Mesh_ColorPointer(color4f, 0, 0);
3596 for (i = 0, c = color4f;i < 6;i++, c += 4)
3600 R_Mesh_ColorPointer(nomodelcolor4f, 0, 0);
3601 R_Mesh_ResetTextureState();
3602 R_Mesh_Draw(0, 6, 8, nomodelelements, 0, 0);
3605 void R_DrawNoModel(entity_render_t *ent)
3608 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3609 //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
3610 R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_view.origin : org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
3612 // R_DrawNoModelCallback(ent, 0);
3615 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
3617 vec3_t right1, right2, diff, normal;
3619 VectorSubtract (org2, org1, normal);
3621 // calculate 'right' vector for start
3622 VectorSubtract (r_view.origin, org1, diff);
3623 CrossProduct (normal, diff, right1);
3624 VectorNormalize (right1);
3626 // calculate 'right' vector for end
3627 VectorSubtract (r_view.origin, org2, diff);
3628 CrossProduct (normal, diff, right2);
3629 VectorNormalize (right2);
3631 vert[ 0] = org1[0] + width * right1[0];
3632 vert[ 1] = org1[1] + width * right1[1];
3633 vert[ 2] = org1[2] + width * right1[2];
3634 vert[ 3] = org1[0] - width * right1[0];
3635 vert[ 4] = org1[1] - width * right1[1];
3636 vert[ 5] = org1[2] - width * right1[2];
3637 vert[ 6] = org2[0] - width * right2[0];
3638 vert[ 7] = org2[1] - width * right2[1];
3639 vert[ 8] = org2[2] - width * right2[2];
3640 vert[ 9] = org2[0] + width * right2[0];
3641 vert[10] = org2[1] + width * right2[1];
3642 vert[11] = org2[2] + width * right2[2];
3645 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
3647 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)
3652 if (r_refdef.fogenabled)
3653 fog = FogPoint_World(origin);
3655 R_Mesh_Matrix(&identitymatrix);
3656 GL_BlendFunc(blendfunc1, blendfunc2);
3662 GL_CullFace(r_view.cullface_front);
3665 GL_CullFace(r_view.cullface_back);
3667 GL_DepthMask(false);
3668 GL_DepthRange(0, depthshort ? 0.0625 : 1);
3669 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
3670 GL_DepthTest(!depthdisable);
3672 vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
3673 vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
3674 vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
3675 vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
3676 vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
3677 vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
3678 vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
3679 vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
3680 vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
3681 vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
3682 vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
3683 vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
3685 R_Mesh_VertexPointer(vertex3f, 0, 0);
3686 R_Mesh_ColorPointer(NULL, 0, 0);
3687 R_Mesh_ResetTextureState();
3688 R_Mesh_TexBind(0, R_GetTexture(texture));
3689 R_Mesh_TexCoordPointer(0, 2, spritetexcoord2f, 0, 0);
3690 // FIXME: fixed function path can't properly handle r_view.colorscale > 1
3691 GL_Color(cr * fog * r_view.colorscale, cg * fog * r_view.colorscale, cb * fog * r_view.colorscale, ca);
3692 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3694 if (blendfunc2 == GL_ONE_MINUS_SRC_ALPHA)
3696 R_Mesh_TexBind(0, R_GetTexture(fogtexture));
3697 GL_BlendFunc(blendfunc1, GL_ONE);
3699 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);
3700 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3704 int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
3709 VectorSet(v, x, y, z);
3710 for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
3711 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
3713 if (i == mesh->numvertices)
3715 if (mesh->numvertices < mesh->maxvertices)
3717 VectorCopy(v, vertex3f);
3718 mesh->numvertices++;
3720 return mesh->numvertices;
3726 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
3730 element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
3731 element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
3732 e = mesh->element3i + mesh->numtriangles * 3;
3733 for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
3735 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
3736 if (mesh->numtriangles < mesh->maxtriangles)
3741 mesh->numtriangles++;
3743 element[1] = element[2];
3747 void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
3751 element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
3752 element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
3753 e = mesh->element3i + mesh->numtriangles * 3;
3754 for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
3756 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
3757 if (mesh->numtriangles < mesh->maxtriangles)
3762 mesh->numtriangles++;
3764 element[1] = element[2];
3768 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
3769 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
3771 int planenum, planenum2;
3774 mplane_t *plane, *plane2;
3776 double temppoints[2][256*3];
3777 // figure out how large a bounding box we need to properly compute this brush
3779 for (w = 0;w < numplanes;w++)
3780 maxdist = max(maxdist, planes[w].dist);
3781 // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
3782 maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
3783 for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
3787 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
3788 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
3790 if (planenum2 == planenum)
3792 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);
3795 if (tempnumpoints < 3)
3797 // generate elements forming a triangle fan for this polygon
3798 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
3802 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)
3804 texturelayer_t *layer;
3805 layer = t->currentlayers + t->currentnumlayers++;
3807 layer->depthmask = depthmask;
3808 layer->blendfunc1 = blendfunc1;
3809 layer->blendfunc2 = blendfunc2;
3810 layer->texture = texture;
3811 layer->texmatrix = *matrix;
3812 layer->color[0] = r * r_view.colorscale;
3813 layer->color[1] = g * r_view.colorscale;
3814 layer->color[2] = b * r_view.colorscale;
3815 layer->color[3] = a;
3818 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
3821 index = parms[2] + r_refdef.time * parms[3];
3822 index -= floor(index);
3826 case Q3WAVEFUNC_NONE:
3827 case Q3WAVEFUNC_NOISE:
3828 case Q3WAVEFUNC_COUNT:
3831 case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
3832 case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
3833 case Q3WAVEFUNC_SAWTOOTH: f = index;break;
3834 case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
3835 case Q3WAVEFUNC_TRIANGLE:
3837 f = index - floor(index);
3848 return (float)(parms[0] + parms[1] * f);
3851 void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t)
3854 model_t *model = ent->model;
3857 q3shaderinfo_layer_tcmod_t *tcmod;
3859 // switch to an alternate material if this is a q1bsp animated material
3861 texture_t *texture = t;
3862 int s = ent->skinnum;
3863 if ((unsigned int)s >= (unsigned int)model->numskins)
3865 if (model->skinscenes)
3867 if (model->skinscenes[s].framecount > 1)
3868 s = model->skinscenes[s].firstframe + (unsigned int) (r_refdef.time * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
3870 s = model->skinscenes[s].firstframe;
3873 t = t + s * model->num_surfaces;
3876 // use an alternate animation if the entity's frame is not 0,
3877 // and only if the texture has an alternate animation
3878 if (ent->frame2 != 0 && t->anim_total[1])
3879 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(r_refdef.time * 5.0f) % t->anim_total[1]) : 0];
3881 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(r_refdef.time * 5.0f) % t->anim_total[0]) : 0];
3883 texture->currentframe = t;
3886 // update currentskinframe to be a qw skin or animation frame
3887 if ((i = ent->entitynumber - 1) >= 0 && i < cl.maxclients)
3889 if (strcmp(r_qwskincache[i], cl.scores[i].qw_skin))
3891 strlcpy(r_qwskincache[i], cl.scores[i].qw_skin, sizeof(r_qwskincache[i]));
3892 Con_DPrintf("loading skins/%s\n", r_qwskincache[i]);
3893 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);
3895 t->currentskinframe = r_qwskincache_skinframe[i];
3896 if (t->currentskinframe == NULL)
3897 t->currentskinframe = t->skinframes[(int)(t->skinframerate * (cl.time - ent->frame2time)) % t->numskinframes];
3899 else if (t->numskinframes >= 2)
3900 t->currentskinframe = t->skinframes[(int)(t->skinframerate * (cl.time - ent->frame2time)) % t->numskinframes];
3901 if (t->backgroundnumskinframes >= 2)
3902 t->backgroundcurrentskinframe = t->backgroundskinframes[(int)(t->backgroundskinframerate * (cl.time - ent->frame2time)) % t->backgroundnumskinframes];
3904 t->currentmaterialflags = t->basematerialflags;
3905 t->currentalpha = ent->alpha;
3906 if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_novis.integer))
3908 t->currentalpha *= r_wateralpha.value;
3910 * FIXME what is this supposed to do?
3911 // if rendering refraction/reflection, disable transparency
3912 if (r_waterstate.enabled && (t->currentalpha < 1 || (t->currentmaterialflags & MATERIALFLAG_ALPHA)))
3913 t->currentmaterialflags |= MATERIALFLAG_WATERSHADER;
3916 if(!r_waterstate.enabled)
3917 t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION);
3918 if (!(ent->flags & RENDER_LIGHT))
3919 t->currentmaterialflags |= MATERIALFLAG_FULLBRIGHT;
3920 if (ent->effects & EF_ADDITIVE)
3921 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
3922 else if (t->currentalpha < 1)
3923 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
3924 if (ent->effects & EF_DOUBLESIDED)
3925 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
3926 if (ent->effects & EF_NODEPTHTEST)
3927 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
3928 if (ent->flags & RENDER_VIEWMODEL)
3929 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
3930 if (t->backgroundnumskinframes && !(t->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED))
3931 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
3932 if (t->currentmaterialflags & MATERIALFLAG_WATERSHADER)
3933 t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_CUSTOMBLEND);
3935 for (i = 0, tcmod = t->tcmods;i < Q3MAXTCMODS && (tcmod->tcmod || i < 1);i++, tcmod++)
3938 switch(tcmod->tcmod)
3942 if (t->currentmaterialflags & MATERIALFLAG_WATER && r_waterscroll.value != 0)
3943 matrix = r_waterscrollmatrix;
3945 matrix = identitymatrix;
3947 case Q3TCMOD_ENTITYTRANSLATE:
3948 // this is used in Q3 to allow the gamecode to control texcoord
3949 // scrolling on the entity, which is not supported in darkplaces yet.
3950 Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
3952 case Q3TCMOD_ROTATE:
3953 Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
3954 Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * r_refdef.time, 0, 0, 1);
3955 Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
3958 Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
3960 case Q3TCMOD_SCROLL:
3961 Matrix4x4_CreateTranslate(&matrix, tcmod->parms[0] * r_refdef.time, tcmod->parms[1] * r_refdef.time, 0);
3963 case Q3TCMOD_STRETCH:
3964 f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
3965 Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
3967 case Q3TCMOD_TRANSFORM:
3968 VectorSet(tcmat + 0, tcmod->parms[0], tcmod->parms[1], 0);
3969 VectorSet(tcmat + 3, tcmod->parms[2], tcmod->parms[3], 0);
3970 VectorSet(tcmat + 6, 0 , 0 , 1);
3971 VectorSet(tcmat + 9, tcmod->parms[4], tcmod->parms[5], 0);
3972 Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
3974 case Q3TCMOD_TURBULENT:
3975 // this is handled in the RSurf_PrepareVertices function
3976 matrix = identitymatrix;
3979 // either replace or concatenate the transformation
3981 t->currenttexmatrix = matrix;
3984 matrix4x4_t temp = t->currenttexmatrix;
3985 Matrix4x4_Concat(&t->currenttexmatrix, &matrix, &temp);
3989 t->colormapping = VectorLength2(ent->colormap_pantscolor) + VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f);
3990 t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
3991 t->glosstexture = r_texture_black;
3992 t->backgroundbasetexture = t->backgroundnumskinframes ? ((!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base) : r_texture_white;
3993 t->backgroundglosstexture = r_texture_black;
3994 t->specularpower = r_shadow_glossexponent.value;
3995 // TODO: store reference values for these in the texture?
3996 t->specularscale = 0;
3997 if (r_shadow_gloss.integer > 0)
3999 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
4001 if (r_shadow_glossintensity.value > 0)
4003 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
4004 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
4005 t->specularscale = r_shadow_glossintensity.value;
4008 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
4010 t->glosstexture = r_texture_white;
4011 t->backgroundglosstexture = r_texture_white;
4012 t->specularscale = r_shadow_gloss2intensity.value;
4016 // lightmaps mode looks bad with dlights using actual texturing, so turn
4017 // off the colormap and glossmap, but leave the normalmap on as it still
4018 // accurately represents the shading involved
4019 if (gl_lightmaps.integer && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
4021 t->basetexture = r_texture_white;
4022 t->specularscale = 0;
4025 t->currentpolygonfactor = r_refdef.polygonfactor + t->basepolygonfactor;
4026 t->currentpolygonoffset = r_refdef.polygonoffset + t->basepolygonoffset;
4027 // submodels are biased to avoid z-fighting with world surfaces that they
4028 // may be exactly overlapping (avoids z-fighting artifacts on certain
4029 // doors and things in Quake maps)
4030 if (ent->model->brush.submodel)
4032 t->currentpolygonfactor += r_polygonoffset_submodel_factor.value;
4033 t->currentpolygonoffset += r_polygonoffset_submodel_offset.value;
4036 VectorClear(t->dlightcolor);
4037 t->currentnumlayers = 0;
4038 if (!(t->currentmaterialflags & MATERIALFLAG_NODRAW))
4040 if (!(t->currentmaterialflags & MATERIALFLAG_SKY))
4042 int blendfunc1, blendfunc2, depthmask;
4043 if (t->currentmaterialflags & MATERIALFLAG_ADD)
4045 blendfunc1 = GL_SRC_ALPHA;
4046 blendfunc2 = GL_ONE;
4048 else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
4050 blendfunc1 = GL_SRC_ALPHA;
4051 blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
4053 else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
4055 blendfunc1 = t->customblendfunc[0];
4056 blendfunc2 = t->customblendfunc[1];
4060 blendfunc1 = GL_ONE;
4061 blendfunc2 = GL_ZERO;
4063 depthmask = !(t->currentmaterialflags & MATERIALFLAG_BLENDED);
4064 if (t->currentmaterialflags & (MATERIALFLAG_WATER | MATERIALFLAG_WALL))
4066 rtexture_t *currentbasetexture;
4068 if (r_refdef.fogenabled && (t->currentmaterialflags & MATERIALFLAG_BLENDED))
4069 layerflags |= TEXTURELAYERFLAG_FOGDARKEN;
4070 currentbasetexture = (VectorLength2(ent->colormap_pantscolor) + VectorLength2(ent->colormap_shirtcolor) < (1.0f / 1048576.0f) && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
4071 if (t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
4073 // fullbright is not affected by r_refdef.lightmapintensity
4074 R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_TEXTURE, currentbasetexture, &t->currenttexmatrix, ent->colormod[0], ent->colormod[1], ent->colormod[2], t->currentalpha);
4075 if (VectorLength2(ent->colormap_pantscolor) >= (1.0f / 1048576.0f) && t->currentskinframe->pants)
4076 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);
4077 if (VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->currentskinframe->shirt)
4078 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);
4083 // set the color tint used for lights affecting this surface
4084 VectorSet(t->dlightcolor, ent->colormod[0] * t->currentalpha, ent->colormod[1] * t->currentalpha, ent->colormod[2] * t->currentalpha);
4086 // q3bsp has no lightmap updates, so the lightstylevalue that
4087 // would normally be baked into the lightmap must be
4088 // applied to the color
4089 // FIXME: r_glsl 1 rendering doesn't support overbright lightstyles with this (the default light style is not overbright)
4090 if (ent->model->type == mod_brushq3)
4091 colorscale *= r_refdef.lightstylevalue[0] * (1.0f / 256.0f);
4092 colorscale *= r_refdef.lightmapintensity;
4093 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);
4094 if (r_ambient.value >= (1.0f/64.0f))
4095 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);
4096 if (VectorLength2(ent->colormap_pantscolor) >= (1.0f / 1048576.0f) && t->currentskinframe->pants)
4098 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);
4099 if (r_ambient.value >= (1.0f/64.0f))
4100 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);
4102 if (VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->currentskinframe->shirt)
4104 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);
4105 if (r_ambient.value >= (1.0f/64.0f))
4106 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);
4109 if (t->currentskinframe->glow != NULL)
4110 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);
4111 if (r_refdef.fogenabled && !(t->currentmaterialflags & MATERIALFLAG_ADD))
4113 // if this is opaque use alpha blend which will darken the earlier
4116 // if this is an alpha blended material, all the earlier passes
4117 // were darkened by fog already, so we only need to add the fog
4118 // color ontop through the fog mask texture
4120 // if this is an additive blended material, all the earlier passes
4121 // were darkened by fog already, and we should not add fog color
4122 // (because the background was not darkened, there is no fog color
4123 // that was lost behind it).
4124 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);
4131 void R_UpdateAllTextureInfo(entity_render_t *ent)
4135 for (i = 0;i < ent->model->num_texturesperskin;i++)
4136 R_UpdateTextureInfo(ent, ent->model->data_textures + i);
4139 rsurfacestate_t rsurface;
4141 void R_Mesh_ResizeArrays(int newvertices)
4144 if (rsurface.array_size >= newvertices)
4146 if (rsurface.array_modelvertex3f)
4147 Mem_Free(rsurface.array_modelvertex3f);
4148 rsurface.array_size = (newvertices + 1023) & ~1023;
4149 base = (float *)Mem_Alloc(r_main_mempool, rsurface.array_size * sizeof(float[33]));
4150 rsurface.array_modelvertex3f = base + rsurface.array_size * 0;
4151 rsurface.array_modelsvector3f = base + rsurface.array_size * 3;
4152 rsurface.array_modeltvector3f = base + rsurface.array_size * 6;
4153 rsurface.array_modelnormal3f = base + rsurface.array_size * 9;
4154 rsurface.array_deformedvertex3f = base + rsurface.array_size * 12;
4155 rsurface.array_deformedsvector3f = base + rsurface.array_size * 15;
4156 rsurface.array_deformedtvector3f = base + rsurface.array_size * 18;
4157 rsurface.array_deformednormal3f = base + rsurface.array_size * 21;
4158 rsurface.array_texcoord3f = base + rsurface.array_size * 24;
4159 rsurface.array_color4f = base + rsurface.array_size * 27;
4160 rsurface.array_generatedtexcoordtexture2f = base + rsurface.array_size * 31;
4163 void RSurf_CleanUp(void)
4166 if (rsurface.mode == RSURFMODE_GLSL)
4168 qglUseProgramObjectARB(0);CHECKGLERROR
4170 GL_AlphaTest(false);
4171 rsurface.mode = RSURFMODE_NONE;
4172 rsurface.uselightmaptexture = false;
4173 rsurface.texture = NULL;
4176 void RSurf_ActiveWorldEntity(void)
4178 model_t *model = r_refdef.worldmodel;
4180 if (rsurface.array_size < model->surfmesh.num_vertices)
4181 R_Mesh_ResizeArrays(model->surfmesh.num_vertices);
4182 rsurface.matrix = identitymatrix;
4183 rsurface.inversematrix = identitymatrix;
4184 R_Mesh_Matrix(&identitymatrix);
4185 VectorCopy(r_view.origin, rsurface.modelorg);
4186 VectorSet(rsurface.modellight_ambient, 0, 0, 0);
4187 VectorSet(rsurface.modellight_diffuse, 0, 0, 0);
4188 VectorSet(rsurface.modellight_lightdir, 0, 0, 1);
4189 VectorSet(rsurface.colormap_pantscolor, 0, 0, 0);
4190 VectorSet(rsurface.colormap_shirtcolor, 0, 0, 0);
4191 rsurface.frameblend[0].frame = 0;
4192 rsurface.frameblend[0].lerp = 1;
4193 rsurface.frameblend[1].frame = 0;
4194 rsurface.frameblend[1].lerp = 0;
4195 rsurface.frameblend[2].frame = 0;
4196 rsurface.frameblend[2].lerp = 0;
4197 rsurface.frameblend[3].frame = 0;
4198 rsurface.frameblend[3].lerp = 0;
4199 rsurface.modelvertex3f = model->surfmesh.data_vertex3f;
4200 rsurface.modelvertex3f_bufferobject = model->surfmesh.vbo;
4201 rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f;
4202 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
4203 rsurface.modelsvector3f_bufferobject = model->surfmesh.vbo;
4204 rsurface.modelsvector3f_bufferoffset = model->surfmesh.vbooffset_svector3f;
4205 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
4206 rsurface.modeltvector3f_bufferobject = model->surfmesh.vbo;
4207 rsurface.modeltvector3f_bufferoffset = model->surfmesh.vbooffset_tvector3f;
4208 rsurface.modelnormal3f = model->surfmesh.data_normal3f;
4209 rsurface.modelnormal3f_bufferobject = model->surfmesh.vbo;
4210 rsurface.modelnormal3f_bufferoffset = model->surfmesh.vbooffset_normal3f;
4211 rsurface.modellightmapcolor4f = model->surfmesh.data_lightmapcolor4f;
4212 rsurface.modellightmapcolor4f_bufferobject = model->surfmesh.vbo;
4213 rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.vbooffset_lightmapcolor4f;
4214 rsurface.modeltexcoordtexture2f = model->surfmesh.data_texcoordtexture2f;
4215 rsurface.modeltexcoordtexture2f_bufferobject = model->surfmesh.vbo;
4216 rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.vbooffset_texcoordtexture2f;
4217 rsurface.modeltexcoordlightmap2f = model->surfmesh.data_texcoordlightmap2f;
4218 rsurface.modeltexcoordlightmap2f_bufferobject = model->surfmesh.vbo;
4219 rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f;
4220 rsurface.modelelement3i = model->surfmesh.data_element3i;
4221 rsurface.modelelement3i_bufferobject = model->surfmesh.ebo;
4222 rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
4223 rsurface.modelnum_vertices = model->surfmesh.num_vertices;
4224 rsurface.modelnum_triangles = model->surfmesh.num_triangles;
4225 rsurface.modelsurfaces = model->data_surfaces;
4226 rsurface.generatedvertex = false;
4227 rsurface.vertex3f = rsurface.modelvertex3f;
4228 rsurface.vertex3f_bufferobject = rsurface.modelvertex3f_bufferobject;
4229 rsurface.vertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
4230 rsurface.svector3f = rsurface.modelsvector3f;
4231 rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject;
4232 rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
4233 rsurface.tvector3f = rsurface.modeltvector3f;
4234 rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject;
4235 rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
4236 rsurface.normal3f = rsurface.modelnormal3f;
4237 rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject;
4238 rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
4239 rsurface.texcoordtexture2f = rsurface.modeltexcoordtexture2f;
4242 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
4244 model_t *model = ent->model;
4246 if (rsurface.array_size < model->surfmesh.num_vertices)
4247 R_Mesh_ResizeArrays(model->surfmesh.num_vertices);
4248 rsurface.matrix = ent->matrix;
4249 rsurface.inversematrix = ent->inversematrix;
4250 R_Mesh_Matrix(&rsurface.matrix);
4251 Matrix4x4_Transform(&rsurface.inversematrix, r_view.origin, rsurface.modelorg);
4252 VectorCopy(ent->modellight_ambient, rsurface.modellight_ambient);
4253 VectorCopy(ent->modellight_diffuse, rsurface.modellight_diffuse);
4254 VectorCopy(ent->modellight_lightdir, rsurface.modellight_lightdir);
4255 VectorCopy(ent->colormap_pantscolor, rsurface.colormap_pantscolor);
4256 VectorCopy(ent->colormap_shirtcolor, rsurface.colormap_shirtcolor);
4257 rsurface.frameblend[0] = ent->frameblend[0];
4258 rsurface.frameblend[1] = ent->frameblend[1];
4259 rsurface.frameblend[2] = ent->frameblend[2];
4260 rsurface.frameblend[3] = ent->frameblend[3];
4261 if (model->surfmesh.isanimated && (rsurface.frameblend[0].lerp != 1 || rsurface.frameblend[0].frame != 0))
4265 rsurface.modelvertex3f = rsurface.array_modelvertex3f;
4266 rsurface.modelsvector3f = rsurface.array_modelsvector3f;
4267 rsurface.modeltvector3f = rsurface.array_modeltvector3f;
4268 rsurface.modelnormal3f = rsurface.array_modelnormal3f;
4269 Mod_Alias_GetMesh_Vertices(model, rsurface.frameblend, rsurface.array_modelvertex3f, rsurface.array_modelnormal3f, rsurface.array_modelsvector3f, rsurface.array_modeltvector3f);
4271 else if (wantnormals)
4273 rsurface.modelvertex3f = rsurface.array_modelvertex3f;
4274 rsurface.modelsvector3f = NULL;
4275 rsurface.modeltvector3f = NULL;
4276 rsurface.modelnormal3f = rsurface.array_modelnormal3f;
4277 Mod_Alias_GetMesh_Vertices(model, rsurface.frameblend, rsurface.array_modelvertex3f, rsurface.array_modelnormal3f, NULL, NULL);
4281 rsurface.modelvertex3f = rsurface.array_modelvertex3f;
4282 rsurface.modelsvector3f = NULL;
4283 rsurface.modeltvector3f = NULL;
4284 rsurface.modelnormal3f = NULL;
4285 Mod_Alias_GetMesh_Vertices(model, rsurface.frameblend, rsurface.array_modelvertex3f, NULL, NULL, NULL);
4287 rsurface.modelvertex3f_bufferobject = 0;
4288 rsurface.modelvertex3f_bufferoffset = 0;
4289 rsurface.modelsvector3f_bufferobject = 0;
4290 rsurface.modelsvector3f_bufferoffset = 0;
4291 rsurface.modeltvector3f_bufferobject = 0;
4292 rsurface.modeltvector3f_bufferoffset = 0;
4293 rsurface.modelnormal3f_bufferobject = 0;
4294 rsurface.modelnormal3f_bufferoffset = 0;
4295 rsurface.generatedvertex = true;
4299 rsurface.modelvertex3f = model->surfmesh.data_vertex3f;
4300 rsurface.modelvertex3f_bufferobject = model->surfmesh.vbo;
4301 rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f;
4302 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
4303 rsurface.modelsvector3f_bufferobject = model->surfmesh.vbo;
4304 rsurface.modelsvector3f_bufferoffset = model->surfmesh.vbooffset_svector3f;
4305 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
4306 rsurface.modeltvector3f_bufferobject = model->surfmesh.vbo;
4307 rsurface.modeltvector3f_bufferoffset = model->surfmesh.vbooffset_tvector3f;
4308 rsurface.modelnormal3f = model->surfmesh.data_normal3f;
4309 rsurface.modelnormal3f_bufferobject = model->surfmesh.vbo;
4310 rsurface.modelnormal3f_bufferoffset = model->surfmesh.vbooffset_normal3f;
4311 rsurface.generatedvertex = false;
4313 rsurface.modellightmapcolor4f = model->surfmesh.data_lightmapcolor4f;
4314 rsurface.modellightmapcolor4f_bufferobject = model->surfmesh.vbo;
4315 rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.vbooffset_lightmapcolor4f;
4316 rsurface.modeltexcoordtexture2f = model->surfmesh.data_texcoordtexture2f;
4317 rsurface.modeltexcoordtexture2f_bufferobject = model->surfmesh.vbo;
4318 rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.vbooffset_texcoordtexture2f;
4319 rsurface.modeltexcoordlightmap2f = model->surfmesh.data_texcoordlightmap2f;
4320 rsurface.modeltexcoordlightmap2f_bufferobject = model->surfmesh.vbo;
4321 rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f;
4322 rsurface.modelelement3i = model->surfmesh.data_element3i;
4323 rsurface.modelelement3i_bufferobject = model->surfmesh.ebo;
4324 rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
4325 rsurface.modelnum_vertices = model->surfmesh.num_vertices;
4326 rsurface.modelnum_triangles = model->surfmesh.num_triangles;
4327 rsurface.modelsurfaces = model->data_surfaces;
4328 rsurface.vertex3f = rsurface.modelvertex3f;
4329 rsurface.vertex3f_bufferobject = rsurface.modelvertex3f_bufferobject;
4330 rsurface.vertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
4331 rsurface.svector3f = rsurface.modelsvector3f;
4332 rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject;
4333 rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
4334 rsurface.tvector3f = rsurface.modeltvector3f;
4335 rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject;
4336 rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
4337 rsurface.normal3f = rsurface.modelnormal3f;
4338 rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject;
4339 rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
4340 rsurface.texcoordtexture2f = rsurface.modeltexcoordtexture2f;
4343 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
4344 void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generatetangents, int texturenumsurfaces, msurface_t **texturesurfacelist)
4347 int texturesurfaceindex;
4352 const float *v1, *in_tc;
4354 float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
4356 q3shaderinfo_deform_t *deform;
4357 // 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
4358 if (rsurface.generatedvertex)
4360 if (rsurface.texture->tcgen.tcgen == Q3TCGEN_ENVIRONMENT)
4361 generatenormals = true;
4362 for (i = 0;i < Q3MAXDEFORMS;i++)
4364 if (rsurface.texture->deforms[i].deform == Q3DEFORM_AUTOSPRITE)
4366 generatetangents = true;
4367 generatenormals = true;
4369 if (rsurface.texture->deforms[i].deform != Q3DEFORM_NONE)
4370 generatenormals = true;
4372 if (generatenormals && !rsurface.modelnormal3f)
4374 rsurface.normal3f = rsurface.modelnormal3f = rsurface.array_modelnormal3f;
4375 rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject = 0;
4376 rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset = 0;
4377 Mod_BuildNormals(0, rsurface.modelnum_vertices, rsurface.modelnum_triangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.array_modelnormal3f, r_smoothnormals_areaweighting.integer);
4379 if (generatetangents && !rsurface.modelsvector3f)
4381 rsurface.svector3f = rsurface.modelsvector3f = rsurface.array_modelsvector3f;
4382 rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject = 0;
4383 rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset = 0;
4384 rsurface.tvector3f = rsurface.modeltvector3f = rsurface.array_modeltvector3f;
4385 rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject = 0;
4386 rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset = 0;
4387 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);
4390 rsurface.vertex3f = rsurface.modelvertex3f;
4391 rsurface.vertex3f_bufferobject = rsurface.modelvertex3f_bufferobject;
4392 rsurface.vertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
4393 rsurface.svector3f = rsurface.modelsvector3f;
4394 rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject;
4395 rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
4396 rsurface.tvector3f = rsurface.modeltvector3f;
4397 rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject;
4398 rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
4399 rsurface.normal3f = rsurface.modelnormal3f;
4400 rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject;
4401 rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
4402 // if vertices are deformed (sprite flares and things in maps, possibly
4403 // water waves, bulges and other deformations), generate them into
4404 // rsurface.deform* arrays from whatever the rsurface.* arrays point to
4405 // (may be static model data or generated data for an animated model, or
4406 // the previous deform pass)
4407 for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform;deformindex++, deform++)
4409 switch (deform->deform)
4412 case Q3DEFORM_PROJECTIONSHADOW:
4413 case Q3DEFORM_TEXT0:
4414 case Q3DEFORM_TEXT1:
4415 case Q3DEFORM_TEXT2:
4416 case Q3DEFORM_TEXT3:
4417 case Q3DEFORM_TEXT4:
4418 case Q3DEFORM_TEXT5:
4419 case Q3DEFORM_TEXT6:
4420 case Q3DEFORM_TEXT7:
4423 case Q3DEFORM_AUTOSPRITE:
4424 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.forward, newforward);
4425 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.right, newright);
4426 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.up, newup);
4427 VectorNormalize(newforward);
4428 VectorNormalize(newright);
4429 VectorNormalize(newup);
4430 // make deformed versions of only the model vertices used by the specified surfaces
4431 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4433 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4434 // a single autosprite surface can contain multiple sprites...
4435 for (j = 0;j < surface->num_vertices - 3;j += 4)
4437 VectorClear(center);
4438 for (i = 0;i < 4;i++)
4439 VectorAdd(center, (rsurface.vertex3f + 3 * surface->num_firstvertex) + (j+i) * 3, center);
4440 VectorScale(center, 0.25f, center);
4441 VectorCopy((rsurface.normal3f + 3 * surface->num_firstvertex) + j*3, forward);
4442 VectorCopy((rsurface.svector3f + 3 * surface->num_firstvertex) + j*3, right);
4443 VectorCopy((rsurface.tvector3f + 3 * surface->num_firstvertex) + j*3, up);
4444 for (i = 0;i < 4;i++)
4446 VectorSubtract((rsurface.vertex3f + 3 * surface->num_firstvertex) + (j+i)*3, center, v);
4447 VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.array_deformedvertex3f + (surface->num_firstvertex+i+j) * 3);
4450 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);
4451 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);
4453 rsurface.vertex3f = rsurface.array_deformedvertex3f;
4454 rsurface.vertex3f_bufferobject = 0;
4455 rsurface.vertex3f_bufferoffset = 0;
4456 rsurface.svector3f = rsurface.array_deformedsvector3f;
4457 rsurface.svector3f_bufferobject = 0;
4458 rsurface.svector3f_bufferoffset = 0;
4459 rsurface.tvector3f = rsurface.array_deformedtvector3f;
4460 rsurface.tvector3f_bufferobject = 0;
4461 rsurface.tvector3f_bufferoffset = 0;
4462 rsurface.normal3f = rsurface.array_deformednormal3f;
4463 rsurface.normal3f_bufferobject = 0;
4464 rsurface.normal3f_bufferoffset = 0;
4466 case Q3DEFORM_AUTOSPRITE2:
4467 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.forward, newforward);
4468 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.right, newright);
4469 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.up, newup);
4470 VectorNormalize(newforward);
4471 VectorNormalize(newright);
4472 VectorNormalize(newup);
4473 // make deformed versions of only the model vertices used by the specified surfaces
4474 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4476 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4477 const float *v1, *v2;
4487 memset(shortest, 0, sizeof(shortest));
4488 // a single autosprite surface can contain multiple sprites...
4489 for (j = 0;j < surface->num_vertices - 3;j += 4)
4491 VectorClear(center);
4492 for (i = 0;i < 4;i++)
4493 VectorAdd(center, (rsurface.vertex3f + 3 * surface->num_firstvertex) + (j+i) * 3, center);
4494 VectorScale(center, 0.25f, center);
4495 // find the two shortest edges, then use them to define the
4496 // axis vectors for rotating around the central axis
4497 for (i = 0;i < 6;i++)
4499 v1 = rsurface.vertex3f + 3 * (surface->num_firstvertex + quadedges[i][0]);
4500 v2 = rsurface.vertex3f + 3 * (surface->num_firstvertex + quadedges[i][1]);
4502 Debug_PolygonBegin(NULL, 0, false, 0);
4503 Debug_PolygonVertex(v1[0], v1[1], v1[2], 0, 0, 1, 0, 0, 1);
4504 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);
4505 Debug_PolygonVertex(v2[0], v2[1], v2[2], 0, 0, 1, 0, 0, 1);
4508 l = VectorDistance2(v1, v2);
4509 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
4511 l += (1.0f / 1024.0f);
4512 if (shortest[0].length2 > l || i == 0)
4514 shortest[1] = shortest[0];
4515 shortest[0].length2 = l;
4516 shortest[0].v1 = v1;
4517 shortest[0].v2 = v2;
4519 else if (shortest[1].length2 > l || i == 1)
4521 shortest[1].length2 = l;
4522 shortest[1].v1 = v1;
4523 shortest[1].v2 = v2;
4526 VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
4527 VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
4529 Debug_PolygonBegin(NULL, 0, false, 0);
4530 Debug_PolygonVertex(start[0], start[1], start[2], 0, 0, 1, 1, 0, 1);
4531 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);
4532 Debug_PolygonVertex(end[0], end[1], end[2], 0, 0, 0, 1, 1, 1);
4535 // this calculates the right vector from the shortest edge
4536 // and the up vector from the edge midpoints
4537 VectorSubtract(shortest[0].v1, shortest[0].v2, right);
4538 VectorNormalize(right);
4539 VectorSubtract(end, start, up);
4540 VectorNormalize(up);
4541 // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
4542 //VectorSubtract(rsurface.modelorg, center, forward);
4543 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.forward, forward);
4544 VectorNegate(forward, forward);
4545 VectorReflect(forward, 0, up, forward);
4546 VectorNormalize(forward);
4547 CrossProduct(up, forward, newright);
4548 VectorNormalize(newright);
4550 Debug_PolygonBegin(NULL, 0, false, 0);
4551 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);
4552 Debug_PolygonVertex(center[0] + right[0] * 8, center[1] + right[1] * 8, center[2] + right[2] * 8, 0, 0, 0, 1, 0, 1);
4553 Debug_PolygonVertex(center[0] + up [0] * 8, center[1] + up [1] * 8, center[2] + up [2] * 8, 0, 0, 0, 0, 1, 1);
4557 Debug_PolygonBegin(NULL, 0, false, 0);
4558 Debug_PolygonVertex(center[0] + forward [0] * 8, center[1] + forward [1] * 8, center[2] + forward [2] * 8, 0, 0, 1, 0, 0, 1);
4559 Debug_PolygonVertex(center[0] + newright[0] * 8, center[1] + newright[1] * 8, center[2] + newright[2] * 8, 0, 0, 0, 1, 0, 1);
4560 Debug_PolygonVertex(center[0] + up [0] * 8, center[1] + up [1] * 8, center[2] + up [2] * 8, 0, 0, 0, 0, 1, 1);
4563 // rotate the quad around the up axis vector, this is made
4564 // especially easy by the fact we know the quad is flat,
4565 // so we only have to subtract the center position and
4566 // measure distance along the right vector, and then
4567 // multiply that by the newright vector and add back the
4569 // we also need to subtract the old position to undo the
4570 // displacement from the center, which we do with a
4571 // DotProduct, the subtraction/addition of center is also
4572 // optimized into DotProducts here
4573 l = DotProduct(right, center);
4574 for (i = 0;i < 4;i++)
4576 v1 = rsurface.vertex3f + 3 * (surface->num_firstvertex + j + i);
4577 f = DotProduct(right, v1) - l;
4578 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.array_deformedvertex3f + (surface->num_firstvertex+i+j) * 3);
4581 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);
4582 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);
4584 rsurface.vertex3f = rsurface.array_deformedvertex3f;
4585 rsurface.vertex3f_bufferobject = 0;
4586 rsurface.vertex3f_bufferoffset = 0;
4587 rsurface.svector3f = rsurface.array_deformedsvector3f;
4588 rsurface.svector3f_bufferobject = 0;
4589 rsurface.svector3f_bufferoffset = 0;
4590 rsurface.tvector3f = rsurface.array_deformedtvector3f;
4591 rsurface.tvector3f_bufferobject = 0;
4592 rsurface.tvector3f_bufferoffset = 0;
4593 rsurface.normal3f = rsurface.array_deformednormal3f;
4594 rsurface.normal3f_bufferobject = 0;
4595 rsurface.normal3f_bufferoffset = 0;
4597 case Q3DEFORM_NORMAL:
4598 // deform the normals to make reflections wavey
4599 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4601 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4602 for (j = 0;j < surface->num_vertices;j++)
4605 float *normal = (rsurface.array_deformednormal3f + 3 * surface->num_firstvertex) + j*3;
4606 VectorScale((rsurface.vertex3f + 3 * surface->num_firstvertex) + j*3, 0.98f, vertex);
4607 VectorCopy((rsurface.normal3f + 3 * surface->num_firstvertex) + j*3, normal);
4608 normal[0] += deform->parms[0] * noise4f( vertex[0], vertex[1], vertex[2], r_refdef.time * deform->parms[1]);
4609 normal[1] += deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], r_refdef.time * deform->parms[1]);
4610 normal[2] += deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], r_refdef.time * deform->parms[1]);
4611 VectorNormalize(normal);
4613 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);
4615 rsurface.svector3f = rsurface.array_deformedsvector3f;
4616 rsurface.svector3f_bufferobject = 0;
4617 rsurface.svector3f_bufferoffset = 0;
4618 rsurface.tvector3f = rsurface.array_deformedtvector3f;
4619 rsurface.tvector3f_bufferobject = 0;
4620 rsurface.tvector3f_bufferoffset = 0;
4621 rsurface.normal3f = rsurface.array_deformednormal3f;
4622 rsurface.normal3f_bufferobject = 0;
4623 rsurface.normal3f_bufferoffset = 0;
4626 // deform vertex array to make wavey water and flags and such
4627 waveparms[0] = deform->waveparms[0];
4628 waveparms[1] = deform->waveparms[1];
4629 waveparms[2] = deform->waveparms[2];
4630 waveparms[3] = deform->waveparms[3];
4631 // this is how a divisor of vertex influence on deformation
4632 animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
4633 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
4634 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4636 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4637 for (j = 0;j < surface->num_vertices;j++)
4639 float *vertex = (rsurface.array_deformedvertex3f + 3 * surface->num_firstvertex) + j*3;
4640 VectorCopy((rsurface.vertex3f + 3 * surface->num_firstvertex) + j*3, vertex);
4641 // if the wavefunc depends on time, evaluate it per-vertex
4644 waveparms[2] = deform->waveparms[2] + (vertex[0] + vertex[1] + vertex[2]) * animpos;
4645 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
4647 VectorMA(vertex, scale, (rsurface.normal3f + 3 * surface->num_firstvertex) + j*3, vertex);
4650 rsurface.vertex3f = rsurface.array_deformedvertex3f;
4651 rsurface.vertex3f_bufferobject = 0;
4652 rsurface.vertex3f_bufferoffset = 0;
4654 case Q3DEFORM_BULGE:
4655 // deform vertex array to make the surface have moving bulges
4656 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4658 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4659 for (j = 0;j < surface->num_vertices;j++)
4661 scale = sin((rsurface.modeltexcoordtexture2f[2 * (surface->num_firstvertex + j)] * deform->parms[0] + r_refdef.time * deform->parms[2])) * deform->parms[1];
4662 VectorMA(rsurface.vertex3f + 3 * (surface->num_firstvertex + j), scale, rsurface.normal3f + 3 * (surface->num_firstvertex + j), rsurface.array_deformedvertex3f + 3 * (surface->num_firstvertex + j));
4665 rsurface.vertex3f = rsurface.array_deformedvertex3f;
4666 rsurface.vertex3f_bufferobject = 0;
4667 rsurface.vertex3f_bufferoffset = 0;
4670 // deform vertex array
4671 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
4672 VectorScale(deform->parms, scale, waveparms);
4673 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4675 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4676 for (j = 0;j < surface->num_vertices;j++)
4677 VectorAdd(rsurface.vertex3f + 3 * (surface->num_firstvertex + j), waveparms, rsurface.array_deformedvertex3f + 3 * (surface->num_firstvertex + j));
4679 rsurface.vertex3f = rsurface.array_deformedvertex3f;
4680 rsurface.vertex3f_bufferobject = 0;
4681 rsurface.vertex3f_bufferoffset = 0;
4685 // generate texcoords based on the chosen texcoord source
4686 switch(rsurface.texture->tcgen.tcgen)
4689 case Q3TCGEN_TEXTURE:
4690 rsurface.texcoordtexture2f = rsurface.modeltexcoordtexture2f;
4691 rsurface.texcoordtexture2f_bufferobject = rsurface.modeltexcoordtexture2f_bufferobject;
4692 rsurface.texcoordtexture2f_bufferoffset = rsurface.modeltexcoordtexture2f_bufferoffset;
4694 case Q3TCGEN_LIGHTMAP:
4695 rsurface.texcoordtexture2f = rsurface.modeltexcoordlightmap2f;
4696 rsurface.texcoordtexture2f_bufferobject = rsurface.modeltexcoordlightmap2f_bufferobject;
4697 rsurface.texcoordtexture2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
4699 case Q3TCGEN_VECTOR:
4700 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4702 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4703 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)
4705 out_tc[0] = DotProduct(v1, rsurface.texture->tcgen.parms);
4706 out_tc[1] = DotProduct(v1, rsurface.texture->tcgen.parms + 3);
4709 rsurface.texcoordtexture2f = rsurface.array_generatedtexcoordtexture2f;
4710 rsurface.texcoordtexture2f_bufferobject = 0;
4711 rsurface.texcoordtexture2f_bufferoffset = 0;
4713 case Q3TCGEN_ENVIRONMENT:
4714 // make environment reflections using a spheremap
4715 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4717 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4718 const float *vertex = rsurface.modelvertex3f + 3 * surface->num_firstvertex;
4719 const float *normal = rsurface.modelnormal3f + 3 * surface->num_firstvertex;
4720 float *out_tc = rsurface.array_generatedtexcoordtexture2f + 2 * surface->num_firstvertex;
4721 for (j = 0;j < surface->num_vertices;j++, vertex += 3, normal += 3, out_tc += 2)
4723 float l, d, eyedir[3];
4724 VectorSubtract(rsurface.modelorg, vertex, eyedir);
4725 l = 0.5f / VectorLength(eyedir);
4726 d = DotProduct(normal, eyedir)*2;
4727 out_tc[0] = 0.5f + (normal[1]*d - eyedir[1])*l;
4728 out_tc[1] = 0.5f - (normal[2]*d - eyedir[2])*l;
4731 rsurface.texcoordtexture2f = rsurface.array_generatedtexcoordtexture2f;
4732 rsurface.texcoordtexture2f_bufferobject = 0;
4733 rsurface.texcoordtexture2f_bufferoffset = 0;
4736 // the only tcmod that needs software vertex processing is turbulent, so
4737 // check for it here and apply the changes if needed
4738 // and we only support that as the first one
4739 // (handling a mixture of turbulent and other tcmods would be problematic
4740 // without punting it entirely to a software path)
4741 if (rsurface.texture->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
4743 amplitude = rsurface.texture->tcmods[0].parms[1];
4744 animpos = rsurface.texture->tcmods[0].parms[2] + r_refdef.time * rsurface.texture->tcmods[0].parms[3];
4745 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4747 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4748 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)
4750 out_tc[0] = in_tc[0] + amplitude * sin(((v1[0] + v1[2]) * 1.0 / 1024.0f + animpos) * M_PI * 2);
4751 out_tc[1] = in_tc[1] + amplitude * sin(((v1[1] ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
4754 rsurface.texcoordtexture2f = rsurface.array_generatedtexcoordtexture2f;
4755 rsurface.texcoordtexture2f_bufferobject = 0;
4756 rsurface.texcoordtexture2f_bufferoffset = 0;
4758 rsurface.texcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
4759 rsurface.texcoordlightmap2f_bufferobject = rsurface.modeltexcoordlightmap2f_bufferobject;
4760 rsurface.texcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
4761 R_Mesh_VertexPointer(rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
4764 void RSurf_DrawBatch_Simple(int texturenumsurfaces, msurface_t **texturesurfacelist)
4767 const msurface_t *surface = texturesurfacelist[0];
4768 const msurface_t *surface2;
4773 // TODO: lock all array ranges before render, rather than on each surface
4774 if (texturenumsurfaces == 1)
4776 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
4777 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));
4779 else if (r_batchmode.integer == 2)
4781 #define MAXBATCHTRIANGLES 4096
4782 int batchtriangles = 0;
4783 int batchelements[MAXBATCHTRIANGLES*3];
4784 for (i = 0;i < texturenumsurfaces;i = j)
4786 surface = texturesurfacelist[i];
4788 if (surface->num_triangles > MAXBATCHTRIANGLES)
4790 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));
4793 memcpy(batchelements, rsurface.modelelement3i + 3 * surface->num_firsttriangle, surface->num_triangles * sizeof(int[3]));
4794 batchtriangles = surface->num_triangles;
4795 firstvertex = surface->num_firstvertex;
4796 endvertex = surface->num_firstvertex + surface->num_vertices;
4797 for (;j < texturenumsurfaces;j++)
4799 surface2 = texturesurfacelist[j];
4800 if (batchtriangles + surface2->num_triangles > MAXBATCHTRIANGLES)
4802 memcpy(batchelements + batchtriangles * 3, rsurface.modelelement3i + 3 * surface2->num_firsttriangle, surface2->num_triangles * sizeof(int[3]));
4803 batchtriangles += surface2->num_triangles;
4804 firstvertex = min(firstvertex, surface2->num_firstvertex);
4805 endvertex = max(endvertex, surface2->num_firstvertex + surface2->num_vertices);
4807 surface2 = texturesurfacelist[j-1];
4808 numvertices = endvertex - firstvertex;
4809 R_Mesh_Draw(firstvertex, numvertices, batchtriangles, batchelements, 0, 0);
4812 else if (r_batchmode.integer == 1)
4814 for (i = 0;i < texturenumsurfaces;i = j)
4816 surface = texturesurfacelist[i];
4817 for (j = i + 1, surface2 = surface + 1;j < texturenumsurfaces;j++, surface2++)
4818 if (texturesurfacelist[j] != surface2)
4820 surface2 = texturesurfacelist[j-1];
4821 numvertices = surface2->num_firstvertex + surface2->num_vertices - surface->num_firstvertex;
4822 numtriangles = surface2->num_firsttriangle + surface2->num_triangles - surface->num_firsttriangle;
4823 GL_LockArrays(surface->num_firstvertex, numvertices);
4824 R_Mesh_Draw(surface->num_firstvertex, numvertices, numtriangles, (rsurface.modelelement3i + 3 * surface->num_firsttriangle), rsurface.modelelement3i_bufferobject, (sizeof(int[3]) * surface->num_firsttriangle));
4829 for (i = 0;i < texturenumsurfaces;i++)
4831 surface = texturesurfacelist[i];
4832 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
4833 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 static void RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(int texturenumsurfaces, msurface_t **texturesurfacelist, int lightmaptexunit, int deluxemaptexunit, int refractiontexunit, int reflectiontexunit)
4840 int i, planeindex, vertexindex;
4844 r_waterstate_waterplane_t *p, *bestp;
4845 msurface_t *surface;
4846 if (r_waterstate.renderingscene)
4848 for (i = 0;i < texturenumsurfaces;i++)
4850 surface = texturesurfacelist[i];
4851 if (lightmaptexunit >= 0)
4852 R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
4853 if (deluxemaptexunit >= 0)
4854 R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
4855 // pick the closest matching water plane
4858 for (planeindex = 0, p = r_waterstate.waterplanes;planeindex < r_waterstate.numwaterplanes;planeindex++, p++)
4861 for (vertexindex = 0, v = rsurface.modelvertex3f + surface->num_firstvertex * 3;vertexindex < surface->num_vertices;vertexindex++, v += 3)
4863 Matrix4x4_Transform(&rsurface.matrix, v, vert);
4864 d += fabs(PlaneDiff(vert, &p->plane));
4866 if (bestd > d || !bestp)
4874 if (refractiontexunit >= 0)
4875 R_Mesh_TexBind(refractiontexunit, R_GetTexture(bestp->texture_refraction));
4876 if (reflectiontexunit >= 0)
4877 R_Mesh_TexBind(reflectiontexunit, R_GetTexture(bestp->texture_reflection));
4881 if (refractiontexunit >= 0)
4882 R_Mesh_TexBind(refractiontexunit, R_GetTexture(r_texture_black));
4883 if (reflectiontexunit >= 0)
4884 R_Mesh_TexBind(reflectiontexunit, R_GetTexture(r_texture_black));
4886 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
4887 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));
4891 static void RSurf_DrawBatch_WithLightmapSwitching(int texturenumsurfaces, msurface_t **texturesurfacelist, int lightmaptexunit, int deluxemaptexunit)
4895 const msurface_t *surface = texturesurfacelist[0];
4896 const msurface_t *surface2;
4901 // TODO: lock all array ranges before render, rather than on each surface
4902 if (texturenumsurfaces == 1)
4904 R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
4905 if (deluxemaptexunit >= 0)
4906 R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
4907 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
4908 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));
4910 else if (r_batchmode.integer == 2)
4912 #define MAXBATCHTRIANGLES 4096
4913 int batchtriangles = 0;
4914 int batchelements[MAXBATCHTRIANGLES*3];
4915 for (i = 0;i < texturenumsurfaces;i = j)
4917 surface = texturesurfacelist[i];
4918 R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
4919 if (deluxemaptexunit >= 0)
4920 R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
4922 if (surface->num_triangles > MAXBATCHTRIANGLES)
4924 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));
4927 memcpy(batchelements, rsurface.modelelement3i + 3 * surface->num_firsttriangle, surface->num_triangles * sizeof(int[3]));
4928 batchtriangles = surface->num_triangles;
4929 firstvertex = surface->num_firstvertex;
4930 endvertex = surface->num_firstvertex + surface->num_vertices;
4931 for (;j < texturenumsurfaces;j++)
4933 surface2 = texturesurfacelist[j];
4934 if (surface2->lightmaptexture != surface->lightmaptexture || batchtriangles + surface2->num_triangles > MAXBATCHTRIANGLES)
4936 memcpy(batchelements + batchtriangles * 3, rsurface.modelelement3i + 3 * surface2->num_firsttriangle, surface2->num_triangles * sizeof(int[3]));
4937 batchtriangles += surface2->num_triangles;
4938 firstvertex = min(firstvertex, surface2->num_firstvertex);
4939 endvertex = max(endvertex, surface2->num_firstvertex + surface2->num_vertices);
4941 surface2 = texturesurfacelist[j-1];
4942 numvertices = endvertex - firstvertex;
4943 R_Mesh_Draw(firstvertex, numvertices, batchtriangles, batchelements, 0, 0);
4946 else if (r_batchmode.integer == 1)
4949 Con_Printf("%s batch sizes ignoring lightmap:", rsurface.texture->name);
4950 for (i = 0;i < texturenumsurfaces;i = j)
4952 surface = texturesurfacelist[i];
4953 for (j = i + 1, surface2 = surface + 1;j < texturenumsurfaces;j++, surface2++)
4954 if (texturesurfacelist[j] != surface2)
4956 Con_Printf(" %i", j - i);
4959 Con_Printf("%s batch sizes honoring lightmap:", rsurface.texture->name);
4961 for (i = 0;i < texturenumsurfaces;i = j)
4963 surface = texturesurfacelist[i];
4964 R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
4965 if (deluxemaptexunit >= 0)
4966 R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
4967 for (j = i + 1, surface2 = surface + 1;j < texturenumsurfaces;j++, surface2++)
4968 if (texturesurfacelist[j] != surface2 || texturesurfacelist[j]->lightmaptexture != surface->lightmaptexture)
4971 Con_Printf(" %i", j - i);
4973 surface2 = texturesurfacelist[j-1];
4974 numvertices = surface2->num_firstvertex + surface2->num_vertices - surface->num_firstvertex;
4975 numtriangles = surface2->num_firsttriangle + surface2->num_triangles - surface->num_firsttriangle;
4976 GL_LockArrays(surface->num_firstvertex, numvertices);
4977 R_Mesh_Draw(surface->num_firstvertex, numvertices, numtriangles, (rsurface.modelelement3i + 3 * surface->num_firsttriangle), rsurface.modelelement3i_bufferobject, (sizeof(int[3]) * surface->num_firsttriangle));
4985 for (i = 0;i < texturenumsurfaces;i++)
4987 surface = texturesurfacelist[i];
4988 R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
4989 if (deluxemaptexunit >= 0)
4990 R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
4991 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
4992 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));
4997 static void RSurf_DrawBatch_ShowSurfaces(int texturenumsurfaces, msurface_t **texturesurfacelist)
5000 int texturesurfaceindex;
5001 if (r_showsurfaces.integer == 2)
5003 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
5005 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
5006 for (j = 0;j < surface->num_triangles;j++)
5008 float f = ((j + surface->num_firsttriangle) & 31) * (1.0f / 31.0f) * r_view.colorscale;
5009 GL_Color(f, f, f, 1);
5010 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)));
5016 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
5018 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
5019 int k = (int)(((size_t)surface) / sizeof(msurface_t));
5020 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);
5021 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
5022 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));
5027 static void RSurf_DrawBatch_GL11_ApplyFog(int texturenumsurfaces, msurface_t **texturesurfacelist)
5029 int texturesurfaceindex;
5033 if (rsurface.lightmapcolor4f)
5035 // generate color arrays for the surfaces in this list
5036 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
5038 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
5039 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)
5041 f = FogPoint_Model(v);
5051 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
5053 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
5054 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)
5056 f = FogPoint_Model(v);
5064 rsurface.lightmapcolor4f = rsurface.array_color4f;
5065 rsurface.lightmapcolor4f_bufferobject = 0;
5066 rsurface.lightmapcolor4f_bufferoffset = 0;
5069 static void RSurf_DrawBatch_GL11_ApplyColor(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a)
5071 int texturesurfaceindex;
5074 if (!rsurface.lightmapcolor4f)
5076 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
5078 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
5079 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)
5087 rsurface.lightmapcolor4f = rsurface.array_color4f;
5088 rsurface.lightmapcolor4f_bufferobject = 0;
5089 rsurface.lightmapcolor4f_bufferoffset = 0;
5092 static void RSurf_DrawBatch_GL11_Lightmap(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
5095 rsurface.lightmapcolor4f = NULL;
5096 rsurface.lightmapcolor4f_bufferobject = 0;
5097 rsurface.lightmapcolor4f_bufferoffset = 0;
5098 if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
5099 if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
5100 R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
5101 GL_Color(r, g, b, a);
5102 RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist, 0, -1);
5105 static void RSurf_DrawBatch_GL11_Unlit(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
5107 // TODO: optimize applyfog && applycolor case
5108 // just apply fog if necessary, and tint the fog color array if necessary
5109 rsurface.lightmapcolor4f = NULL;
5110 rsurface.lightmapcolor4f_bufferobject = 0;
5111 rsurface.lightmapcolor4f_bufferoffset = 0;
5112 if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
5113 if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
5114 R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
5115 GL_Color(r, g, b, a);
5116 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
5119 static void RSurf_DrawBatch_GL11_VertexColor(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
5121 int texturesurfaceindex;
5125 if (texturesurfacelist[0]->lightmapinfo && texturesurfacelist[0]->lightmapinfo->stainsamples)
5127 // generate color arrays for the surfaces in this list
5128 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
5130 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
5131 for (i = 0, c = rsurface.array_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
5133 if (surface->lightmapinfo->samples)
5135 const unsigned char *lm = surface->lightmapinfo->samples + (rsurface.modellightmapoffsets + surface->num_firstvertex)[i];
5136 float scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[0]] * (1.0f / 32768.0f);
5137 VectorScale(lm, scale, c);
5138 if (surface->lightmapinfo->styles[1] != 255)
5140 int size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
5142 scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[1]] * (1.0f / 32768.0f);
5143 VectorMA(c, scale, lm, c);
5144 if (surface->lightmapinfo->styles[2] != 255)
5147 scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[2]] * (1.0f / 32768.0f);
5148 VectorMA(c, scale, lm, c);
5149 if (surface->lightmapinfo->styles[3] != 255)
5152 scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[3]] * (1.0f / 32768.0f);
5153 VectorMA(c, scale, lm, c);
5163 rsurface.lightmapcolor4f = rsurface.array_color4f;
5164 rsurface.lightmapcolor4f_bufferobject = 0;
5165 rsurface.lightmapcolor4f_bufferoffset = 0;
5169 rsurface.lightmapcolor4f = rsurface.modellightmapcolor4f;
5170 rsurface.lightmapcolor4f_bufferobject = rsurface.modellightmapcolor4f_bufferobject;
5171 rsurface.lightmapcolor4f_bufferoffset = rsurface.modellightmapcolor4f_bufferoffset;
5173 if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
5174 if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
5175 R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
5176 GL_Color(r, g, b, a);
5177 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
5180 static void RSurf_DrawBatch_GL11_VertexShade(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
5182 int texturesurfaceindex;
5186 vec3_t ambientcolor;
5187 vec3_t diffusecolor;
5191 VectorCopy(rsurface.modellight_lightdir, lightdir);
5192 ambientcolor[0] = rsurface.modellight_ambient[0] * r * 0.5f;
5193 ambientcolor[1] = rsurface.modellight_ambient[1] * g * 0.5f;
5194 ambientcolor[2] = rsurface.modellight_ambient[2] * b * 0.5f;
5195 diffusecolor[0] = rsurface.modellight_diffuse[0] * r * 0.5f;
5196 diffusecolor[1] = rsurface.modellight_diffuse[1] * g * 0.5f;
5197 diffusecolor[2] = rsurface.modellight_diffuse[2] * b * 0.5f;
5198 if (VectorLength2(diffusecolor) > 0)
5200 // generate color arrays for the surfaces in this list
5201 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
5203 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
5204 int numverts = surface->num_vertices;
5205 v = rsurface.vertex3f + 3 * surface->num_firstvertex;
5206 c2 = rsurface.normal3f + 3 * surface->num_firstvertex;
5207 c = rsurface.array_color4f + 4 * surface->num_firstvertex;
5208 // q3-style directional shading
5209 for (i = 0;i < numverts;i++, v += 3, c2 += 3, c += 4)
5211 if ((f = DotProduct(c2, lightdir)) > 0)
5212 VectorMA(ambientcolor, f, diffusecolor, c);
5214 VectorCopy(ambientcolor, c);
5223 rsurface.lightmapcolor4f = rsurface.array_color4f;
5224 rsurface.lightmapcolor4f_bufferobject = 0;
5225 rsurface.lightmapcolor4f_bufferoffset = 0;
5229 r = ambientcolor[0];
5230 g = ambientcolor[1];
5231 b = ambientcolor[2];
5232 rsurface.lightmapcolor4f = NULL;
5233 rsurface.lightmapcolor4f_bufferobject = 0;
5234 rsurface.lightmapcolor4f_bufferoffset = 0;
5236 if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
5237 if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
5238 R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
5239 GL_Color(r, g, b, a);
5240 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
5243 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, msurface_t **texturesurfacelist)
5245 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
5246 GL_PolygonOffset(rsurface.texture->currentpolygonfactor, rsurface.texture->currentpolygonoffset);
5247 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
5248 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_view.cullface_back);
5249 if (rsurface.mode != RSURFMODE_SHOWSURFACES)
5251 rsurface.mode = RSURFMODE_SHOWSURFACES;
5253 GL_BlendFunc(GL_ONE, GL_ZERO);
5254 R_Mesh_ColorPointer(NULL, 0, 0);
5255 R_Mesh_ResetTextureState();
5257 RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
5258 RSurf_DrawBatch_ShowSurfaces(texturenumsurfaces, texturesurfacelist);
5261 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, msurface_t **texturesurfacelist)
5263 // transparent sky would be ridiculous
5264 if ((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED))
5266 if (rsurface.mode != RSURFMODE_SKY)
5268 if (rsurface.mode == RSURFMODE_GLSL)
5270 qglUseProgramObjectARB(0);CHECKGLERROR
5272 rsurface.mode = RSURFMODE_SKY;
5276 skyrendernow = false;
5278 // restore entity matrix
5279 R_Mesh_Matrix(&rsurface.matrix);
5281 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
5282 GL_PolygonOffset(rsurface.texture->currentpolygonfactor, rsurface.texture->currentpolygonoffset);
5283 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
5284 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_view.cullface_back);
5286 // LordHavoc: HalfLife maps have freaky skypolys so don't use
5287 // skymasking on them, and Quake3 never did sky masking (unlike
5288 // software Quake and software Quake2), so disable the sky masking
5289 // in Quake3 maps as it causes problems with q3map2 sky tricks,
5290 // and skymasking also looks very bad when noclipping outside the
5291 // level, so don't use it then either.
5292 if (r_refdef.worldmodel && r_refdef.worldmodel->type == mod_brushq1 && r_q1bsp_skymasking.integer && !r_viewcache.world_novis)
5294 GL_Color(r_refdef.fogcolor[0] * r_view.colorscale, r_refdef.fogcolor[1] * r_view.colorscale, r_refdef.fogcolor[2] * r_view.colorscale, 1);
5295 R_Mesh_ColorPointer(NULL, 0, 0);
5296 R_Mesh_ResetTextureState();
5297 if (skyrendermasked)
5299 // depth-only (masking)
5300 GL_ColorMask(0,0,0,0);
5301 // just to make sure that braindead drivers don't draw
5302 // anything despite that colormask...
5303 GL_BlendFunc(GL_ZERO, GL_ONE);
5308 GL_BlendFunc(GL_ONE, GL_ZERO);
5310 RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
5311 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
5312 if (skyrendermasked)
5313 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
5317 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, msurface_t **texturesurfacelist)
5319 if (rsurface.mode != RSURFMODE_GLSL)
5321 rsurface.mode = RSURFMODE_GLSL;
5322 R_Mesh_ResetTextureState();
5325 R_SetupSurfaceShader(vec3_origin, rsurface.lightmode == 2, 1, 1, rsurface.texture->specularscale);
5326 if (!r_glsl_permutation)
5329 if (rsurface.lightmode == 2)
5330 RSurf_PrepareVerticesForBatch(true, r_glsl_permutation->loc_Texture_Normal >= 0, texturenumsurfaces, texturesurfacelist);
5332 RSurf_PrepareVerticesForBatch(r_glsl_permutation->loc_Texture_Normal >= 0, r_glsl_permutation->loc_Texture_Normal >= 0, texturenumsurfaces, texturesurfacelist);
5333 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
5334 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
5335 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
5336 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
5337 R_Mesh_TexCoordPointer(4, 2, rsurface.modeltexcoordlightmap2f, rsurface.modeltexcoordlightmap2f_bufferobject, rsurface.modeltexcoordlightmap2f_bufferoffset);
5339 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]);
5340 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
5342 R_Mesh_TexBind(7, R_GetTexture(r_texture_grey128));
5343 if (r_glsl_permutation->loc_Texture_Deluxemap >= 0)
5344 R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
5345 R_Mesh_ColorPointer(NULL, 0, 0);
5347 else if (rsurface.uselightmaptexture)
5349 R_Mesh_TexBind(7, R_GetTexture(texturesurfacelist[0]->lightmaptexture));
5350 if (r_glsl_permutation->loc_Texture_Deluxemap >= 0)
5351 R_Mesh_TexBind(8, R_GetTexture(texturesurfacelist[0]->deluxemaptexture));
5352 R_Mesh_ColorPointer(NULL, 0, 0);
5356 R_Mesh_TexBind(7, R_GetTexture(r_texture_white));
5357 if (r_glsl_permutation->loc_Texture_Deluxemap >= 0)
5358 R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
5359 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
5362 if (rsurface.uselightmaptexture && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT))
5364 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERSHADER)
5365 RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(texturenumsurfaces, texturesurfacelist, 7, r_glsl_permutation->loc_Texture_Deluxemap >= 0 ? 8 : -1, 11, 12);
5366 else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
5367 RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(texturenumsurfaces, texturesurfacelist, 7, r_glsl_permutation->loc_Texture_Deluxemap >= 0 ? 8 : -1, -1, 12);
5369 RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist, 7, r_glsl_permutation->loc_Texture_Deluxemap >= 0 ? 8 : -1);
5373 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_WATERSHADER)
5374 RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(texturenumsurfaces, texturesurfacelist, -1, -1, 11, 12);
5375 else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION)
5376 RSurf_DrawBatch_WithLightmapSwitching_WithWaterTextureSwitching(texturenumsurfaces, texturesurfacelist, -1, -1, -1, 12);
5378 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
5380 if (rsurface.texture->backgroundnumskinframes && !(rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED))
5385 static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, msurface_t **texturesurfacelist)
5387 // OpenGL 1.3 path - anything not completely ancient
5388 int texturesurfaceindex;
5389 qboolean applycolor;
5393 const texturelayer_t *layer;
5394 if (rsurface.mode != RSURFMODE_MULTIPASS)
5395 rsurface.mode = RSURFMODE_MULTIPASS;
5396 RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist);
5397 for (layerindex = 0, layer = rsurface.texture->currentlayers;layerindex < rsurface.texture->currentnumlayers;layerindex++, layer++)
5400 int layertexrgbscale;
5401 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
5403 if (layerindex == 0)
5407 GL_AlphaTest(false);
5408 qglDepthFunc(GL_EQUAL);CHECKGLERROR
5411 GL_DepthMask(layer->depthmask);
5412 GL_BlendFunc(layer->blendfunc1, layer->blendfunc2);
5413 if ((layer->color[0] > 2 || layer->color[1] > 2 || layer->color[2] > 2) && (gl_combine.integer || layer->depthmask))
5415 layertexrgbscale = 4;
5416 VectorScale(layer->color, 0.25f, layercolor);
5418 else if ((layer->color[0] > 1 || layer->color[1] > 1 || layer->color[2] > 1) && (gl_combine.integer || layer->depthmask))
5420 layertexrgbscale = 2;
5421 VectorScale(layer->color, 0.5f, layercolor);
5425 layertexrgbscale = 1;
5426 VectorScale(layer->color, 1.0f, layercolor);
5428 layercolor[3] = layer->color[3];
5429 applycolor = layercolor[0] != 1 || layercolor[1] != 1 || layercolor[2] != 1 || layercolor[3] != 1;
5430 R_Mesh_ColorPointer(NULL, 0, 0);
5431 applyfog = (layer->flags & TEXTURELAYERFLAG_FOGDARKEN) != 0;
5432 switch (layer->type)
5434 case TEXTURELAYERTYPE_LITTEXTURE:
5435 memset(&m, 0, sizeof(m));
5436 m.tex[0] = R_GetTexture(r_texture_white);
5437 m.pointer_texcoord[0] = rsurface.modeltexcoordlightmap2f;
5438 m.pointer_texcoord_bufferobject[0] = rsurface.modeltexcoordlightmap2f_bufferobject;
5439 m.pointer_texcoord_bufferoffset[0] = rsurface.modeltexcoordlightmap2f_bufferoffset;
5440 m.tex[1] = R_GetTexture(layer->texture);
5441 m.texmatrix[1] = layer->texmatrix;
5442 m.texrgbscale[1] = layertexrgbscale;
5443 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
5444 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
5445 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
5446 R_Mesh_TextureState(&m);
5447 if (rsurface.lightmode == 2)
5448 RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
5449 else if (rsurface.uselightmaptexture)
5450 RSurf_DrawBatch_GL11_Lightmap(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
5452 RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
5454 case TEXTURELAYERTYPE_TEXTURE:
5455 memset(&m, 0, sizeof(m));
5456 m.tex[0] = R_GetTexture(layer->texture);
5457 m.texmatrix[0] = layer->texmatrix;
5458 m.texrgbscale[0] = layertexrgbscale;
5459 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
5460 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
5461 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
5462 R_Mesh_TextureState(&m);
5463 RSurf_DrawBatch_GL11_Unlit(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
5465 case TEXTURELAYERTYPE_FOG:
5466 memset(&m, 0, sizeof(m));
5467 m.texrgbscale[0] = layertexrgbscale;
5470 m.tex[0] = R_GetTexture(layer->texture);
5471 m.texmatrix[0] = layer->texmatrix;
5472 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
5473 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
5474 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
5476 R_Mesh_TextureState(&m);
5477 // generate a color array for the fog pass
5478 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
5479 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
5483 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
5484 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)
5486 f = 1 - FogPoint_Model(v);
5487 c[0] = layercolor[0];
5488 c[1] = layercolor[1];
5489 c[2] = layercolor[2];
5490 c[3] = f * layercolor[3];
5493 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
5496 Con_Printf("R_DrawTextureSurfaceList: unknown layer type %i\n", layer->type);
5498 GL_LockArrays(0, 0);
5501 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
5503 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
5504 GL_AlphaTest(false);
5508 static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, msurface_t **texturesurfacelist)
5510 // OpenGL 1.1 - crusty old voodoo path
5511 int texturesurfaceindex;
5515 const texturelayer_t *layer;
5516 if (rsurface.mode != RSURFMODE_MULTIPASS)
5517 rsurface.mode = RSURFMODE_MULTIPASS;
5518 RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist);
5519 for (layerindex = 0, layer = rsurface.texture->currentlayers;layerindex < rsurface.texture->currentnumlayers;layerindex++, layer++)
5521 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
5523 if (layerindex == 0)
5527 GL_AlphaTest(false);
5528 qglDepthFunc(GL_EQUAL);CHECKGLERROR
5531 GL_DepthMask(layer->depthmask);
5532 GL_BlendFunc(layer->blendfunc1, layer->blendfunc2);
5533 R_Mesh_ColorPointer(NULL, 0, 0);
5534 applyfog = (layer->flags & TEXTURELAYERFLAG_FOGDARKEN) != 0;
5535 switch (layer->type)
5537 case TEXTURELAYERTYPE_LITTEXTURE:
5538 if (layer->blendfunc1 == GL_ONE && layer->blendfunc2 == GL_ZERO)
5540 // two-pass lit texture with 2x rgbscale
5541 // first the lightmap pass
5542 memset(&m, 0, sizeof(m));
5543 m.tex[0] = R_GetTexture(r_texture_white);
5544 m.pointer_texcoord[0] = rsurface.modeltexcoordlightmap2f;
5545 m.pointer_texcoord_bufferobject[0] = rsurface.modeltexcoordlightmap2f_bufferobject;
5546 m.pointer_texcoord_bufferoffset[0] = rsurface.modeltexcoordlightmap2f_bufferoffset;
5547 R_Mesh_TextureState(&m);
5548 if (rsurface.lightmode == 2)
5549 RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
5550 else if (rsurface.uselightmaptexture)
5551 RSurf_DrawBatch_GL11_Lightmap(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
5553 RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
5554 GL_LockArrays(0, 0);
5555 // then apply the texture to it
5556 GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
5557 memset(&m, 0, sizeof(m));
5558 m.tex[0] = R_GetTexture(layer->texture);
5559 m.texmatrix[0] = layer->texmatrix;
5560 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
5561 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
5562 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
5563 R_Mesh_TextureState(&m);
5564 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);
5568 // single pass vertex-lighting-only texture with 1x rgbscale and transparency support
5569 memset(&m, 0, sizeof(m));
5570 m.tex[0] = R_GetTexture(layer->texture);
5571 m.texmatrix[0] = layer->texmatrix;
5572 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
5573 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
5574 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
5575 R_Mesh_TextureState(&m);
5576 if (rsurface.lightmode == 2)
5577 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);
5579 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);
5582 case TEXTURELAYERTYPE_TEXTURE:
5583 // singletexture unlit texture with transparency support
5584 memset(&m, 0, sizeof(m));
5585 m.tex[0] = R_GetTexture(layer->texture);
5586 m.texmatrix[0] = layer->texmatrix;
5587 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
5588 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
5589 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
5590 R_Mesh_TextureState(&m);
5591 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);
5593 case TEXTURELAYERTYPE_FOG:
5594 // singletexture fogging
5595 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
5598 memset(&m, 0, sizeof(m));
5599 m.tex[0] = R_GetTexture(layer->texture);
5600 m.texmatrix[0] = layer->texmatrix;
5601 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
5602 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
5603 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
5604 R_Mesh_TextureState(&m);
5607 R_Mesh_ResetTextureState();
5608 // generate a color array for the fog pass
5609 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
5613 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
5614 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)
5616 f = 1 - FogPoint_Model(v);
5617 c[0] = layer->color[0];
5618 c[1] = layer->color[1];
5619 c[2] = layer->color[2];
5620 c[3] = f * layer->color[3];
5623 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
5626 Con_Printf("R_DrawTextureSurfaceList: unknown layer type %i\n", layer->type);
5628 GL_LockArrays(0, 0);
5631 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
5633 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
5634 GL_AlphaTest(false);
5638 static void R_DrawTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly)
5640 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW)
5642 rsurface.rtlight = NULL;
5646 if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
5648 if (r_waterstate.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
5650 if (rsurface.mode != RSURFMODE_MULTIPASS)
5651 rsurface.mode = RSURFMODE_MULTIPASS;
5652 if (r_depthfirst.integer == 3)
5654 int i = (int)(texturesurfacelist[0] - rsurface.modelsurfaces);
5655 if (!r_view.showdebug)
5656 GL_Color(0, 0, 0, 1);
5658 GL_Color(((i >> 6) & 7) / 7.0f, ((i >> 3) & 7) / 7.0f, (i & 7) / 7.0f,1);
5662 GL_ColorMask(0,0,0,0);
5665 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
5666 GL_PolygonOffset(rsurface.texture->currentpolygonfactor, rsurface.texture->currentpolygonoffset);
5667 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_view.cullface_back);
5669 GL_BlendFunc(GL_ONE, GL_ZERO);
5671 GL_AlphaTest(false);
5672 R_Mesh_ColorPointer(NULL, 0, 0);
5673 R_Mesh_ResetTextureState();
5674 RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
5675 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
5676 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
5677 r_refdef.stats.entities_surfaces += texturenumsurfaces;
5679 else if (r_depthfirst.integer == 3)
5681 else if (!r_view.showdebug && (r_showsurfaces.integer || gl_lightmaps.integer))
5683 GL_Color(0, 0, 0, 1);
5684 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
5686 else if (r_showsurfaces.integer)
5688 if (rsurface.mode != RSURFMODE_MULTIPASS)
5689 rsurface.mode = RSURFMODE_MULTIPASS;
5690 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
5691 GL_PolygonOffset(rsurface.texture->currentpolygonfactor, rsurface.texture->currentpolygonoffset);
5693 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_view.cullface_back);
5694 GL_BlendFunc(GL_ONE, GL_ZERO);
5695 GL_DepthMask(writedepth);
5697 GL_AlphaTest(false);
5698 R_Mesh_ColorPointer(NULL, 0, 0);
5699 R_Mesh_ResetTextureState();
5700 RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
5701 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist);
5702 r_refdef.stats.entities_surfaces += texturenumsurfaces;
5704 else if (gl_lightmaps.integer)
5707 if (rsurface.mode != RSURFMODE_MULTIPASS)
5708 rsurface.mode = RSURFMODE_MULTIPASS;
5709 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
5711 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_view.cullface_back);
5712 GL_BlendFunc(GL_ONE, GL_ZERO);
5713 GL_DepthMask(writedepth);
5715 GL_AlphaTest(false);
5716 // use lightmode 0 (fullbright or lightmap) or 2 (model lighting)
5717 rsurface.lightmode = ((rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || rsurface.modeltexcoordlightmap2f != NULL) ? 0 : 2;
5718 R_Mesh_ColorPointer(NULL, 0, 0);
5719 memset(&m, 0, sizeof(m));
5720 m.tex[0] = R_GetTexture(r_texture_white);
5721 m.pointer_texcoord[0] = rsurface.modeltexcoordlightmap2f;
5722 m.pointer_texcoord_bufferobject[0] = rsurface.modeltexcoordlightmap2f_bufferobject;
5723 m.pointer_texcoord_bufferoffset[0] = rsurface.modeltexcoordlightmap2f_bufferoffset;
5724 R_Mesh_TextureState(&m);
5725 RSurf_PrepareVerticesForBatch(rsurface.lightmode == 2, false, texturenumsurfaces, texturesurfacelist);
5726 if (rsurface.lightmode == 2)
5727 RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
5728 else if (rsurface.uselightmaptexture)
5729 RSurf_DrawBatch_GL11_Lightmap(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
5731 RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
5732 r_refdef.stats.entities_surfaces += texturenumsurfaces;
5734 else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY)
5736 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
5737 r_refdef.stats.entities_surfaces += texturenumsurfaces;
5739 else if (rsurface.texture->currentnumlayers)
5741 // write depth for anything we skipped on the depth-only pass earlier
5742 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
5744 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
5745 GL_PolygonOffset(rsurface.texture->currentpolygonfactor, rsurface.texture->currentpolygonoffset);
5746 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
5747 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_view.cullface_back);
5748 GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
5749 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
5750 GL_AlphaTest((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
5751 // use lightmode 0 (fullbright or lightmap) or 2 (model lighting)
5752 rsurface.lightmode = ((rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || rsurface.modeltexcoordlightmap2f != NULL) ? 0 : 2;
5753 if (r_glsl.integer && gl_support_fragment_shader)
5754 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist);
5755 else if (gl_combine.integer && r_textureunits.integer >= 2)
5756 R_DrawTextureSurfaceList_GL13(texturenumsurfaces, texturesurfacelist);
5758 R_DrawTextureSurfaceList_GL11(texturenumsurfaces, texturesurfacelist);
5759 r_refdef.stats.entities_surfaces += texturenumsurfaces;
5762 GL_LockArrays(0, 0);
5765 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5768 int texturenumsurfaces, endsurface;
5770 msurface_t *surface;
5771 msurface_t *texturesurfacelist[1024];
5773 // if the model is static it doesn't matter what value we give for
5774 // wantnormals and wanttangents, so this logic uses only rules applicable
5775 // to a model, knowing that they are meaningless otherwise
5776 if (ent == r_refdef.worldentity)
5777 RSurf_ActiveWorldEntity();
5778 else if ((ent->effects & EF_FULLBRIGHT) || r_showsurfaces.integer || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f))
5779 RSurf_ActiveModelEntity(ent, false, false);
5781 RSurf_ActiveModelEntity(ent, true, r_glsl.integer && gl_support_fragment_shader);
5783 for (i = 0;i < numsurfaces;i = j)
5786 surface = rsurface.modelsurfaces + surfacelist[i];
5787 texture = surface->texture;
5788 R_UpdateTextureInfo(ent, texture);
5789 rsurface.texture = texture->currentframe;
5790 rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
5791 // scan ahead until we find a different texture
5792 endsurface = min(i + 1024, numsurfaces);
5793 texturenumsurfaces = 0;
5794 texturesurfacelist[texturenumsurfaces++] = surface;
5795 for (;j < endsurface;j++)
5797 surface = rsurface.modelsurfaces + surfacelist[j];
5798 if (texture != surface->texture || rsurface.uselightmaptexture != (surface->lightmaptexture != NULL))
5800 texturesurfacelist[texturenumsurfaces++] = surface;
5802 // render the range of surfaces
5803 R_DrawTextureSurfaceList(texturenumsurfaces, texturesurfacelist, true, false);
5809 void R_QueueSurfaceList(entity_render_t *ent, int numsurfaces, msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean addwaterplanes)
5812 vec3_t tempcenter, center;
5814 // if we're rendering water textures (extra scene renders), use a separate loop to avoid burdening the main one
5817 for (i = 0;i < numsurfaces;i++)
5818 if (surfacelist[i]->texture->currentframe->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION))
5819 R_Water_AddWaterPlane(surfacelist[i]);
5822 // break the surface list down into batches by texture and use of lightmapping
5823 for (i = 0;i < numsurfaces;i = j)
5826 // texture is the base texture pointer, rsurface.texture is the
5827 // current frame/skin the texture is directing us to use (for example
5828 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
5829 // use skin 1 instead)
5830 texture = surfacelist[i]->texture;
5831 rsurface.texture = texture->currentframe;
5832 rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
5833 if (!(rsurface.texture->currentmaterialflags & flagsmask))
5835 // if this texture is not the kind we want, skip ahead to the next one
5836 for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
5840 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
5842 // transparent surfaces get pushed off into the transparent queue
5843 const msurface_t *surface = surfacelist[i];
5846 tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
5847 tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
5848 tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
5849 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
5850 R_MeshQueue_AddTransparent(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_view.origin : center, R_DrawSurface_TransparentCallback, ent, surface - rsurface.modelsurfaces, rsurface.rtlight);
5854 // simply scan ahead until we find a different texture or lightmap state
5855 for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.uselightmaptexture == (surfacelist[j]->lightmaptexture != NULL);j++)
5857 // render the range of surfaces
5858 R_DrawTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly);
5863 float locboxvertex3f[6*4*3] =
5865 1,0,1, 1,0,0, 1,1,0, 1,1,1,
5866 0,1,1, 0,1,0, 0,0,0, 0,0,1,
5867 1,1,1, 1,1,0, 0,1,0, 0,1,1,
5868 0,0,1, 0,0,0, 1,0,0, 1,0,1,
5869 0,0,1, 1,0,1, 1,1,1, 0,1,1,
5870 1,0,0, 0,0,0, 0,1,0, 1,1,0
5873 int locboxelement3i[6*2*3] =
5883 void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5886 cl_locnode_t *loc = (cl_locnode_t *)ent;
5888 float vertex3f[6*4*3];
5890 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5891 GL_DepthMask(false);
5892 GL_DepthRange(0, 1);
5893 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
5895 GL_CullFace(GL_NONE);
5896 R_Mesh_Matrix(&identitymatrix);
5898 R_Mesh_VertexPointer(vertex3f, 0, 0);
5899 R_Mesh_ColorPointer(NULL, 0, 0);
5900 R_Mesh_ResetTextureState();
5903 GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_view.colorscale,
5904 ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_view.colorscale,
5905 ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_view.colorscale,
5906 surfacelist[0] < 0 ? 0.5f : 0.125f);
5908 if (VectorCompare(loc->mins, loc->maxs))
5910 VectorSet(size, 2, 2, 2);
5911 VectorMA(loc->mins, -0.5f, size, mins);
5915 VectorCopy(loc->mins, mins);
5916 VectorSubtract(loc->maxs, loc->mins, size);
5919 for (i = 0;i < 6*4*3;)
5920 for (j = 0;j < 3;j++, i++)
5921 vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
5923 R_Mesh_Draw(0, 6*4, 6*2, locboxelement3i, 0, 0);
5926 void R_DrawLocs(void)
5929 cl_locnode_t *loc, *nearestloc;
5931 nearestloc = CL_Locs_FindNearest(cl.movement_origin);
5932 for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
5934 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
5935 R_MeshQueue_AddTransparent(center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
5939 void R_DrawDebugModel(entity_render_t *ent)
5941 int i, j, k, l, flagsmask;
5942 const int *elements;
5944 msurface_t *surface;
5945 model_t *model = ent->model;
5948 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WATER | MATERIALFLAG_WALL;
5950 R_Mesh_ColorPointer(NULL, 0, 0);
5951 R_Mesh_ResetTextureState();
5952 GL_DepthRange(0, 1);
5953 GL_DepthTest(!r_showdisabledepthtest.integer);
5954 GL_DepthMask(false);
5955 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5957 if (r_showcollisionbrushes.value > 0 && model->brush.num_brushes)
5959 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
5960 for (i = 0, brush = model->brush.data_brushes + model->firstmodelbrush;i < model->nummodelbrushes;i++, brush++)
5962 if (brush->colbrushf && brush->colbrushf->numtriangles)
5964 R_Mesh_VertexPointer(brush->colbrushf->points->v, 0, 0);
5965 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);
5966 R_Mesh_Draw(0, brush->colbrushf->numpoints, brush->colbrushf->numtriangles, brush->colbrushf->elements, 0, 0);
5969 for (i = 0, surface = model->data_surfaces + model->firstmodelsurface;i < model->nummodelsurfaces;i++, surface++)
5971 if (surface->num_collisiontriangles)
5973 R_Mesh_VertexPointer(surface->data_collisionvertex3f, 0, 0);
5974 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);
5975 R_Mesh_Draw(0, surface->num_collisionvertices, surface->num_collisiontriangles, surface->data_collisionelement3i, 0, 0);
5980 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
5982 if (r_showtris.integer || r_shownormals.integer)
5984 if (r_showdisabledepthtest.integer)
5986 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5987 GL_DepthMask(false);
5991 GL_BlendFunc(GL_ONE, GL_ZERO);
5994 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
5996 if (ent == r_refdef.worldentity && !r_viewcache.world_surfacevisible[j])
5998 rsurface.texture = surface->texture->currentframe;
5999 if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
6001 RSurf_PrepareVerticesForBatch(true, true, 1, &surface);
6002 if (r_showtris.value > 0)
6004 if (!rsurface.texture->currentlayers->depthmask)
6005 GL_Color(r_view.colorscale, 0, 0, r_showtris.value);
6006 else if (ent == r_refdef.worldentity)
6007 GL_Color(r_view.colorscale, r_view.colorscale, r_view.colorscale, r_showtris.value);
6009 GL_Color(0, r_view.colorscale, 0, r_showtris.value);
6010 elements = (ent->model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);
6013 for (k = 0;k < surface->num_triangles;k++, elements += 3)
6015 #define GLVERTEXELEMENT(n) qglVertex3f(rsurface.vertex3f[elements[n]*3+0], rsurface.vertex3f[elements[n]*3+1], rsurface.vertex3f[elements[n]*3+2])
6016 GLVERTEXELEMENT(0);GLVERTEXELEMENT(1);
6017 GLVERTEXELEMENT(1);GLVERTEXELEMENT(2);
6018 GLVERTEXELEMENT(2);GLVERTEXELEMENT(0);
6023 if (r_shownormals.value > 0)
6025 GL_Color(r_view.colorscale, 0, 0, r_shownormals.value);
6027 for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
6029 VectorCopy(rsurface.vertex3f + l * 3, v);
6030 qglVertex3f(v[0], v[1], v[2]);
6031 VectorMA(v, 8, rsurface.svector3f + l * 3, v);
6032 qglVertex3f(v[0], v[1], v[2]);
6036 GL_Color(0, 0, r_view.colorscale, r_shownormals.value);
6038 for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
6040 VectorCopy(rsurface.vertex3f + l * 3, v);
6041 qglVertex3f(v[0], v[1], v[2]);
6042 VectorMA(v, 8, rsurface.tvector3f + l * 3, v);
6043 qglVertex3f(v[0], v[1], v[2]);
6047 GL_Color(0, r_view.colorscale, 0, r_shownormals.value);
6049 for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
6051 VectorCopy(rsurface.vertex3f + l * 3, v);
6052 qglVertex3f(v[0], v[1], v[2]);
6053 VectorMA(v, 8, rsurface.normal3f + l * 3, v);
6054 qglVertex3f(v[0], v[1], v[2]);
6061 rsurface.texture = NULL;
6065 extern void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface);
6066 void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean addwaterplanes, qboolean debug)
6068 int i, j, endj, f, flagsmask;
6069 int counttriangles = 0;
6070 msurface_t *surface, **surfacechain;
6072 model_t *model = r_refdef.worldmodel;
6073 const int maxsurfacelist = 1024;
6074 int numsurfacelist = 0;
6075 msurface_t *surfacelist[1024];
6079 RSurf_ActiveWorldEntity();
6081 // update light styles
6082 if (!skysurfaces && !depthonly && !addwaterplanes && model->brushq1.light_styleupdatechains)
6084 for (i = 0;i < model->brushq1.light_styles;i++)
6086 if (model->brushq1.light_stylevalue[i] != r_refdef.lightstylevalue[model->brushq1.light_style[i]])
6088 model->brushq1.light_stylevalue[i] = r_refdef.lightstylevalue[model->brushq1.light_style[i]];
6089 if ((surfacechain = model->brushq1.light_styleupdatechains[i]))
6090 for (;(surface = *surfacechain);surfacechain++)
6091 surface->cached_dlight = true;
6096 R_UpdateAllTextureInfo(r_refdef.worldentity);
6097 flagsmask = addwaterplanes ? (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) : (skysurfaces ? MATERIALFLAG_SKY : (MATERIALFLAG_WATER | MATERIALFLAG_WALL));
6101 R_DrawDebugModel(r_refdef.worldentity);
6107 rsurface.uselightmaptexture = false;
6108 rsurface.texture = NULL;
6110 j = model->firstmodelsurface;
6111 endj = j + model->nummodelsurfaces;
6114 // quickly skip over non-visible surfaces
6115 for (;j < endj && !r_viewcache.world_surfacevisible[j];j++)
6117 // quickly iterate over visible surfaces
6118 for (;j < endj && r_viewcache.world_surfacevisible[j];j++)
6120 // process this surface
6121 surface = model->data_surfaces + j;
6122 // if this surface fits the criteria, add it to the list
6123 if (surface->num_triangles)
6125 // if lightmap parameters changed, rebuild lightmap texture
6126 if (surface->cached_dlight)
6127 R_BuildLightMap(r_refdef.worldentity, surface);
6128 // add face to draw list
6129 surfacelist[numsurfacelist++] = surface;
6130 counttriangles += surface->num_triangles;
6131 if (numsurfacelist >= maxsurfacelist)
6133 R_QueueSurfaceList(r_refdef.worldentity, numsurfacelist, surfacelist, flagsmask, writedepth, depthonly, addwaterplanes);
6140 R_QueueSurfaceList(r_refdef.worldentity, numsurfacelist, surfacelist, flagsmask, writedepth, depthonly, addwaterplanes);
6141 r_refdef.stats.entities_triangles += counttriangles;
6145 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean addwaterplanes, qboolean debug)
6147 int i, f, flagsmask;
6148 int counttriangles = 0;
6149 msurface_t *surface, *endsurface, **surfacechain;
6151 model_t *model = ent->model;
6152 const int maxsurfacelist = 1024;
6153 int numsurfacelist = 0;
6154 msurface_t *surfacelist[1024];
6158 // if the model is static it doesn't matter what value we give for
6159 // wantnormals and wanttangents, so this logic uses only rules applicable
6160 // to a model, knowing that they are meaningless otherwise
6161 if (ent == r_refdef.worldentity)
6162 RSurf_ActiveWorldEntity();
6163 else if ((ent->effects & EF_FULLBRIGHT) || r_showsurfaces.integer || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f))
6164 RSurf_ActiveModelEntity(ent, false, false);
6166 RSurf_ActiveModelEntity(ent, true, r_glsl.integer && gl_support_fragment_shader && !depthonly);
6168 // update light styles
6169 if (!skysurfaces && !depthonly && !addwaterplanes && model->brushq1.light_styleupdatechains)
6171 for (i = 0;i < model->brushq1.light_styles;i++)
6173 if (model->brushq1.light_stylevalue[i] != r_refdef.lightstylevalue[model->brushq1.light_style[i]])
6175 model->brushq1.light_stylevalue[i] = r_refdef.lightstylevalue[model->brushq1.light_style[i]];
6176 if ((surfacechain = model->brushq1.light_styleupdatechains[i]))
6177 for (;(surface = *surfacechain);surfacechain++)
6178 surface->cached_dlight = true;
6183 R_UpdateAllTextureInfo(ent);
6184 flagsmask = addwaterplanes ? (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) : (skysurfaces ? MATERIALFLAG_SKY : (MATERIALFLAG_WATER | MATERIALFLAG_WALL));
6188 R_DrawDebugModel(ent);
6194 rsurface.uselightmaptexture = false;
6195 rsurface.texture = NULL;
6197 surface = model->data_surfaces + model->firstmodelsurface;
6198 endsurface = surface + model->nummodelsurfaces;
6199 for (;surface < endsurface;surface++)
6201 // if this surface fits the criteria, add it to the list
6202 if (surface->num_triangles)
6204 // if lightmap parameters changed, rebuild lightmap texture
6205 if (surface->cached_dlight)
6206 R_BuildLightMap(ent, surface);
6207 // add face to draw list
6208 surfacelist[numsurfacelist++] = surface;
6209 counttriangles += surface->num_triangles;
6210 if (numsurfacelist >= maxsurfacelist)
6212 R_QueueSurfaceList(ent, numsurfacelist, surfacelist, flagsmask, writedepth, depthonly, addwaterplanes);
6218 R_QueueSurfaceList(ent, numsurfacelist, surfacelist, flagsmask, writedepth, depthonly, addwaterplanes);
6219 r_refdef.stats.entities_triangles += counttriangles;