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_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "1", "enables animation smoothing on sprites (requires r_lerpmodels 1)"};
85 cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
86 cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
88 cvar_t r_bloom = {CVAR_SAVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"};
89 cvar_t r_bloom_colorscale = {CVAR_SAVE, "r_bloom_colorscale", "1", "how bright the glow is"};
90 cvar_t r_bloom_brighten = {CVAR_SAVE, "r_bloom_brighten", "2", "how bright the glow is, after subtract/power"};
91 cvar_t r_bloom_blur = {CVAR_SAVE, "r_bloom_blur", "4", "how large the glow is"};
92 cvar_t r_bloom_resolution = {CVAR_SAVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"};
93 cvar_t r_bloom_colorexponent = {CVAR_SAVE, "r_bloom_colorexponent", "1", "how exagerated the glow is"};
94 cvar_t r_bloom_colorsubtract = {CVAR_SAVE, "r_bloom_colorsubtract", "0.125", "reduces bloom colors by a certain amount"};
96 cvar_t r_hdr = {CVAR_SAVE, "r_hdr", "0", "enables High Dynamic Range bloom effect (higher quality version of r_bloom)"};
97 cvar_t r_hdr_scenebrightness = {CVAR_SAVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
98 cvar_t r_hdr_glowintensity = {CVAR_SAVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
99 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)"};
101 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"};
103 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"};
105 cvar_t gl_lightmaps = {0, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers)"};
107 cvar_t r_test = {0, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
108 cvar_t r_batchmode = {0, "r_batchmode", "1", "selects method of rendering multiple surfaces with one driver call (values are 0, 1, 2, etc...)"};
110 extern qboolean v_flipped_state;
112 typedef struct r_glsl_bloomshader_s
115 int loc_Texture_Bloom;
117 r_glsl_bloomshader_t;
119 static struct r_bloomstate_s
124 int bloomwidth, bloomheight;
126 int screentexturewidth, screentextureheight;
127 rtexture_t *texture_screen;
129 int bloomtexturewidth, bloomtextureheight;
130 rtexture_t *texture_bloom;
132 r_glsl_bloomshader_t *shader;
134 // arrays for rendering the screen passes
135 float screentexcoord2f[8];
136 float bloomtexcoord2f[8];
137 float offsettexcoord2f[8];
141 // shadow volume bsp struct with automatically growing nodes buffer
144 rtexture_t *r_texture_blanknormalmap;
145 rtexture_t *r_texture_white;
146 rtexture_t *r_texture_grey128;
147 rtexture_t *r_texture_black;
148 rtexture_t *r_texture_notexture;
149 rtexture_t *r_texture_whitecube;
150 rtexture_t *r_texture_normalizationcube;
151 rtexture_t *r_texture_fogattenuation;
152 //rtexture_t *r_texture_fogintensity;
154 // information about each possible shader permutation
155 r_glsl_permutation_t r_glsl_permutations[SHADERPERMUTATION_MAX];
156 // currently selected permutation
157 r_glsl_permutation_t *r_glsl_permutation;
159 char r_qwskincache[MAX_SCOREBOARD][MAX_QPATH];
160 skinframe_t *r_qwskincache_skinframe[MAX_SCOREBOARD];
162 // vertex coordinates for a quad that covers the screen exactly
163 const static float r_screenvertex3f[12] =
171 extern void R_DrawModelShadows(void);
173 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
176 for (i = 0;i < verts;i++)
187 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
190 for (i = 0;i < verts;i++)
200 // FIXME: move this to client?
203 if (gamemode == GAME_NEHAHRA)
205 Cvar_Set("gl_fogenable", "0");
206 Cvar_Set("gl_fogdensity", "0.2");
207 Cvar_Set("gl_fogred", "0.3");
208 Cvar_Set("gl_foggreen", "0.3");
209 Cvar_Set("gl_fogblue", "0.3");
211 r_refdef.fog_density = r_refdef.fog_red = r_refdef.fog_green = r_refdef.fog_blue = 0.0f;
214 float FogPoint_World(const vec3_t p)
216 int fogmasktableindex = (int)(VectorDistance((p), r_view.origin) * r_refdef.fogmasktabledistmultiplier);
217 return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
220 float FogPoint_Model(const vec3_t p)
222 int fogmasktableindex = (int)(VectorDistance((p), rsurface.modelorg) * r_refdef.fogmasktabledistmultiplier);
223 return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
226 static void R_BuildBlankTextures(void)
228 unsigned char data[4];
229 data[0] = 128; // normal X
230 data[1] = 128; // normal Y
231 data[2] = 255; // normal Z
232 data[3] = 128; // height
233 r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
238 r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
243 r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
248 r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_RGBA, TEXF_PRECACHE, NULL);
251 static void R_BuildNoTexture(void)
254 unsigned char pix[16][16][4];
255 // this makes a light grey/dark grey checkerboard texture
256 for (y = 0;y < 16;y++)
258 for (x = 0;x < 16;x++)
260 if ((y < 8) ^ (x < 8))
276 r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP, NULL);
279 static void R_BuildWhiteCube(void)
281 unsigned char data[6*1*1*4];
282 data[ 0] = 255;data[ 1] = 255;data[ 2] = 255;data[ 3] = 255;
283 data[ 4] = 255;data[ 5] = 255;data[ 6] = 255;data[ 7] = 255;
284 data[ 8] = 255;data[ 9] = 255;data[10] = 255;data[11] = 255;
285 data[12] = 255;data[13] = 255;data[14] = 255;data[15] = 255;
286 data[16] = 255;data[17] = 255;data[18] = 255;data[19] = 255;
287 data[20] = 255;data[21] = 255;data[22] = 255;data[23] = 255;
288 r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
291 static void R_BuildNormalizationCube(void)
295 vec_t s, t, intensity;
297 unsigned char data[6][NORMSIZE][NORMSIZE][4];
298 for (side = 0;side < 6;side++)
300 for (y = 0;y < NORMSIZE;y++)
302 for (x = 0;x < NORMSIZE;x++)
304 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
305 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
340 intensity = 127.0f / sqrt(DotProduct(v, v));
341 data[side][y][x][0] = (unsigned char)(128.0f + intensity * v[0]);
342 data[side][y][x][1] = (unsigned char)(128.0f + intensity * v[1]);
343 data[side][y][x][2] = (unsigned char)(128.0f + intensity * v[2]);
344 data[side][y][x][3] = 255;
348 r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, &data[0][0][0][0], TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_CLAMP, NULL);
351 static void R_BuildFogTexture(void)
355 unsigned char data1[FOGWIDTH][4];
356 //unsigned char data2[FOGWIDTH][4];
357 for (x = 0;x < FOGWIDTH;x++)
359 b = (int)(r_refdef.fogmasktable[x * (FOGMASKTABLEWIDTH - 1) / (FOGWIDTH - 1)] * 255);
364 //data2[x][0] = 255 - b;
365 //data2[x][1] = 255 - b;
366 //data2[x][2] = 255 - b;
369 r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
370 //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_RGBA, TEXF_PRECACHE | TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
373 static const char *builtinshaderstring =
374 "// ambient+diffuse+specular+normalmap+attenuation+cubemap+fog shader\n"
375 "// written by Forest 'LordHavoc' Hale\n"
377 "// common definitions between vertex shader and fragment shader:\n"
379 "#ifdef __GLSL_CG_DATA_TYPES\n"
380 "#define myhalf half\n"
381 "#define myhvec2 hvec2\n"
382 "#define myhvec3 hvec3\n"
383 "#define myhvec4 hvec4\n"
385 "#define myhalf float\n"
386 "#define myhvec2 vec2\n"
387 "#define myhvec3 vec3\n"
388 "#define myhvec4 vec4\n"
391 "varying vec2 TexCoord;\n"
392 "varying vec2 TexCoordLightmap;\n"
394 "varying vec3 CubeVector;\n"
395 "varying vec3 LightVector;\n"
396 "varying vec3 EyeVector;\n"
398 "varying vec3 EyeVectorModelSpace;\n"
401 "varying vec3 VectorS; // direction of S texcoord (sometimes crudely called tangent)\n"
402 "varying vec3 VectorT; // direction of T texcoord (sometimes crudely called binormal)\n"
403 "varying vec3 VectorR; // direction of R texcoord (surface normal)\n"
408 "// vertex shader specific:\n"
409 "#ifdef VERTEX_SHADER\n"
411 "uniform vec3 LightPosition;\n"
412 "uniform vec3 EyePosition;\n"
413 "uniform vec3 LightDir;\n"
415 "// TODO: get rid of tangentt (texcoord2) and use a crossproduct to regenerate it from tangents (texcoord1) and normal (texcoord3)\n"
419 " gl_FrontColor = gl_Color;\n"
420 " // copy the surface texcoord\n"
421 " TexCoord = vec2(gl_TextureMatrix[0] * gl_MultiTexCoord0);\n"
422 "#if !defined(MODE_LIGHTSOURCE) && !defined(MODE_LIGHTDIRECTION)\n"
423 " TexCoordLightmap = vec2(gl_MultiTexCoord4);\n"
426 "#ifdef MODE_LIGHTSOURCE\n"
427 " // transform vertex position into light attenuation/cubemap space\n"
428 " // (-1 to +1 across the light box)\n"
429 " CubeVector = vec3(gl_TextureMatrix[3] * gl_Vertex);\n"
431 " // transform unnormalized light direction into tangent space\n"
432 " // (we use unnormalized to ensure that it interpolates correctly and then\n"
433 " // normalize it per pixel)\n"
434 " vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;\n"
435 " LightVector.x = dot(lightminusvertex, gl_MultiTexCoord1.xyz);\n"
436 " LightVector.y = dot(lightminusvertex, gl_MultiTexCoord2.xyz);\n"
437 " LightVector.z = dot(lightminusvertex, gl_MultiTexCoord3.xyz);\n"
440 "#ifdef MODE_LIGHTDIRECTION\n"
441 " LightVector.x = dot(LightDir, gl_MultiTexCoord1.xyz);\n"
442 " LightVector.y = dot(LightDir, gl_MultiTexCoord2.xyz);\n"
443 " LightVector.z = dot(LightDir, gl_MultiTexCoord3.xyz);\n"
446 " // transform unnormalized eye direction into tangent space\n"
448 " vec3 EyeVectorModelSpace;\n"
450 " EyeVectorModelSpace = EyePosition - gl_Vertex.xyz;\n"
451 " EyeVector.x = dot(EyeVectorModelSpace, gl_MultiTexCoord1.xyz);\n"
452 " EyeVector.y = dot(EyeVectorModelSpace, gl_MultiTexCoord2.xyz);\n"
453 " EyeVector.z = dot(EyeVectorModelSpace, gl_MultiTexCoord3.xyz);\n"
455 "#ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
456 " VectorS = gl_MultiTexCoord1.xyz;\n"
457 " VectorT = gl_MultiTexCoord2.xyz;\n"
458 " VectorR = gl_MultiTexCoord3.xyz;\n"
461 " // transform vertex to camera space, using ftransform to match non-VS\n"
463 " gl_Position = ftransform();\n"
466 "#endif // VERTEX_SHADER\n"
471 "// fragment shader specific:\n"
472 "#ifdef FRAGMENT_SHADER\n"
474 "// 11 textures, we can only use up to 16 on DX9-class hardware\n"
475 "uniform sampler2D Texture_Normal;\n"
476 "uniform sampler2D Texture_Color;\n"
477 "uniform sampler2D Texture_Gloss;\n"
478 "uniform samplerCube Texture_Cube;\n"
479 "uniform sampler2D Texture_Attenuation;\n"
480 "uniform sampler2D Texture_FogMask;\n"
481 "uniform sampler2D Texture_Pants;\n"
482 "uniform sampler2D Texture_Shirt;\n"
483 "uniform sampler2D Texture_Lightmap;\n"
484 "uniform sampler2D Texture_Deluxemap;\n"
485 "uniform sampler2D Texture_Glow;\n"
487 "uniform myhvec3 LightColor;\n"
488 "uniform myhvec3 AmbientColor;\n"
489 "uniform myhvec3 DiffuseColor;\n"
490 "uniform myhvec3 SpecularColor;\n"
491 "uniform myhvec3 Color_Pants;\n"
492 "uniform myhvec3 Color_Shirt;\n"
493 "uniform myhvec3 FogColor;\n"
495 "uniform myhalf GlowScale;\n"
496 "uniform myhalf SceneBrightness;\n"
497 "#ifdef USECONTRASTBOOST\n"
498 "uniform myhalf ContrastBoostCoeff;\n"
501 "uniform float OffsetMapping_Scale;\n"
502 "uniform float OffsetMapping_Bias;\n"
503 "uniform float FogRangeRecip;\n"
505 "uniform myhalf AmbientScale;\n"
506 "uniform myhalf DiffuseScale;\n"
507 "uniform myhalf SpecularScale;\n"
508 "uniform myhalf SpecularPower;\n"
510 "#ifdef USEOFFSETMAPPING\n"
511 "vec2 OffsetMapping(vec2 TexCoord)\n"
513 "#ifdef USEOFFSETMAPPING_RELIEFMAPPING\n"
514 " // 14 sample relief mapping: linear search and then binary search\n"
515 " // this basically steps forward a small amount repeatedly until it finds\n"
516 " // itself inside solid, then jitters forward and back using decreasing\n"
517 " // amounts to find the impact\n"
518 " //vec3 OffsetVector = vec3(EyeVector.xy * ((1.0 / EyeVector.z) * OffsetMapping_Scale) * vec2(-1, 1), -1);\n"
519 " //vec3 OffsetVector = vec3(normalize(EyeVector.xy) * OffsetMapping_Scale * vec2(-1, 1), -1);\n"
520 " vec3 OffsetVector = vec3(normalize(EyeVector).xy * OffsetMapping_Scale * vec2(-1, 1), -1);\n"
521 " vec3 RT = vec3(TexCoord, 1);\n"
522 " OffsetVector *= 0.1;\n"
523 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
524 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
525 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
526 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
527 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
528 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
529 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
530 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
531 " RT += OffsetVector * step(texture2D(Texture_Normal, RT.xy).a, RT.z);\n"
532 " RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) - 0.5);\n"
533 " RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) * 0.5 - 0.25);\n"
534 " RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) * 0.25 - 0.125);\n"
535 " RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) * 0.125 - 0.0625);\n"
536 " RT += OffsetVector * (step(texture2D(Texture_Normal, RT.xy).a, RT.z) * 0.0625 - 0.03125);\n"
539 " // 3 sample offset mapping (only 3 samples because of ATI Radeon 9500-9800/X300 limits)\n"
540 " // this basically moves forward the full distance, and then backs up based\n"
541 " // on height of samples\n"
542 " //vec2 OffsetVector = vec2(EyeVector.xy * ((1.0 / EyeVector.z) * OffsetMapping_Scale) * vec2(-1, 1));\n"
543 " //vec2 OffsetVector = vec2(normalize(EyeVector.xy) * OffsetMapping_Scale * vec2(-1, 1));\n"
544 " vec2 OffsetVector = vec2(normalize(EyeVector).xy * OffsetMapping_Scale * vec2(-1, 1));\n"
545 " TexCoord += OffsetVector;\n"
546 " OffsetVector *= 0.333;\n"
547 " TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
548 " TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
549 " TexCoord -= OffsetVector * texture2D(Texture_Normal, TexCoord).a;\n"
550 " return TexCoord;\n"
557 "#ifdef USEOFFSETMAPPING\n"
558 " // apply offsetmapping\n"
559 " vec2 TexCoordOffset = OffsetMapping(TexCoord);\n"
560 "#define TexCoord TexCoordOffset\n"
563 " // combine the diffuse textures (base, pants, shirt)\n"
564 " myhvec4 color = myhvec4(texture2D(Texture_Color, TexCoord));\n"
565 "#ifdef USECOLORMAPPING\n"
566 " color.rgb += myhvec3(texture2D(Texture_Pants, TexCoord)) * Color_Pants + myhvec3(texture2D(Texture_Shirt, TexCoord)) * Color_Shirt;\n"
572 "#ifdef MODE_LIGHTSOURCE\n"
575 " // calculate surface normal, light normal, and specular normal\n"
576 " // compute color intensity for the two textures (colormap and glossmap)\n"
577 " // scale by light color and attenuation as efficiently as possible\n"
578 " // (do as much scalar math as possible rather than vector math)\n"
579 "#ifdef USESPECULAR\n"
580 " myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5));\n"
581 " myhvec3 diffusenormal = myhvec3(normalize(LightVector));\n"
582 " myhvec3 specularnormal = normalize(diffusenormal + myhvec3(normalize(EyeVector)));\n"
584 " // calculate directional shading\n"
585 " 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"
587 "#ifdef USEDIFFUSE\n"
588 " myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5));\n"
589 " myhvec3 diffusenormal = myhvec3(normalize(LightVector));\n"
591 " // calculate directional shading\n"
592 " 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"
594 " // calculate directionless shading\n"
595 " color.rgb = color.rgb * LightColor * myhalf(texture2D(Texture_Attenuation, vec2(length(CubeVector), 0.0)));\n"
599 "#ifdef USECUBEFILTER\n"
600 " // apply light cubemap filter\n"
601 " //color.rgb *= normalize(CubeVector) * 0.5 + 0.5;//vec3(textureCube(Texture_Cube, CubeVector));\n"
602 " color.rgb *= myhvec3(textureCube(Texture_Cube, CubeVector));\n"
608 "#elif defined(MODE_LIGHTDIRECTION)\n"
609 " // directional model lighting\n"
611 " // get the surface normal and light normal\n"
612 " myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5));\n"
613 " myhvec3 diffusenormal = myhvec3(LightVector);\n"
615 " // calculate directional shading\n"
616 " color.rgb *= AmbientColor + DiffuseColor * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0));\n"
617 "#ifdef USESPECULAR\n"
618 " myhvec3 specularnormal = normalize(diffusenormal + myhvec3(normalize(EyeVector)));\n"
619 " color.rgb += myhvec3(texture2D(Texture_Gloss, TexCoord)) * SpecularColor * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
625 "#elif defined(MODE_LIGHTDIRECTIONMAP_MODELSPACE) || defined(MODE_LIGHTDIRECTIONMAP_TANGENTSPACE)\n"
626 " // deluxemap lightmapping using light vectors in modelspace (evil q3map2)\n"
628 " // get the surface normal and light normal\n"
629 " myhvec3 surfacenormal = normalize(myhvec3(texture2D(Texture_Normal, TexCoord)) - myhvec3(0.5));\n"
631 "#ifdef MODE_LIGHTDIRECTIONMAP_MODELSPACE\n"
632 " myhvec3 diffusenormal_modelspace = myhvec3(texture2D(Texture_Deluxemap, TexCoordLightmap)) - myhvec3(0.5);\n"
633 " myhvec3 diffusenormal = normalize(myhvec3(dot(diffusenormal_modelspace, myhvec3(VectorS)), dot(diffusenormal_modelspace, myhvec3(VectorT)), dot(diffusenormal_modelspace, myhvec3(VectorR))));\n"
635 " myhvec3 diffusenormal = normalize(myhvec3(texture2D(Texture_Deluxemap, TexCoordLightmap)) - myhvec3(0.5));\n"
637 " // calculate directional shading\n"
638 " myhvec3 tempcolor = color.rgb * (DiffuseScale * myhalf(max(float(dot(surfacenormal, diffusenormal)), 0.0)));\n"
639 "#ifdef USESPECULAR\n"
640 " myhvec3 specularnormal = myhvec3(normalize(diffusenormal + myhvec3(normalize(EyeVector))));\n"
641 " tempcolor += myhvec3(texture2D(Texture_Gloss, TexCoord)) * SpecularScale * pow(myhalf(max(float(dot(surfacenormal, specularnormal)), 0.0)), SpecularPower);\n"
644 " // apply lightmap color\n"
645 " color.rgb = tempcolor * myhvec3(texture2D(Texture_Lightmap, TexCoordLightmap)) + color.rgb * AmbientScale;\n"
648 "#else // MODE none (lightmap)\n"
649 " // apply lightmap color\n"
650 " color.rgb *= myhvec3(texture2D(Texture_Lightmap, TexCoordLightmap)) * DiffuseScale + myhvec3(AmbientScale);\n"
653 " color *= myhvec4(gl_Color);\n"
656 " color.rgb += myhvec3(texture2D(Texture_Glow, TexCoord)) * GlowScale;\n"
661 " color.rgb = mix(FogColor, color.rgb, myhalf(texture2D(Texture_FogMask, myhvec2(length(EyeVectorModelSpace)*FogRangeRecip, 0.0))));\n"
664 "#ifdef USECONTRASTBOOST\n"
665 " color.rgb = color.rgb * SceneBrightness / (ContrastBoostCoeff * color.rgb + myhvec3(1, 1, 1));\n"
667 " color.rgb *= SceneBrightness;\n"
670 " gl_FragColor = vec4(color);\n"
673 "#endif // FRAGMENT_SHADER\n"
676 // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
677 const char *permutationinfo[][2] =
679 {"#define MODE_LIGHTSOURCE\n", " lightsource"},
680 {"#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
681 {"#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
682 {"#define MODE_LIGHTDIRECTION\n", " lightdirection"},
683 {"#define USEGLOW\n", " glow"},
684 {"#define USEFOG\n", " fog"},
685 {"#define USECOLORMAPPING\n", " colormapping"},
686 {"#define USEDIFFUSE\n", " diffuse"},
687 {"#define USECONTRASTBOOST\n", " contrastboost"},
688 {"#define USESPECULAR\n", " specular"},
689 {"#define USECUBEFILTER\n", " cubefilter"},
690 {"#define USEOFFSETMAPPING\n", " offsetmapping"},
691 {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
695 void R_GLSL_CompilePermutation(const char *filename, int permutation)
698 qboolean shaderfound;
699 r_glsl_permutation_t *p = r_glsl_permutations + (permutation & SHADERPERMUTATION_MASK);
700 int vertstrings_count;
701 int geomstrings_count;
702 int fragstrings_count;
704 const char *vertstrings_list[32+1];
705 const char *geomstrings_list[32+1];
706 const char *fragstrings_list[32+1];
707 char permutationname[256];
712 vertstrings_list[0] = "#define VERTEX_SHADER\n";
713 geomstrings_list[0] = "#define GEOMETRY_SHADER\n";
714 fragstrings_list[0] = "#define FRAGMENT_SHADER\n";
715 vertstrings_count = 1;
716 geomstrings_count = 1;
717 fragstrings_count = 1;
718 permutationname[0] = 0;
719 for (i = 0;permutationinfo[i][0];i++)
721 if (permutation & (1<<i))
723 vertstrings_list[vertstrings_count++] = permutationinfo[i][0];
724 geomstrings_list[geomstrings_count++] = permutationinfo[i][0];
725 fragstrings_list[fragstrings_count++] = permutationinfo[i][0];
726 strlcat(permutationname, permutationinfo[i][1], sizeof(permutationname));
730 // keep line numbers correct
731 vertstrings_list[vertstrings_count++] = "\n";
732 geomstrings_list[geomstrings_count++] = "\n";
733 fragstrings_list[fragstrings_count++] = "\n";
736 shaderstring = (char *)FS_LoadFile(filename, r_main_mempool, false, NULL);
740 Con_DPrintf("GLSL shader text for \"%s\" loaded from disk\n", filename);
741 vertstrings_list[vertstrings_count++] = shaderstring;
742 geomstrings_list[geomstrings_count++] = shaderstring;
743 fragstrings_list[fragstrings_count++] = shaderstring;
746 else if (!strcmp(filename, "glsl/default.glsl"))
748 Con_DPrintf("GLSL shader text for \"%s\" loaded from engine\n", filename);
749 vertstrings_list[vertstrings_count++] = builtinshaderstring;
750 geomstrings_list[geomstrings_count++] = builtinshaderstring;
751 fragstrings_list[fragstrings_count++] = builtinshaderstring;
754 // clear any lists that are not needed by this shader
755 if (!(permutation & SHADERPERMUTATION_USES_VERTEXSHADER))
756 vertstrings_count = 0;
757 if (!(permutation & SHADERPERMUTATION_USES_GEOMETRYSHADER))
758 geomstrings_count = 0;
759 if (!(permutation & SHADERPERMUTATION_USES_FRAGMENTSHADER))
760 fragstrings_count = 0;
761 // compile the shader program
762 if (shaderfound && vertstrings_count + geomstrings_count + fragstrings_count)
763 p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
767 qglUseProgramObjectARB(p->program);CHECKGLERROR
768 // look up all the uniform variable names we care about, so we don't
769 // have to look them up every time we set them
770 p->loc_Texture_Normal = qglGetUniformLocationARB(p->program, "Texture_Normal");
771 p->loc_Texture_Color = qglGetUniformLocationARB(p->program, "Texture_Color");
772 p->loc_Texture_Gloss = qglGetUniformLocationARB(p->program, "Texture_Gloss");
773 p->loc_Texture_Cube = qglGetUniformLocationARB(p->program, "Texture_Cube");
774 p->loc_Texture_Attenuation = qglGetUniformLocationARB(p->program, "Texture_Attenuation");
775 p->loc_Texture_FogMask = qglGetUniformLocationARB(p->program, "Texture_FogMask");
776 p->loc_Texture_Pants = qglGetUniformLocationARB(p->program, "Texture_Pants");
777 p->loc_Texture_Shirt = qglGetUniformLocationARB(p->program, "Texture_Shirt");
778 p->loc_Texture_Lightmap = qglGetUniformLocationARB(p->program, "Texture_Lightmap");
779 p->loc_Texture_Deluxemap = qglGetUniformLocationARB(p->program, "Texture_Deluxemap");
780 p->loc_Texture_Glow = qglGetUniformLocationARB(p->program, "Texture_Glow");
781 p->loc_FogColor = qglGetUniformLocationARB(p->program, "FogColor");
782 p->loc_LightPosition = qglGetUniformLocationARB(p->program, "LightPosition");
783 p->loc_EyePosition = qglGetUniformLocationARB(p->program, "EyePosition");
784 p->loc_LightColor = qglGetUniformLocationARB(p->program, "LightColor");
785 p->loc_Color_Pants = qglGetUniformLocationARB(p->program, "Color_Pants");
786 p->loc_Color_Shirt = qglGetUniformLocationARB(p->program, "Color_Shirt");
787 p->loc_FogRangeRecip = qglGetUniformLocationARB(p->program, "FogRangeRecip");
788 p->loc_AmbientScale = qglGetUniformLocationARB(p->program, "AmbientScale");
789 p->loc_DiffuseScale = qglGetUniformLocationARB(p->program, "DiffuseScale");
790 p->loc_SpecularPower = qglGetUniformLocationARB(p->program, "SpecularPower");
791 p->loc_SpecularScale = qglGetUniformLocationARB(p->program, "SpecularScale");
792 p->loc_GlowScale = qglGetUniformLocationARB(p->program, "GlowScale");
793 p->loc_SceneBrightness = qglGetUniformLocationARB(p->program, "SceneBrightness");
794 p->loc_OffsetMapping_Scale = qglGetUniformLocationARB(p->program, "OffsetMapping_Scale");
795 p->loc_AmbientColor = qglGetUniformLocationARB(p->program, "AmbientColor");
796 p->loc_DiffuseColor = qglGetUniformLocationARB(p->program, "DiffuseColor");
797 p->loc_SpecularColor = qglGetUniformLocationARB(p->program, "SpecularColor");
798 p->loc_LightDir = qglGetUniformLocationARB(p->program, "LightDir");
799 p->loc_ContrastBoostCoeff = qglGetUniformLocationARB(p->program, "ContrastBoostCoeff");
800 // initialize the samplers to refer to the texture units we use
801 if (p->loc_Texture_Normal >= 0) qglUniform1iARB(p->loc_Texture_Normal, 0);
802 if (p->loc_Texture_Color >= 0) qglUniform1iARB(p->loc_Texture_Color, 1);
803 if (p->loc_Texture_Gloss >= 0) qglUniform1iARB(p->loc_Texture_Gloss, 2);
804 if (p->loc_Texture_Cube >= 0) qglUniform1iARB(p->loc_Texture_Cube, 3);
805 if (p->loc_Texture_FogMask >= 0) qglUniform1iARB(p->loc_Texture_FogMask, 4);
806 if (p->loc_Texture_Pants >= 0) qglUniform1iARB(p->loc_Texture_Pants, 5);
807 if (p->loc_Texture_Shirt >= 0) qglUniform1iARB(p->loc_Texture_Shirt, 6);
808 if (p->loc_Texture_Lightmap >= 0) qglUniform1iARB(p->loc_Texture_Lightmap, 7);
809 if (p->loc_Texture_Deluxemap >= 0) qglUniform1iARB(p->loc_Texture_Deluxemap, 8);
810 if (p->loc_Texture_Glow >= 0) qglUniform1iARB(p->loc_Texture_Glow, 9);
811 if (p->loc_Texture_Attenuation >= 0) qglUniform1iARB(p->loc_Texture_Attenuation, 10);
813 qglUseProgramObjectARB(0);CHECKGLERROR
816 Con_Printf("permutation%s failed for shader %s, some features may not work properly!\n", permutationname, filename);
818 Mem_Free(shaderstring);
821 void R_GLSL_Restart_f(void)
824 for (i = 0;i < SHADERPERMUTATION_MAX;i++)
825 if (r_glsl_permutations[i].program)
826 GL_Backend_FreeProgram(r_glsl_permutations[i].program);
827 memset(r_glsl_permutations, 0, sizeof(r_glsl_permutations));
830 void R_GLSL_DumpShader_f(void)
834 qfile_t *file = FS_Open("glsl/default.glsl", "w", false, false);
837 Con_Printf("failed to write to glsl/default.glsl\n");
841 FS_Print(file, "// The engine may define the following macros:\n");
842 FS_Print(file, "// #define VERTEX_SHADER\n// #define GEOMETRY_SHADER\n// #define FRAGMENT_SHADER\n");
843 for (i = 0;permutationinfo[i][0];i++)
844 FS_Printf(file, "// %s", permutationinfo[i][0]);
845 FS_Print(file, "\n");
846 FS_Print(file, builtinshaderstring);
849 Con_Printf("glsl/default.glsl written\n");
852 extern rtexture_t *r_shadow_attenuationgradienttexture;
853 extern rtexture_t *r_shadow_attenuation2dtexture;
854 extern rtexture_t *r_shadow_attenuation3dtexture;
855 int R_SetupSurfaceShader(const vec3_t lightcolorbase, qboolean modellighting, float ambientscale, float diffusescale, float specularscale)
857 // select a permutation of the lighting shader appropriate to this
858 // combination of texture, entity, light source, and fogging, only use the
859 // minimum features necessary to avoid wasting rendering time in the
860 // fragment shader on features that are not being used
861 const char *shaderfilename = NULL;
862 unsigned int permutation = 0;
864 r_glsl_permutation = NULL;
865 // TODO: implement geometry-shader based shadow volumes someday
866 if (rsurface.rtlight)
869 shaderfilename = "glsl/default.glsl";
870 permutation = SHADERPERMUTATION_MODE_LIGHTSOURCE | SHADERPERMUTATION_USES_VERTEXSHADER | SHADERPERMUTATION_USES_FRAGMENTSHADER;
871 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
872 permutation |= SHADERPERMUTATION_CUBEFILTER;
873 if (diffusescale > 0)
874 permutation |= SHADERPERMUTATION_DIFFUSE;
875 if (specularscale > 0)
876 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
877 if (r_refdef.fogenabled)
878 permutation |= SHADERPERMUTATION_FOG;
879 if (rsurface.texture->colormapping)
880 permutation |= SHADERPERMUTATION_COLORMAPPING;
881 if (r_glsl_offsetmapping.integer)
883 permutation |= SHADERPERMUTATION_OFFSETMAPPING;
884 if (r_glsl_offsetmapping_reliefmapping.integer)
885 permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
887 if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
888 permutation |= SHADERPERMUTATION_CONTRASTBOOST;
890 else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
892 // bright unshaded geometry
893 shaderfilename = "glsl/default.glsl";
894 permutation = SHADERPERMUTATION_USES_VERTEXSHADER | SHADERPERMUTATION_USES_FRAGMENTSHADER;
895 if (rsurface.texture->currentskinframe->glow)
896 permutation |= SHADERPERMUTATION_GLOW;
897 if (r_refdef.fogenabled)
898 permutation |= SHADERPERMUTATION_FOG;
899 if (rsurface.texture->colormapping)
900 permutation |= SHADERPERMUTATION_COLORMAPPING;
901 if (r_glsl_offsetmapping.integer)
903 permutation |= SHADERPERMUTATION_OFFSETMAPPING;
904 if (r_glsl_offsetmapping_reliefmapping.integer)
905 permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
907 if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
908 permutation |= SHADERPERMUTATION_CONTRASTBOOST;
910 else if (modellighting)
912 // directional model lighting
913 shaderfilename = "glsl/default.glsl";
914 permutation = SHADERPERMUTATION_USES_VERTEXSHADER | SHADERPERMUTATION_USES_FRAGMENTSHADER;
915 permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTION;
916 if (rsurface.texture->currentskinframe->glow)
917 permutation |= SHADERPERMUTATION_GLOW;
918 if (specularscale > 0)
919 permutation |= SHADERPERMUTATION_SPECULAR;
920 if (r_refdef.fogenabled)
921 permutation |= SHADERPERMUTATION_FOG;
922 if (rsurface.texture->colormapping)
923 permutation |= SHADERPERMUTATION_COLORMAPPING;
924 if (r_glsl_offsetmapping.integer)
926 permutation |= SHADERPERMUTATION_OFFSETMAPPING;
927 if (r_glsl_offsetmapping_reliefmapping.integer)
928 permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
930 if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
931 permutation |= SHADERPERMUTATION_CONTRASTBOOST;
936 shaderfilename = "glsl/default.glsl";
937 permutation = SHADERPERMUTATION_USES_VERTEXSHADER | SHADERPERMUTATION_USES_FRAGMENTSHADER;
938 if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping)
940 // deluxemapping (light direction texture)
941 if (rsurface.uselightmaptexture && r_refdef.worldmodel && r_refdef.worldmodel->brushq3.deluxemapping && r_refdef.worldmodel->brushq3.deluxemapping_modelspace)
942 permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_MODELSPACE;
944 permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
945 if (specularscale > 0)
946 permutation |= SHADERPERMUTATION_SPECULAR;
948 else if (r_glsl_deluxemapping.integer >= 2)
950 // fake deluxemapping (uniform light direction in tangentspace)
951 permutation |= SHADERPERMUTATION_MODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
952 if (specularscale > 0)
953 permutation |= SHADERPERMUTATION_SPECULAR;
957 // ordinary lightmapping
960 if (rsurface.texture->currentskinframe->glow)
961 permutation |= SHADERPERMUTATION_GLOW;
962 if (r_refdef.fogenabled)
963 permutation |= SHADERPERMUTATION_FOG;
964 if (rsurface.texture->colormapping)
965 permutation |= SHADERPERMUTATION_COLORMAPPING;
966 if (r_glsl_offsetmapping.integer)
968 permutation |= SHADERPERMUTATION_OFFSETMAPPING;
969 if (r_glsl_offsetmapping_reliefmapping.integer)
970 permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;
972 if(r_glsl_contrastboost.value > 1 || r_glsl_contrastboost.value < 0)
973 permutation |= SHADERPERMUTATION_CONTRASTBOOST;
975 if (!r_glsl_permutations[permutation & SHADERPERMUTATION_MASK].program)
977 if (!r_glsl_permutations[permutation & SHADERPERMUTATION_MASK].compiled)
978 R_GLSL_CompilePermutation(shaderfilename, permutation);
979 if (!r_glsl_permutations[permutation & SHADERPERMUTATION_MASK].program)
981 // remove features until we find a valid permutation
983 for (i = (SHADERPERMUTATION_MAX >> 1);;i>>=1)
986 return 0; // no bit left to clear
987 // reduce i more quickly whenever it would not remove any bits
988 if (!(permutation & i))
991 if (!r_glsl_permutations[permutation & SHADERPERMUTATION_MASK].compiled)
992 R_GLSL_CompilePermutation(shaderfilename, permutation);
993 if (r_glsl_permutations[permutation & SHADERPERMUTATION_MASK].program)
998 r_glsl_permutation = r_glsl_permutations + (permutation & SHADERPERMUTATION_MASK);
1000 qglUseProgramObjectARB(r_glsl_permutation->program);CHECKGLERROR
1001 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
1002 if (permutation & SHADERPERMUTATION_MODE_LIGHTSOURCE)
1004 if (r_glsl_permutation->loc_Texture_Cube >= 0 && rsurface.rtlight) R_Mesh_TexBindCubeMap(3, R_GetTexture(rsurface.rtlight->currentcubemap));
1005 if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
1006 if (permutation & SHADERPERMUTATION_DIFFUSE)
1008 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightColor, lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);
1009 if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, ambientscale);
1010 if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, diffusescale);
1011 if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, specularscale);
1015 // ambient only is simpler
1016 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightColor, lightcolorbase[0] * ambientscale, lightcolorbase[1] * ambientscale, lightcolorbase[2] * ambientscale);
1017 if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, 1);
1018 if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, 0);
1019 if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, 0);
1022 else if (permutation & SHADERPERMUTATION_MODE_LIGHTDIRECTION)
1024 if (r_glsl_permutation->loc_AmbientColor >= 0)
1025 qglUniform3fARB(r_glsl_permutation->loc_AmbientColor, rsurface.modellight_ambient[0] * ambientscale, rsurface.modellight_ambient[1] * ambientscale, rsurface.modellight_ambient[2] * ambientscale);
1026 if (r_glsl_permutation->loc_DiffuseColor >= 0)
1027 qglUniform3fARB(r_glsl_permutation->loc_DiffuseColor, rsurface.modellight_diffuse[0] * diffusescale, rsurface.modellight_diffuse[1] * diffusescale, rsurface.modellight_diffuse[2] * diffusescale);
1028 if (r_glsl_permutation->loc_SpecularColor >= 0)
1029 qglUniform3fARB(r_glsl_permutation->loc_SpecularColor, rsurface.modellight_diffuse[0] * specularscale, rsurface.modellight_diffuse[1] * specularscale, rsurface.modellight_diffuse[2] * specularscale);
1030 if (r_glsl_permutation->loc_LightDir >= 0)
1031 qglUniform3fARB(r_glsl_permutation->loc_LightDir, rsurface.modellight_lightdir[0], rsurface.modellight_lightdir[1], rsurface.modellight_lightdir[2]);
1035 if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, r_ambient.value * 2.0f / 128.0f);
1036 if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, r_refdef.lightmapintensity * 2.0f);
1037 if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, r_refdef.lightmapintensity * specularscale * 2.0f);
1039 nmap = rsurface.texture->currentskinframe->nmap;
1040 if (gl_lightmaps.integer)
1041 nmap = r_texture_blanknormalmap;
1042 if (r_glsl_permutation->loc_Texture_Normal >= 0) R_Mesh_TexBind(0, R_GetTexture(nmap));
1043 if (r_glsl_permutation->loc_Texture_Color >= 0) R_Mesh_TexBind(1, R_GetTexture(rsurface.texture->basetexture));
1044 if (r_glsl_permutation->loc_Texture_Gloss >= 0) R_Mesh_TexBind(2, R_GetTexture(rsurface.texture->glosstexture));
1045 //if (r_glsl_permutation->loc_Texture_Cube >= 0 && permutation & SHADERPERMUTATION_MODE_LIGHTSOURCE) R_Mesh_TexBindCubeMap(3, R_GetTexture(rsurface.rtlight->currentcubemap));
1046 if (r_glsl_permutation->loc_Texture_Attenuation >= 0) R_Mesh_TexBind(10, R_GetTexture(r_shadow_attenuationgradienttexture));
1047 if (r_glsl_permutation->loc_Texture_FogMask >= 0) R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation));
1048 if (r_glsl_permutation->loc_Texture_Pants >= 0) R_Mesh_TexBind(5, R_GetTexture(rsurface.texture->currentskinframe->pants));
1049 if (r_glsl_permutation->loc_Texture_Shirt >= 0) R_Mesh_TexBind(6, R_GetTexture(rsurface.texture->currentskinframe->shirt));
1050 //if (r_glsl_permutation->loc_Texture_Lightmap >= 0) R_Mesh_TexBind(7, R_GetTexture(r_texture_white));
1051 //if (r_glsl_permutation->loc_Texture_Deluxemap >= 0) R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
1052 if (r_glsl_permutation->loc_Texture_Glow >= 0) R_Mesh_TexBind(9, R_GetTexture(rsurface.texture->currentskinframe->glow));
1053 if (r_glsl_permutation->loc_GlowScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_GlowScale, r_hdr_glowintensity.value);
1054 if (r_glsl_permutation->loc_ContrastBoostCoeff >= 0)
1056 // The formula used is actually:
1057 // color.rgb *= SceneBrightness;
1058 // color.rgb *= ContrastBoost / ((ContrastBoost - 1) * color.rgb + 1);
1059 // I simplify that to
1060 // color.rgb *= [[SceneBrightness * ContrastBoost]];
1061 // color.rgb /= [[(ContrastBoost - 1) / ContrastBoost]] * color.rgb + 1;
1063 // color.rgb = [[SceneBrightness * ContrastBoost]] / ([[(ContrastBoost - 1) * SceneBrightness]] + 1 / color.rgb);
1064 // and do [[calculations]] here in the engine
1065 qglUniform1fARB(r_glsl_permutation->loc_ContrastBoostCoeff, (r_glsl_contrastboost.value - 1) * r_view.colorscale);
1066 if (r_glsl_permutation->loc_SceneBrightness >= 0) qglUniform1fARB(r_glsl_permutation->loc_SceneBrightness, r_view.colorscale * r_glsl_contrastboost.value);
1069 if (r_glsl_permutation->loc_SceneBrightness >= 0) qglUniform1fARB(r_glsl_permutation->loc_SceneBrightness, r_view.colorscale);
1070 if (r_glsl_permutation->loc_FogColor >= 0)
1072 // additive passes are only darkened by fog, not tinted
1073 if (rsurface.rtlight || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ADD))
1074 qglUniform3fARB(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1076 qglUniform3fARB(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1078 if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_EyePosition, rsurface.modelorg[0], rsurface.modelorg[1], rsurface.modelorg[2]);
1079 if (r_glsl_permutation->loc_Color_Pants >= 0)
1081 if (rsurface.texture->currentskinframe->pants)
1082 qglUniform3fARB(r_glsl_permutation->loc_Color_Pants, rsurface.colormap_pantscolor[0], rsurface.colormap_pantscolor[1], rsurface.colormap_pantscolor[2]);
1084 qglUniform3fARB(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
1086 if (r_glsl_permutation->loc_Color_Shirt >= 0)
1088 if (rsurface.texture->currentskinframe->shirt)
1089 qglUniform3fARB(r_glsl_permutation->loc_Color_Shirt, rsurface.colormap_shirtcolor[0], rsurface.colormap_shirtcolor[1], rsurface.colormap_shirtcolor[2]);
1091 qglUniform3fARB(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
1093 if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1fARB(r_glsl_permutation->loc_FogRangeRecip, r_refdef.fograngerecip);
1094 if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularPower, rsurface.texture->specularpower);
1095 if (r_glsl_permutation->loc_OffsetMapping_Scale >= 0) qglUniform1fARB(r_glsl_permutation->loc_OffsetMapping_Scale, r_glsl_offsetmapping_scale.value);
1100 void R_SwitchSurfaceShader(int permutation)
1102 if (r_glsl_permutation != r_glsl_permutations + (permutation & SHADERPERMUTATION_MASK))
1104 r_glsl_permutation = r_glsl_permutations + (permutation & SHADERPERMUTATION_MASK);
1106 qglUseProgramObjectARB(r_glsl_permutation->program);
1111 #define SKINFRAME_HASH 1024
1115 int loadsequence; // incremented each level change
1116 memexpandablearray_t array;
1117 skinframe_t *hash[SKINFRAME_HASH];
1121 void R_SkinFrame_PrepareForPurge(void)
1123 r_skinframe.loadsequence++;
1124 // wrap it without hitting zero
1125 if (r_skinframe.loadsequence >= 200)
1126 r_skinframe.loadsequence = 1;
1129 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
1133 // mark the skinframe as used for the purging code
1134 skinframe->loadsequence = r_skinframe.loadsequence;
1137 void R_SkinFrame_Purge(void)
1141 for (i = 0;i < SKINFRAME_HASH;i++)
1143 for (s = r_skinframe.hash[i];s;s = s->next)
1145 if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
1147 if (s->base == r_texture_notexture) s->base = NULL;
1148 if (s->nmap == r_texture_blanknormalmap)s->nmap = NULL;
1149 if (s->merged == s->base) s->merged = NULL;
1150 if (s->stain ) R_FreeTexture(s->stain );s->stain = NULL;
1151 if (s->merged) R_FreeTexture(s->merged);s->merged = NULL;
1152 if (s->base ) R_FreeTexture(s->base );s->base = NULL;
1153 if (s->pants ) R_FreeTexture(s->pants );s->pants = NULL;
1154 if (s->shirt ) R_FreeTexture(s->shirt );s->shirt = NULL;
1155 if (s->nmap ) R_FreeTexture(s->nmap );s->nmap = NULL;
1156 if (s->gloss ) R_FreeTexture(s->gloss );s->gloss = NULL;
1157 if (s->glow ) R_FreeTexture(s->glow );s->glow = NULL;
1158 if (s->fog ) R_FreeTexture(s->fog );s->fog = NULL;
1159 s->loadsequence = 0;
1165 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qboolean add)
1169 char basename[MAX_QPATH];
1171 Image_StripImageExtension(name, basename, sizeof(basename));
1173 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
1174 for (item = r_skinframe.hash[hashindex];item;item = item->next)
1175 if (!strcmp(item->basename, basename) && item->textureflags == textureflags && item->comparewidth == comparewidth && item->compareheight == compareheight && item->comparecrc == comparecrc)
1181 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
1182 memset(item, 0, sizeof(*item));
1183 strlcpy(item->basename, basename, sizeof(item->basename));
1184 item->textureflags = textureflags;
1185 item->comparewidth = comparewidth;
1186 item->compareheight = compareheight;
1187 item->comparecrc = comparecrc;
1188 item->next = r_skinframe.hash[hashindex];
1189 r_skinframe.hash[hashindex] = item;
1191 R_SkinFrame_MarkUsed(item);
1195 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain)
1197 // FIXME: it should be possible to disable loading various layers using
1198 // cvars, to prevent wasted loading time and memory usage if the user does
1200 qboolean loadnormalmap = true;
1201 qboolean loadgloss = true;
1202 qboolean loadpantsandshirt = true;
1203 qboolean loadglow = true;
1205 unsigned char *pixels;
1206 unsigned char *bumppixels;
1207 unsigned char *basepixels = NULL;
1208 int basepixels_width;
1209 int basepixels_height;
1210 skinframe_t *skinframe;
1212 if (cls.state == ca_dedicated)
1215 // return an existing skinframe if already loaded
1216 // if loading of the first image fails, don't make a new skinframe as it
1217 // would cause all future lookups of this to be missing
1218 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
1219 if (skinframe && skinframe->base)
1222 basepixels = loadimagepixels(name, complain, 0, 0);
1223 if (basepixels == NULL)
1226 // we've got some pixels to store, so really allocate this new texture now
1228 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
1229 skinframe->stain = NULL;
1230 skinframe->merged = NULL;
1231 skinframe->base = r_texture_notexture;
1232 skinframe->pants = NULL;
1233 skinframe->shirt = NULL;
1234 skinframe->nmap = r_texture_blanknormalmap;
1235 skinframe->gloss = NULL;
1236 skinframe->glow = NULL;
1237 skinframe->fog = NULL;
1239 basepixels_width = image_width;
1240 basepixels_height = image_height;
1241 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);
1243 if (textureflags & TEXF_ALPHA)
1245 for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
1246 if (basepixels[j] < 255)
1248 if (j < basepixels_width * basepixels_height * 4)
1250 // has transparent pixels
1251 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
1252 for (j = 0;j < image_width * image_height * 4;j += 4)
1257 pixels[j+3] = basepixels[j+3];
1259 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);
1264 // _norm is the name used by tenebrae and has been adopted as standard
1267 if ((pixels = loadimagepixels(va("%s_norm", skinframe->basename), false, 0, 0)) != NULL)
1269 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);
1273 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixels(va("%s_bump", skinframe->basename), false, 0, 0)) != NULL)
1275 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
1276 Image_HeightmapToNormalmap(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
1277 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);
1279 Mem_Free(bumppixels);
1281 else if (r_shadow_bumpscale_basetexture.value > 0)
1283 pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
1284 Image_HeightmapToNormalmap(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
1285 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);
1289 // _luma is supported for tenebrae compatibility
1290 // (I think it's a very stupid name, but oh well)
1291 // _glow is the preferred name
1292 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;}
1293 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;}
1294 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;}
1295 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;}
1298 Mem_Free(basepixels);
1303 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)
1308 for (i = 0;i < width*height;i++)
1309 if (((unsigned char *)&palette[in[i]])[3] > 0)
1311 if (i == width*height)
1314 return R_LoadTexture2D (r_main_texturepool, name, width, height, in, TEXTYPE_PALETTE, textureflags, palette);
1317 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)
1320 unsigned char *temp1, *temp2;
1321 skinframe_t *skinframe;
1323 if (cls.state == ca_dedicated)
1326 // if already loaded just return it, otherwise make a new skinframe
1327 skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height*bitsperpixel/8) : 0, true);
1328 if (skinframe && skinframe->base)
1331 skinframe->stain = NULL;
1332 skinframe->merged = NULL;
1333 skinframe->base = r_texture_notexture;
1334 skinframe->pants = NULL;
1335 skinframe->shirt = NULL;
1336 skinframe->nmap = r_texture_blanknormalmap;
1337 skinframe->gloss = NULL;
1338 skinframe->glow = NULL;
1339 skinframe->fog = NULL;
1341 // if no data was provided, then clearly the caller wanted to get a blank skinframe
1345 if (bitsperpixel == 32)
1347 if (r_shadow_bumpscale_basetexture.value > 0)
1349 temp1 = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
1350 temp2 = temp1 + width * height * 4;
1351 Image_HeightmapToNormalmap(skindata, temp2, width, height, false, r_shadow_bumpscale_basetexture.value);
1352 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va("%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_RGBA, skinframe->textureflags | TEXF_ALPHA, NULL);
1355 skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_RGBA, skinframe->textureflags, NULL);
1356 if (textureflags & TEXF_ALPHA)
1358 for (i = 3;i < width * height * 4;i += 4)
1359 if (skindata[i] < 255)
1361 if (i < width * height * 4)
1363 unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
1364 memcpy(fogpixels, skindata, width * height * 4);
1365 for (i = 0;i < width * height * 4;i += 4)
1366 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
1367 skinframe->fog = R_LoadTexture2D(r_main_texturepool, va("%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_RGBA, skinframe->textureflags, NULL);
1368 Mem_Free(fogpixels);
1372 else if (bitsperpixel == 8)
1374 if (r_shadow_bumpscale_basetexture.value > 0)
1376 temp1 = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
1377 temp2 = temp1 + width * height * 4;
1378 if (bitsperpixel == 32)
1379 Image_HeightmapToNormalmap(skindata, temp2, width, height, false, r_shadow_bumpscale_basetexture.value);
1382 // use either a custom palette or the quake palette
1383 Image_Copy8bitRGBA(skindata, temp1, width * height, palette ? palette : palette_complete);
1384 Image_HeightmapToNormalmap(temp1, temp2, width, height, false, r_shadow_bumpscale_basetexture.value);
1386 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va("%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_RGBA, skinframe->textureflags | TEXF_ALPHA, NULL);
1389 // use either a custom palette, or the quake palette
1390 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
1391 if (!palette && loadglowtexture)
1392 skinframe->glow = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_glow", skinframe->basename), palette_onlyfullbrights, skinframe->textureflags, false); // glow
1393 if (!palette && loadpantsandshirt)
1395 skinframe->pants = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_pants", skinframe->basename), palette_pantsaswhite, skinframe->textureflags, false); // pants
1396 skinframe->shirt = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_shirt", skinframe->basename), palette_shirtaswhite, skinframe->textureflags, false); // shirt
1398 if (skinframe->pants || skinframe->shirt)
1399 skinframe->base = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_nospecial", skinframe->basename),loadglowtexture ? palette_nocolormapnofullbrights : palette_nocolormap, skinframe->textureflags, false); // no special colors
1400 if (textureflags & TEXF_ALPHA)
1402 // if not using a custom alphapalette, use the quake one
1404 alphapalette = palette_alpha;
1405 for (i = 0;i < width * height;i++)
1406 if (((unsigned char *)alphapalette)[skindata[i]*4+3] < 255)
1408 if (i < width * height)
1409 skinframe->fog = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_fog", skinframe->basename), alphapalette, skinframe->textureflags, true); // fog mask
1416 skinframe_t *R_SkinFrame_LoadMissing(void)
1418 skinframe_t *skinframe;
1420 if (cls.state == ca_dedicated)
1423 skinframe = R_SkinFrame_Find("missing", TEXF_PRECACHE, 0, 0, 0, true);
1424 skinframe->stain = NULL;
1425 skinframe->merged = NULL;
1426 skinframe->base = r_texture_notexture;
1427 skinframe->pants = NULL;
1428 skinframe->shirt = NULL;
1429 skinframe->nmap = r_texture_blanknormalmap;
1430 skinframe->gloss = NULL;
1431 skinframe->glow = NULL;
1432 skinframe->fog = NULL;
1437 void gl_main_start(void)
1442 r = (-1.0/256.0) * (FOGMASKTABLEWIDTH * FOGMASKTABLEWIDTH);
1443 for (x = 0;x < FOGMASKTABLEWIDTH;x++)
1445 alpha = 1 - exp(r / ((double)x*(double)x));
1446 if (x == FOGMASKTABLEWIDTH - 1)
1448 r_refdef.fogmasktable[x] = bound(0, alpha, 1);
1451 memset(r_qwskincache, 0, sizeof(r_qwskincache));
1452 memset(r_qwskincache_skinframe, 0, sizeof(r_qwskincache_skinframe));
1454 // set up r_skinframe loading system for textures
1455 memset(&r_skinframe, 0, sizeof(r_skinframe));
1456 r_skinframe.loadsequence = 1;
1457 Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
1459 r_main_texturepool = R_AllocTexturePool();
1460 R_BuildBlankTextures();
1462 if (gl_texturecubemap)
1465 R_BuildNormalizationCube();
1467 R_BuildFogTexture();
1468 memset(&r_bloomstate, 0, sizeof(r_bloomstate));
1469 memset(r_glsl_permutations, 0, sizeof(r_glsl_permutations));
1470 memset(&r_svbsp, 0, sizeof (r_svbsp));
1473 void gl_main_shutdown(void)
1475 memset(r_qwskincache, 0, sizeof(r_qwskincache));
1476 memset(r_qwskincache_skinframe, 0, sizeof(r_qwskincache_skinframe));
1478 // clear out the r_skinframe state
1479 Mem_ExpandableArray_FreeArray(&r_skinframe.array);
1480 memset(&r_skinframe, 0, sizeof(r_skinframe));
1483 Mem_Free(r_svbsp.nodes);
1484 memset(&r_svbsp, 0, sizeof (r_svbsp));
1485 R_FreeTexturePool(&r_main_texturepool);
1486 r_texture_blanknormalmap = NULL;
1487 r_texture_white = NULL;
1488 r_texture_grey128 = NULL;
1489 r_texture_black = NULL;
1490 r_texture_whitecube = NULL;
1491 r_texture_normalizationcube = NULL;
1492 memset(&r_bloomstate, 0, sizeof(r_bloomstate));
1496 extern void CL_ParseEntityLump(char *entitystring);
1497 void gl_main_newmap(void)
1499 // FIXME: move this code to client
1501 char *entities, entname[MAX_QPATH];
1504 strlcpy(entname, cl.worldmodel->name, sizeof(entname));
1505 l = (int)strlen(entname) - 4;
1506 if (l >= 0 && !strcmp(entname + l, ".bsp"))
1508 memcpy(entname + l, ".ent", 5);
1509 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
1511 CL_ParseEntityLump(entities);
1516 if (cl.worldmodel->brush.entities)
1517 CL_ParseEntityLump(cl.worldmodel->brush.entities);
1521 void GL_Main_Init(void)
1523 r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
1525 Cmd_AddCommand("r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
1526 Cmd_AddCommand("r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
1527 // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
1528 if (gamemode == GAME_NEHAHRA)
1530 Cvar_RegisterVariable (&gl_fogenable);
1531 Cvar_RegisterVariable (&gl_fogdensity);
1532 Cvar_RegisterVariable (&gl_fogred);
1533 Cvar_RegisterVariable (&gl_foggreen);
1534 Cvar_RegisterVariable (&gl_fogblue);
1535 Cvar_RegisterVariable (&gl_fogstart);
1536 Cvar_RegisterVariable (&gl_fogend);
1538 Cvar_RegisterVariable(&r_depthfirst);
1539 Cvar_RegisterVariable(&r_nearclip);
1540 Cvar_RegisterVariable(&r_showbboxes);
1541 Cvar_RegisterVariable(&r_showsurfaces);
1542 Cvar_RegisterVariable(&r_showtris);
1543 Cvar_RegisterVariable(&r_shownormals);
1544 Cvar_RegisterVariable(&r_showlighting);
1545 Cvar_RegisterVariable(&r_showshadowvolumes);
1546 Cvar_RegisterVariable(&r_showcollisionbrushes);
1547 Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
1548 Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
1549 Cvar_RegisterVariable(&r_showdisabledepthtest);
1550 Cvar_RegisterVariable(&r_drawportals);
1551 Cvar_RegisterVariable(&r_drawentities);
1552 Cvar_RegisterVariable(&r_cullentities_trace);
1553 Cvar_RegisterVariable(&r_cullentities_trace_samples);
1554 Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
1555 Cvar_RegisterVariable(&r_cullentities_trace_delay);
1556 Cvar_RegisterVariable(&r_drawviewmodel);
1557 Cvar_RegisterVariable(&r_speeds);
1558 Cvar_RegisterVariable(&r_fullbrights);
1559 Cvar_RegisterVariable(&r_wateralpha);
1560 Cvar_RegisterVariable(&r_dynamic);
1561 Cvar_RegisterVariable(&r_fullbright);
1562 Cvar_RegisterVariable(&r_shadows);
1563 Cvar_RegisterVariable(&r_shadows_throwdistance);
1564 Cvar_RegisterVariable(&r_q1bsp_skymasking);
1565 Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
1566 Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
1567 Cvar_RegisterVariable(&r_textureunits);
1568 Cvar_RegisterVariable(&r_glsl);
1569 Cvar_RegisterVariable(&r_glsl_offsetmapping);
1570 Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
1571 Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
1572 Cvar_RegisterVariable(&r_glsl_deluxemapping);
1573 Cvar_RegisterVariable(&r_lerpsprites);
1574 Cvar_RegisterVariable(&r_lerpmodels);
1575 Cvar_RegisterVariable(&r_waterscroll);
1576 Cvar_RegisterVariable(&r_bloom);
1577 Cvar_RegisterVariable(&r_bloom_colorscale);
1578 Cvar_RegisterVariable(&r_bloom_brighten);
1579 Cvar_RegisterVariable(&r_bloom_blur);
1580 Cvar_RegisterVariable(&r_bloom_resolution);
1581 Cvar_RegisterVariable(&r_bloom_colorexponent);
1582 Cvar_RegisterVariable(&r_bloom_colorsubtract);
1583 Cvar_RegisterVariable(&r_hdr);
1584 Cvar_RegisterVariable(&r_hdr_scenebrightness);
1585 Cvar_RegisterVariable(&r_glsl_contrastboost);
1586 Cvar_RegisterVariable(&r_hdr_glowintensity);
1587 Cvar_RegisterVariable(&r_hdr_range);
1588 Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
1589 Cvar_RegisterVariable(&developer_texturelogging);
1590 Cvar_RegisterVariable(&gl_lightmaps);
1591 Cvar_RegisterVariable(&r_test);
1592 Cvar_RegisterVariable(&r_batchmode);
1593 if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
1594 Cvar_SetValue("r_fullbrights", 0);
1595 R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
1598 extern void R_Textures_Init(void);
1599 extern void GL_Draw_Init(void);
1600 extern void GL_Main_Init(void);
1601 extern void R_Shadow_Init(void);
1602 extern void R_Sky_Init(void);
1603 extern void GL_Surf_Init(void);
1604 extern void R_Light_Init(void);
1605 extern void R_Particles_Init(void);
1606 extern void R_Explosion_Init(void);
1607 extern void gl_backend_init(void);
1608 extern void Sbar_Init(void);
1609 extern void R_LightningBeams_Init(void);
1610 extern void Mod_RenderInit(void);
1612 void Render_Init(void)
1625 R_LightningBeams_Init();
1634 extern char *ENGINE_EXTENSIONS;
1637 VID_CheckExtensions();
1639 // LordHavoc: report supported extensions
1640 Con_DPrintf("\nQuakeC extensions for server and client: %s\nQuakeC extensions for menu: %s\n", vm_sv_extensions, vm_m_extensions );
1642 // clear to black (loading plaque will be seen over this)
1644 qglClearColor(0,0,0,1);CHECKGLERROR
1645 qglClear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
1648 int R_CullBox(const vec3_t mins, const vec3_t maxs)
1652 for (i = 0;i < 4;i++)
1654 p = r_view.frustum + i;
1659 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
1663 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
1667 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
1671 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
1675 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
1679 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
1683 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
1687 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
1695 int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
1699 for (i = 0;i < numplanes;i++)
1706 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
1710 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
1714 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
1718 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
1722 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
1726 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
1730 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
1734 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
1742 //==================================================================================
1744 static void R_UpdateEntityLighting(entity_render_t *ent)
1746 vec3_t tempdiffusenormal;
1748 // fetch the lighting from the worldmodel data
1749 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));
1750 VectorClear(ent->modellight_diffuse);
1751 VectorClear(tempdiffusenormal);
1752 if ((ent->flags & RENDER_LIGHT) && r_refdef.worldmodel && r_refdef.worldmodel->brush.LightPoint)
1755 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
1756 r_refdef.worldmodel->brush.LightPoint(r_refdef.worldmodel, org, ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal);
1759 VectorSet(ent->modellight_ambient, 1, 1, 1);
1761 // move the light direction into modelspace coordinates for lighting code
1762 Matrix4x4_Transform3x3(&ent->inversematrix, tempdiffusenormal, ent->modellight_lightdir);
1763 if(VectorLength2(ent->modellight_lightdir) > 0)
1765 VectorNormalize(ent->modellight_lightdir);
1769 VectorSet(ent->modellight_lightdir, 0, 0, 1); // have to set SOME valid vector here
1772 // scale ambient and directional light contributions according to rendering variables
1773 ent->modellight_ambient[0] *= ent->colormod[0] * r_refdef.lightmapintensity;
1774 ent->modellight_ambient[1] *= ent->colormod[1] * r_refdef.lightmapintensity;
1775 ent->modellight_ambient[2] *= ent->colormod[2] * r_refdef.lightmapintensity;
1776 ent->modellight_diffuse[0] *= ent->colormod[0] * r_refdef.lightmapintensity;
1777 ent->modellight_diffuse[1] *= ent->colormod[1] * r_refdef.lightmapintensity;
1778 ent->modellight_diffuse[2] *= ent->colormod[2] * r_refdef.lightmapintensity;
1781 static void R_View_UpdateEntityVisible (void)
1784 entity_render_t *ent;
1786 if (!r_drawentities.integer)
1789 renderimask = r_refdef.envmap ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL) : (chase_active.integer ? 0 : RENDER_EXTERIORMODEL);
1790 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingVisibleLeafs)
1792 // worldmodel can check visibility
1793 for (i = 0;i < r_refdef.numentities;i++)
1795 ent = r_refdef.entities[i];
1796 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));
1798 if(r_cullentities_trace.integer)
1800 for (i = 0;i < r_refdef.numentities;i++)
1802 ent = r_refdef.entities[i];
1803 if(r_viewcache.entityvisible[i] && !(ent->effects & EF_NODEPTHTEST) && !(ent->flags & RENDER_VIEWMODEL) && !(ent->model && (ent->model->name[0] == '*')))
1805 if(Mod_CanSeeBox_Trace(r_cullentities_trace_samples.integer, r_cullentities_trace_enlarge.value, r_refdef.worldmodel, r_view.origin, ent->mins, ent->maxs))
1806 ent->last_trace_visibility = realtime;
1807 if(ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
1808 r_viewcache.entityvisible[i] = 0;
1815 // no worldmodel or it can't check visibility
1816 for (i = 0;i < r_refdef.numentities;i++)
1818 ent = r_refdef.entities[i];
1819 r_viewcache.entityvisible[i] = !(ent->flags & renderimask) && !R_CullBox(ent->mins, ent->maxs);
1823 // update entity lighting (even on hidden entities for r_shadows)
1824 for (i = 0;i < r_refdef.numentities;i++)
1825 R_UpdateEntityLighting(r_refdef.entities[i]);
1828 // only used if skyrendermasked, and normally returns false
1829 int R_DrawBrushModelsSky (void)
1832 entity_render_t *ent;
1834 if (!r_drawentities.integer)
1838 for (i = 0;i < r_refdef.numentities;i++)
1840 if (!r_viewcache.entityvisible[i])
1842 ent = r_refdef.entities[i];
1843 if (!ent->model || !ent->model->DrawSky)
1845 ent->model->DrawSky(ent);
1851 void R_DrawNoModel(entity_render_t *ent);
1852 void R_DrawModels(void)
1855 entity_render_t *ent;
1857 if (!r_drawentities.integer)
1860 for (i = 0;i < r_refdef.numentities;i++)
1862 if (!r_viewcache.entityvisible[i])
1864 ent = r_refdef.entities[i];
1865 r_refdef.stats.entities++;
1866 if (ent->model && ent->model->Draw != NULL)
1867 ent->model->Draw(ent);
1873 void R_DrawModelsDepth(void)
1876 entity_render_t *ent;
1878 if (!r_drawentities.integer)
1881 for (i = 0;i < r_refdef.numentities;i++)
1883 if (!r_viewcache.entityvisible[i])
1885 ent = r_refdef.entities[i];
1886 r_refdef.stats.entities++;
1887 if (ent->model && ent->model->DrawDepth != NULL)
1888 ent->model->DrawDepth(ent);
1892 static void R_View_SetFrustum(void)
1894 double slopex, slopey;
1896 // break apart the view matrix into vectors for various purposes
1897 Matrix4x4_ToVectors(&r_view.matrix, r_view.forward, r_view.left, r_view.up, r_view.origin);
1898 VectorNegate(r_view.left, r_view.right);
1901 r_view.frustum[0].normal[0] = 0 - 1.0 / r_view.frustum_x;
1902 r_view.frustum[0].normal[1] = 0 - 0;
1903 r_view.frustum[0].normal[2] = -1 - 0;
1904 r_view.frustum[1].normal[0] = 0 + 1.0 / r_view.frustum_x;
1905 r_view.frustum[1].normal[1] = 0 + 0;
1906 r_view.frustum[1].normal[2] = -1 + 0;
1907 r_view.frustum[2].normal[0] = 0 - 0;
1908 r_view.frustum[2].normal[1] = 0 - 1.0 / r_view.frustum_y;
1909 r_view.frustum[2].normal[2] = -1 - 0;
1910 r_view.frustum[3].normal[0] = 0 + 0;
1911 r_view.frustum[3].normal[1] = 0 + 1.0 / r_view.frustum_y;
1912 r_view.frustum[3].normal[2] = -1 + 0;
1916 zNear = r_refdef.nearclip;
1917 nudge = 1.0 - 1.0 / (1<<23);
1918 r_view.frustum[4].normal[0] = 0 - 0;
1919 r_view.frustum[4].normal[1] = 0 - 0;
1920 r_view.frustum[4].normal[2] = -1 - -nudge;
1921 r_view.frustum[4].dist = 0 - -2 * zNear * nudge;
1922 r_view.frustum[5].normal[0] = 0 + 0;
1923 r_view.frustum[5].normal[1] = 0 + 0;
1924 r_view.frustum[5].normal[2] = -1 + -nudge;
1925 r_view.frustum[5].dist = 0 + -2 * zNear * nudge;
1931 r_view.frustum[0].normal[0] = m[3] - m[0];
1932 r_view.frustum[0].normal[1] = m[7] - m[4];
1933 r_view.frustum[0].normal[2] = m[11] - m[8];
1934 r_view.frustum[0].dist = m[15] - m[12];
1936 r_view.frustum[1].normal[0] = m[3] + m[0];
1937 r_view.frustum[1].normal[1] = m[7] + m[4];
1938 r_view.frustum[1].normal[2] = m[11] + m[8];
1939 r_view.frustum[1].dist = m[15] + m[12];
1941 r_view.frustum[2].normal[0] = m[3] - m[1];
1942 r_view.frustum[2].normal[1] = m[7] - m[5];
1943 r_view.frustum[2].normal[2] = m[11] - m[9];
1944 r_view.frustum[2].dist = m[15] - m[13];
1946 r_view.frustum[3].normal[0] = m[3] + m[1];
1947 r_view.frustum[3].normal[1] = m[7] + m[5];
1948 r_view.frustum[3].normal[2] = m[11] + m[9];
1949 r_view.frustum[3].dist = m[15] + m[13];
1951 r_view.frustum[4].normal[0] = m[3] - m[2];
1952 r_view.frustum[4].normal[1] = m[7] - m[6];
1953 r_view.frustum[4].normal[2] = m[11] - m[10];
1954 r_view.frustum[4].dist = m[15] - m[14];
1956 r_view.frustum[5].normal[0] = m[3] + m[2];
1957 r_view.frustum[5].normal[1] = m[7] + m[6];
1958 r_view.frustum[5].normal[2] = m[11] + m[10];
1959 r_view.frustum[5].dist = m[15] + m[14];
1964 if (r_view.useperspective)
1966 slopex = 1.0 / r_view.frustum_x;
1967 slopey = 1.0 / r_view.frustum_y;
1968 VectorMA(r_view.forward, -slopex, r_view.left, r_view.frustum[0].normal);
1969 VectorMA(r_view.forward, slopex, r_view.left, r_view.frustum[1].normal);
1970 VectorMA(r_view.forward, -slopey, r_view.up , r_view.frustum[2].normal);
1971 VectorMA(r_view.forward, slopey, r_view.up , r_view.frustum[3].normal);
1972 VectorCopy(r_view.forward, r_view.frustum[4].normal);
1974 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
1975 VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, -1024 * slopex, r_view.left, -1024 * slopey, r_view.up, r_view.frustumcorner[0]);
1976 VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, 1024 * slopex, r_view.left, -1024 * slopey, r_view.up, r_view.frustumcorner[1]);
1977 VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, -1024 * slopex, r_view.left, 1024 * slopey, r_view.up, r_view.frustumcorner[2]);
1978 VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, 1024 * slopex, r_view.left, 1024 * slopey, r_view.up, r_view.frustumcorner[3]);
1980 r_view.frustum[0].dist = DotProduct (r_view.origin, r_view.frustum[0].normal);
1981 r_view.frustum[1].dist = DotProduct (r_view.origin, r_view.frustum[1].normal);
1982 r_view.frustum[2].dist = DotProduct (r_view.origin, r_view.frustum[2].normal);
1983 r_view.frustum[3].dist = DotProduct (r_view.origin, r_view.frustum[3].normal);
1984 r_view.frustum[4].dist = DotProduct (r_view.origin, r_view.frustum[4].normal) + r_refdef.nearclip;
1988 VectorScale(r_view.left, -r_view.ortho_x, r_view.frustum[0].normal);
1989 VectorScale(r_view.left, r_view.ortho_x, r_view.frustum[1].normal);
1990 VectorScale(r_view.up, -r_view.ortho_y, r_view.frustum[2].normal);
1991 VectorScale(r_view.up, r_view.ortho_y, r_view.frustum[3].normal);
1992 VectorCopy(r_view.forward, r_view.frustum[4].normal);
1993 r_view.frustum[0].dist = DotProduct (r_view.origin, r_view.frustum[0].normal) + r_view.ortho_x;
1994 r_view.frustum[1].dist = DotProduct (r_view.origin, r_view.frustum[1].normal) + r_view.ortho_x;
1995 r_view.frustum[2].dist = DotProduct (r_view.origin, r_view.frustum[2].normal) + r_view.ortho_y;
1996 r_view.frustum[3].dist = DotProduct (r_view.origin, r_view.frustum[3].normal) + r_view.ortho_y;
1997 r_view.frustum[4].dist = DotProduct (r_view.origin, r_view.frustum[4].normal) + r_refdef.nearclip;
2000 PlaneClassify(&r_view.frustum[0]);
2001 PlaneClassify(&r_view.frustum[1]);
2002 PlaneClassify(&r_view.frustum[2]);
2003 PlaneClassify(&r_view.frustum[3]);
2004 PlaneClassify(&r_view.frustum[4]);
2006 // LordHavoc: note to all quake engine coders, Quake had a special case
2007 // for 90 degrees which assumed a square view (wrong), so I removed it,
2008 // Quake2 has it disabled as well.
2010 // rotate R_VIEWFORWARD right by FOV_X/2 degrees
2011 //RotatePointAroundVector( r_view.frustum[0].normal, r_view.up, r_view.forward, -(90 - r_refdef.fov_x / 2));
2012 //r_view.frustum[0].dist = DotProduct (r_view.origin, frustum[0].normal);
2013 //PlaneClassify(&frustum[0]);
2015 // rotate R_VIEWFORWARD left by FOV_X/2 degrees
2016 //RotatePointAroundVector( r_view.frustum[1].normal, r_view.up, r_view.forward, (90 - r_refdef.fov_x / 2));
2017 //r_view.frustum[1].dist = DotProduct (r_view.origin, frustum[1].normal);
2018 //PlaneClassify(&frustum[1]);
2020 // rotate R_VIEWFORWARD up by FOV_X/2 degrees
2021 //RotatePointAroundVector( r_view.frustum[2].normal, r_view.left, r_view.forward, -(90 - r_refdef.fov_y / 2));
2022 //r_view.frustum[2].dist = DotProduct (r_view.origin, frustum[2].normal);
2023 //PlaneClassify(&frustum[2]);
2025 // rotate R_VIEWFORWARD down by FOV_X/2 degrees
2026 //RotatePointAroundVector( r_view.frustum[3].normal, r_view.left, r_view.forward, (90 - r_refdef.fov_y / 2));
2027 //r_view.frustum[3].dist = DotProduct (r_view.origin, frustum[3].normal);
2028 //PlaneClassify(&frustum[3]);
2031 //VectorCopy(r_view.forward, r_view.frustum[4].normal);
2032 //r_view.frustum[4].dist = DotProduct (r_view.origin, frustum[4].normal) + r_nearclip.value;
2033 //PlaneClassify(&frustum[4]);
2036 void R_View_Update(void)
2038 R_View_SetFrustum();
2039 R_View_WorldVisibility();
2040 R_View_UpdateEntityVisible();
2043 void R_SetupView(const matrix4x4_t *matrix)
2045 if (!r_view.useperspective)
2046 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);
2047 else if (r_refdef.rtworldshadows || r_refdef.rtdlightshadows)
2048 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view.frustum_x, r_view.frustum_y, r_refdef.nearclip);
2050 GL_SetupView_Mode_Perspective(r_view.frustum_x, r_view.frustum_y, r_refdef.nearclip, r_refdef.farclip);
2052 GL_SetupView_Orientation_FromEntity(matrix);
2055 void R_ResetViewRendering2D(void)
2057 if (gl_support_fragment_shader)
2059 qglUseProgramObjectARB(0);CHECKGLERROR
2064 // GL is weird because it's bottom to top, r_view.y is top to bottom
2065 qglViewport(r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
2066 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
2067 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2068 GL_Color(1, 1, 1, 1);
2069 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2070 GL_BlendFunc(GL_ONE, GL_ZERO);
2071 GL_AlphaTest(false);
2072 GL_ScissorTest(false);
2073 GL_DepthMask(false);
2074 GL_DepthRange(0, 1);
2075 GL_DepthTest(false);
2076 R_Mesh_Matrix(&identitymatrix);
2077 R_Mesh_ResetTextureState();
2078 GL_PolygonOffset(0, 0);
2079 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
2080 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2081 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
2082 qglStencilMask(~0);CHECKGLERROR
2083 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
2084 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
2085 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
2088 void R_ResetViewRendering3D(void)
2090 if (gl_support_fragment_shader)
2092 qglUseProgramObjectARB(0);CHECKGLERROR
2097 // GL is weird because it's bottom to top, r_view.y is top to bottom
2098 qglViewport(r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
2099 R_SetupView(&r_view.matrix);
2100 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2101 GL_Color(1, 1, 1, 1);
2102 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2103 GL_BlendFunc(GL_ONE, GL_ZERO);
2104 GL_AlphaTest(false);
2105 GL_ScissorTest(true);
2107 GL_DepthRange(0, 1);
2109 R_Mesh_Matrix(&identitymatrix);
2110 R_Mesh_ResetTextureState();
2111 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
2112 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
2113 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2114 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
2115 qglStencilMask(~0);CHECKGLERROR
2116 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
2117 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
2118 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
2122 R_Bloom_SetupShader(
2124 "// written by Forest 'LordHavoc' Hale\n"
2126 "// common definitions between vertex shader and fragment shader:\n"
2128 "#ifdef __GLSL_CG_DATA_TYPES\n"
2129 "#define myhalf half\n"
2130 "#define myhvec2 hvec2\n"
2131 "#define myhvec3 hvec3\n"
2132 "#define myhvec4 hvec4\n"
2134 "#define myhalf float\n"
2135 "#define myhvec2 vec2\n"
2136 "#define myhvec3 vec3\n"
2137 "#define myhvec4 vec4\n"
2140 "varying vec2 ScreenTexCoord;\n"
2141 "varying vec2 BloomTexCoord;\n"
2146 "// vertex shader specific:\n"
2147 "#ifdef VERTEX_SHADER\n"
2151 " ScreenTexCoord = vec2(gl_MultiTexCoord0);\n"
2152 " BloomTexCoord = vec2(gl_MultiTexCoord1);\n"
2153 " // transform vertex to camera space, using ftransform to match non-VS\n"
2155 " gl_Position = ftransform();\n"
2158 "#endif // VERTEX_SHADER\n"
2163 "// fragment shader specific:\n"
2164 "#ifdef FRAGMENT_SHADER\n"
2169 " myhvec3 color = myhvec3(texture2D(Texture_Screen, ScreenTexCoord));\n"
2170 " for (x = -BLUR_X;x <= BLUR_X;x++)
2171 " color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
2172 " color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
2173 " color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
2174 " color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
2176 " gl_FragColor = vec4(color);\n"
2179 "#endif // FRAGMENT_SHADER\n"
2182 void R_RenderScene(void);
2184 void R_Bloom_StartFrame(void)
2186 int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight;
2188 // set bloomwidth and bloomheight to the bloom resolution that will be
2189 // used (often less than the screen resolution for faster rendering)
2190 r_bloomstate.bloomwidth = bound(1, r_bloom_resolution.integer, r_view.width);
2191 r_bloomstate.bloomheight = r_bloomstate.bloomwidth * r_view.height / r_view.width;
2192 r_bloomstate.bloomheight = bound(1, r_bloomstate.bloomheight, r_view.height);
2194 // calculate desired texture sizes
2195 if (gl_support_arb_texture_non_power_of_two)
2197 screentexturewidth = r_view.width;
2198 screentextureheight = r_view.height;
2199 bloomtexturewidth = r_bloomstate.bloomwidth;
2200 bloomtextureheight = r_bloomstate.bloomheight;
2204 for (screentexturewidth = 1;screentexturewidth < vid.width ;screentexturewidth *= 2);
2205 for (screentextureheight = 1;screentextureheight < vid.height ;screentextureheight *= 2);
2206 for (bloomtexturewidth = 1;bloomtexturewidth < r_bloomstate.bloomwidth ;bloomtexturewidth *= 2);
2207 for (bloomtextureheight = 1;bloomtextureheight < r_bloomstate.bloomheight;bloomtextureheight *= 2);
2212 screentexturewidth = screentextureheight = 0;
2214 else if (r_bloom.integer)
2219 screentexturewidth = screentextureheight = 0;
2220 bloomtexturewidth = bloomtextureheight = 0;
2223 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)
2225 // can't use bloom if the parameters are too weird
2226 // can't use bloom if the card does not support the texture size
2227 if (r_bloomstate.texture_screen)
2228 R_FreeTexture(r_bloomstate.texture_screen);
2229 if (r_bloomstate.texture_bloom)
2230 R_FreeTexture(r_bloomstate.texture_bloom);
2231 memset(&r_bloomstate, 0, sizeof(r_bloomstate));
2235 r_bloomstate.enabled = true;
2236 r_bloomstate.hdr = r_hdr.integer != 0;
2238 // allocate textures as needed
2239 if (r_bloomstate.screentexturewidth != screentexturewidth || r_bloomstate.screentextureheight != screentextureheight)
2241 if (r_bloomstate.texture_screen)
2242 R_FreeTexture(r_bloomstate.texture_screen);
2243 r_bloomstate.texture_screen = NULL;
2244 r_bloomstate.screentexturewidth = screentexturewidth;
2245 r_bloomstate.screentextureheight = screentextureheight;
2246 if (r_bloomstate.screentexturewidth && r_bloomstate.screentextureheight)
2247 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);
2249 if (r_bloomstate.bloomtexturewidth != bloomtexturewidth || r_bloomstate.bloomtextureheight != bloomtextureheight)
2251 if (r_bloomstate.texture_bloom)
2252 R_FreeTexture(r_bloomstate.texture_bloom);
2253 r_bloomstate.texture_bloom = NULL;
2254 r_bloomstate.bloomtexturewidth = bloomtexturewidth;
2255 r_bloomstate.bloomtextureheight = bloomtextureheight;
2256 if (r_bloomstate.bloomtexturewidth && r_bloomstate.bloomtextureheight)
2257 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);
2260 // set up a texcoord array for the full resolution screen image
2261 // (we have to keep this around to copy back during final render)
2262 r_bloomstate.screentexcoord2f[0] = 0;
2263 r_bloomstate.screentexcoord2f[1] = (float)r_view.height / (float)r_bloomstate.screentextureheight;
2264 r_bloomstate.screentexcoord2f[2] = (float)r_view.width / (float)r_bloomstate.screentexturewidth;
2265 r_bloomstate.screentexcoord2f[3] = (float)r_view.height / (float)r_bloomstate.screentextureheight;
2266 r_bloomstate.screentexcoord2f[4] = (float)r_view.width / (float)r_bloomstate.screentexturewidth;
2267 r_bloomstate.screentexcoord2f[5] = 0;
2268 r_bloomstate.screentexcoord2f[6] = 0;
2269 r_bloomstate.screentexcoord2f[7] = 0;
2271 // set up a texcoord array for the reduced resolution bloom image
2272 // (which will be additive blended over the screen image)
2273 r_bloomstate.bloomtexcoord2f[0] = 0;
2274 r_bloomstate.bloomtexcoord2f[1] = (float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
2275 r_bloomstate.bloomtexcoord2f[2] = (float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
2276 r_bloomstate.bloomtexcoord2f[3] = (float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
2277 r_bloomstate.bloomtexcoord2f[4] = (float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
2278 r_bloomstate.bloomtexcoord2f[5] = 0;
2279 r_bloomstate.bloomtexcoord2f[6] = 0;
2280 r_bloomstate.bloomtexcoord2f[7] = 0;
2283 void R_Bloom_CopyScreenTexture(float colorscale)
2285 r_refdef.stats.bloom++;
2287 R_ResetViewRendering2D();
2288 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
2289 R_Mesh_ColorPointer(NULL, 0, 0);
2290 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
2291 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
2293 // copy view into the screen texture
2294 GL_ActiveTexture(0);
2296 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
2297 r_refdef.stats.bloom_copypixels += r_view.width * r_view.height;
2299 // now scale it down to the bloom texture size
2301 qglViewport(r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
2302 GL_BlendFunc(GL_ONE, GL_ZERO);
2303 GL_Color(colorscale, colorscale, colorscale, 1);
2304 // TODO: optimize with multitexture or GLSL
2305 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2306 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2308 // we now have a bloom image in the framebuffer
2309 // copy it into the bloom image texture for later processing
2310 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2311 GL_ActiveTexture(0);
2313 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
2314 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2317 void R_Bloom_CopyHDRTexture(void)
2319 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2320 GL_ActiveTexture(0);
2322 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
2323 r_refdef.stats.bloom_copypixels += r_view.width * r_view.height;
2326 void R_Bloom_MakeTexture(void)
2329 float xoffset, yoffset, r, brighten;
2331 r_refdef.stats.bloom++;
2333 R_ResetViewRendering2D();
2334 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
2335 R_Mesh_ColorPointer(NULL, 0, 0);
2337 // we have a bloom image in the framebuffer
2339 qglViewport(r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
2341 for (x = 1;x < r_bloom_colorexponent.value;)
2344 r = bound(0, r_bloom_colorexponent.value / x, 1);
2345 GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
2346 GL_Color(r, r, r, 1);
2347 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2348 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
2349 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2350 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2352 // copy the vertically blurred bloom view to a texture
2353 GL_ActiveTexture(0);
2355 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
2356 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2359 range = r_bloom_blur.integer * r_bloomstate.bloomwidth / 320;
2360 brighten = r_bloom_brighten.value;
2362 brighten *= r_hdr_range.value;
2363 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2364 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.offsettexcoord2f, 0, 0);
2366 for (dir = 0;dir < 2;dir++)
2368 // blend on at multiple vertical offsets to achieve a vertical blur
2369 // TODO: do offset blends using GLSL
2370 GL_BlendFunc(GL_ONE, GL_ZERO);
2371 for (x = -range;x <= range;x++)
2373 if (!dir){xoffset = 0;yoffset = x;}
2374 else {xoffset = x;yoffset = 0;}
2375 xoffset /= (float)r_bloomstate.bloomtexturewidth;
2376 yoffset /= (float)r_bloomstate.bloomtextureheight;
2377 // compute a texcoord array with the specified x and y offset
2378 r_bloomstate.offsettexcoord2f[0] = xoffset+0;
2379 r_bloomstate.offsettexcoord2f[1] = yoffset+(float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
2380 r_bloomstate.offsettexcoord2f[2] = xoffset+(float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
2381 r_bloomstate.offsettexcoord2f[3] = yoffset+(float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
2382 r_bloomstate.offsettexcoord2f[4] = xoffset+(float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
2383 r_bloomstate.offsettexcoord2f[5] = yoffset+0;
2384 r_bloomstate.offsettexcoord2f[6] = xoffset+0;
2385 r_bloomstate.offsettexcoord2f[7] = yoffset+0;
2386 // this r value looks like a 'dot' particle, fading sharply to
2387 // black at the edges
2388 // (probably not realistic but looks good enough)
2389 //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
2390 //r = (dir ? 1.0f : brighten)/(range*2+1);
2391 r = (dir ? 1.0f : brighten)/(range*2+1)*(1 - x*x/(float)(range*range));
2392 GL_Color(r, r, r, 1);
2393 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2394 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2395 GL_BlendFunc(GL_ONE, GL_ONE);
2398 // copy the vertically blurred bloom view to a texture
2399 GL_ActiveTexture(0);
2401 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
2402 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2405 // apply subtract last
2406 // (just like it would be in a GLSL shader)
2407 if (r_bloom_colorsubtract.value > 0 && gl_support_ext_blend_subtract)
2409 GL_BlendFunc(GL_ONE, GL_ZERO);
2410 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2411 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
2412 GL_Color(1, 1, 1, 1);
2413 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2414 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2416 GL_BlendFunc(GL_ONE, GL_ONE);
2417 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2418 R_Mesh_TexBind(0, R_GetTexture(r_texture_white));
2419 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
2420 GL_Color(r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, 1);
2421 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2422 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2423 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2425 // copy the darkened bloom view to a texture
2426 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2427 GL_ActiveTexture(0);
2429 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
2430 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2434 void R_HDR_RenderBloomTexture(void)
2436 int oldwidth, oldheight;
2438 oldwidth = r_view.width;
2439 oldheight = r_view.height;
2440 r_view.width = r_bloomstate.bloomwidth;
2441 r_view.height = r_bloomstate.bloomheight;
2443 // TODO: support GL_EXT_framebuffer_object rather than reusing the framebuffer? it might improve SLI performance.
2444 // TODO: add exposure compensation features
2445 // TODO: add fp16 framebuffer support
2447 r_view.colorscale = r_bloom_colorscale.value * r_hdr_scenebrightness.value;
2449 r_view.colorscale /= r_hdr_range.value;
2452 R_ResetViewRendering2D();
2454 R_Bloom_CopyHDRTexture();
2455 R_Bloom_MakeTexture();
2457 R_ResetViewRendering3D();
2460 if (r_timereport_active)
2461 R_TimeReport("clear");
2464 // restore the view settings
2465 r_view.width = oldwidth;
2466 r_view.height = oldheight;
2469 static void R_BlendView(void)
2471 if (r_bloomstate.enabled && r_bloomstate.hdr)
2473 // render high dynamic range bloom effect
2474 // the bloom texture was made earlier this render, so we just need to
2475 // blend it onto the screen...
2476 R_ResetViewRendering2D();
2477 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
2478 R_Mesh_ColorPointer(NULL, 0, 0);
2479 GL_Color(1, 1, 1, 1);
2480 GL_BlendFunc(GL_ONE, GL_ONE);
2481 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2482 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
2483 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2484 r_refdef.stats.bloom_drawpixels += r_view.width * r_view.height;
2486 else if (r_bloomstate.enabled)
2488 // render simple bloom effect
2489 // copy the screen and shrink it and darken it for the bloom process
2490 R_Bloom_CopyScreenTexture(r_bloom_colorscale.value);
2491 // make the bloom texture
2492 R_Bloom_MakeTexture();
2493 // put the original screen image back in place and blend the bloom
2495 R_ResetViewRendering2D();
2496 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
2497 R_Mesh_ColorPointer(NULL, 0, 0);
2498 GL_Color(1, 1, 1, 1);
2499 GL_BlendFunc(GL_ONE, GL_ZERO);
2500 // do both in one pass if possible
2501 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2502 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
2503 if (r_textureunits.integer >= 2 && gl_combine.integer)
2505 R_Mesh_TexCombine(1, GL_ADD, GL_ADD, 1, 1);
2506 R_Mesh_TexBind(1, R_GetTexture(r_bloomstate.texture_screen));
2507 R_Mesh_TexCoordPointer(1, 2, r_bloomstate.screentexcoord2f, 0, 0);
2511 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2512 r_refdef.stats.bloom_drawpixels += r_view.width * r_view.height;
2513 // now blend on the bloom texture
2514 GL_BlendFunc(GL_ONE, GL_ONE);
2515 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
2516 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
2518 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2519 r_refdef.stats.bloom_drawpixels += r_view.width * r_view.height;
2521 if (r_refdef.viewblend[3] >= (1.0f / 256.0f))
2523 // apply a color tint to the whole view
2524 R_ResetViewRendering2D();
2525 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
2526 R_Mesh_ColorPointer(NULL, 0, 0);
2527 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2528 GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
2529 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2533 void R_RenderScene(void);
2535 matrix4x4_t r_waterscrollmatrix;
2537 void R_UpdateVariables(void)
2541 r_refdef.farclip = 4096;
2542 if (r_refdef.worldmodel)
2543 r_refdef.farclip += VectorDistance(r_refdef.worldmodel->normalmins, r_refdef.worldmodel->normalmaxs);
2544 r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
2546 if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
2547 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
2548 r_refdef.polygonfactor = 0;
2549 r_refdef.polygonoffset = 0;
2550 r_refdef.shadowpolygonfactor = r_refdef.polygonfactor + r_shadow_polygonfactor.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
2551 r_refdef.shadowpolygonoffset = r_refdef.polygonoffset + r_shadow_polygonoffset.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
2553 r_refdef.rtworld = r_shadow_realtime_world.integer;
2554 r_refdef.rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
2555 r_refdef.rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer && r_dynamic.integer;
2556 r_refdef.rtdlightshadows = r_refdef.rtdlight && r_shadow_realtime_dlight_shadows.integer && gl_stencil;
2557 r_refdef.lightmapintensity = r_refdef.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
2558 if (r_showsurfaces.integer)
2560 r_refdef.rtworld = false;
2561 r_refdef.rtworldshadows = false;
2562 r_refdef.rtdlight = false;
2563 r_refdef.rtdlightshadows = false;
2564 r_refdef.lightmapintensity = 0;
2567 if (gamemode == GAME_NEHAHRA)
2569 if (gl_fogenable.integer)
2571 r_refdef.oldgl_fogenable = true;
2572 r_refdef.fog_density = gl_fogdensity.value;
2573 r_refdef.fog_red = gl_fogred.value;
2574 r_refdef.fog_green = gl_foggreen.value;
2575 r_refdef.fog_blue = gl_fogblue.value;
2577 else if (r_refdef.oldgl_fogenable)
2579 r_refdef.oldgl_fogenable = false;
2580 r_refdef.fog_density = 0;
2581 r_refdef.fog_red = 0;
2582 r_refdef.fog_green = 0;
2583 r_refdef.fog_blue = 0;
2586 if (r_refdef.fog_density)
2588 r_refdef.fogcolor[0] = bound(0.0f, r_refdef.fog_red , 1.0f);
2589 r_refdef.fogcolor[1] = bound(0.0f, r_refdef.fog_green, 1.0f);
2590 r_refdef.fogcolor[2] = bound(0.0f, r_refdef.fog_blue , 1.0f);
2592 if (r_refdef.fog_density)
2594 r_refdef.fogenabled = true;
2595 // this is the point where the fog reaches 0.9986 alpha, which we
2596 // consider a good enough cutoff point for the texture
2597 // (0.9986 * 256 == 255.6)
2598 r_refdef.fogrange = 400 / r_refdef.fog_density;
2599 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
2600 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
2601 // fog color was already set
2604 r_refdef.fogenabled = false;
2612 void R_RenderView(void)
2614 if (!r_refdef.entities/* || !r_refdef.worldmodel*/)
2615 return; //Host_Error ("R_RenderView: NULL worldmodel");
2617 R_Shadow_UpdateWorldLightSelection();
2620 if (r_timereport_active)
2621 R_TimeReport("setup");
2624 if (r_timereport_active)
2625 R_TimeReport("visibility");
2627 R_ResetViewRendering3D();
2630 if (r_timereport_active)
2631 R_TimeReport("clear");
2633 R_Bloom_StartFrame();
2635 // this produces a bloom texture to be used in R_BlendView() later
2637 R_HDR_RenderBloomTexture();
2639 r_view.colorscale = r_hdr_scenebrightness.value;
2643 if (r_timereport_active)
2644 R_TimeReport("blendview");
2646 GL_Scissor(0, 0, vid.width, vid.height);
2647 GL_ScissorTest(false);
2651 extern void R_DrawLightningBeams (void);
2652 extern void VM_CL_AddPolygonsToMeshQueue (void);
2653 extern void R_DrawPortals (void);
2654 extern cvar_t cl_locs_show;
2655 static void R_DrawLocs(void);
2656 static void R_DrawEntityBBoxes(void);
2657 void R_RenderScene(void)
2659 // don't let sound skip if going slow
2660 if (r_refdef.extraupdate)
2663 R_ResetViewRendering3D();
2665 R_MeshQueue_BeginScene();
2669 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);
2671 if (cl.csqc_vidvars.drawworld)
2673 // don't let sound skip if going slow
2674 if (r_refdef.extraupdate)
2677 if (r_refdef.worldmodel && r_refdef.worldmodel->DrawSky)
2679 r_refdef.worldmodel->DrawSky(r_refdef.worldentity);
2680 if (r_timereport_active)
2681 R_TimeReport("worldsky");
2684 if (R_DrawBrushModelsSky() && r_timereport_active)
2685 R_TimeReport("bmodelsky");
2688 if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.worldmodel && r_refdef.worldmodel->DrawDepth)
2690 r_refdef.worldmodel->DrawDepth(r_refdef.worldentity);
2691 if (r_timereport_active)
2692 R_TimeReport("worlddepth");
2694 if (r_depthfirst.integer >= 2)
2696 R_DrawModelsDepth();
2697 if (r_timereport_active)
2698 R_TimeReport("modeldepth");
2701 if (cl.csqc_vidvars.drawworld && r_refdef.worldmodel && r_refdef.worldmodel->Draw)
2703 r_refdef.worldmodel->Draw(r_refdef.worldentity);
2704 if (r_timereport_active)
2705 R_TimeReport("world");
2708 // don't let sound skip if going slow
2709 if (r_refdef.extraupdate)
2713 if (r_timereport_active)
2714 R_TimeReport("models");
2716 // don't let sound skip if going slow
2717 if (r_refdef.extraupdate)
2720 if (r_shadows.integer > 0 && r_refdef.lightmapintensity > 0)
2722 R_DrawModelShadows();
2724 R_ResetViewRendering3D();
2726 // don't let sound skip if going slow
2727 if (r_refdef.extraupdate)
2731 R_ShadowVolumeLighting(false);
2732 if (r_timereport_active)
2733 R_TimeReport("rtlights");
2735 // don't let sound skip if going slow
2736 if (r_refdef.extraupdate)
2739 if (cl.csqc_vidvars.drawworld)
2741 R_DrawLightningBeams();
2742 if (r_timereport_active)
2743 R_TimeReport("lightning");
2746 if (r_timereport_active)
2747 R_TimeReport("particles");
2750 if (r_timereport_active)
2751 R_TimeReport("explosions");
2754 if (gl_support_fragment_shader)
2756 qglUseProgramObjectARB(0);CHECKGLERROR
2758 VM_CL_AddPolygonsToMeshQueue();
2760 if (cl_locs_show.integer)
2763 if (r_timereport_active)
2764 R_TimeReport("showlocs");
2767 if (r_drawportals.integer)
2770 if (r_timereport_active)
2771 R_TimeReport("portals");
2774 if (r_showbboxes.value > 0)
2776 R_DrawEntityBBoxes();
2777 if (r_timereport_active)
2778 R_TimeReport("bboxes");
2781 if (gl_support_fragment_shader)
2783 qglUseProgramObjectARB(0);CHECKGLERROR
2785 R_MeshQueue_RenderTransparent();
2786 if (r_timereport_active)
2787 R_TimeReport("drawtrans");
2789 if (gl_support_fragment_shader)
2791 qglUseProgramObjectARB(0);CHECKGLERROR
2794 if (cl.csqc_vidvars.drawworld)
2797 if (r_timereport_active)
2798 R_TimeReport("coronas");
2801 // don't let sound skip if going slow
2802 if (r_refdef.extraupdate)
2805 R_ResetViewRendering2D();
2808 static const int bboxelements[36] =
2818 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
2821 float *v, *c, f1, f2, vertex3f[8*3], color4f[8*4];
2822 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2823 GL_DepthMask(false);
2824 GL_DepthRange(0, 1);
2825 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
2826 R_Mesh_Matrix(&identitymatrix);
2827 R_Mesh_ResetTextureState();
2829 vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2]; //
2830 vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
2831 vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
2832 vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
2833 vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
2834 vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
2835 vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
2836 vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
2837 R_FillColors(color4f, 8, cr, cg, cb, ca);
2838 if (r_refdef.fogenabled)
2840 for (i = 0, v = vertex3f, c = color4f;i < 8;i++, v += 3, c += 4)
2842 f1 = FogPoint_World(v);
2844 c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
2845 c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
2846 c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
2849 R_Mesh_VertexPointer(vertex3f, 0, 0);
2850 R_Mesh_ColorPointer(color4f, 0, 0);
2851 R_Mesh_ResetTextureState();
2852 R_Mesh_Draw(0, 8, 12, bboxelements, 0, 0);
2855 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2859 prvm_edict_t *edict;
2860 // this function draws bounding boxes of server entities
2864 for (i = 0;i < numsurfaces;i++)
2866 edict = PRVM_EDICT_NUM(surfacelist[i]);
2867 switch ((int)edict->fields.server->solid)
2869 case SOLID_NOT: Vector4Set(color, 1, 1, 1, 0.05);break;
2870 case SOLID_TRIGGER: Vector4Set(color, 1, 0, 1, 0.10);break;
2871 case SOLID_BBOX: Vector4Set(color, 0, 1, 0, 0.10);break;
2872 case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
2873 case SOLID_BSP: Vector4Set(color, 0, 0, 1, 0.05);break;
2874 default: Vector4Set(color, 0, 0, 0, 0.50);break;
2876 color[3] *= r_showbboxes.value;
2877 color[3] = bound(0, color[3], 1);
2878 GL_DepthTest(!r_showdisabledepthtest.integer);
2879 GL_CullFace(GL_BACK);
2880 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
2885 static void R_DrawEntityBBoxes(void)
2888 prvm_edict_t *edict;
2890 // this function draws bounding boxes of server entities
2894 for (i = 0;i < prog->num_edicts;i++)
2896 edict = PRVM_EDICT_NUM(i);
2897 if (edict->priv.server->free)
2899 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
2900 R_MeshQueue_AddTransparent(center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)NULL);
2905 int nomodelelements[24] =
2917 float nomodelvertex3f[6*3] =
2927 float nomodelcolor4f[6*4] =
2929 0.0f, 0.0f, 0.5f, 1.0f,
2930 0.0f, 0.0f, 0.5f, 1.0f,
2931 0.0f, 0.5f, 0.0f, 1.0f,
2932 0.0f, 0.5f, 0.0f, 1.0f,
2933 0.5f, 0.0f, 0.0f, 1.0f,
2934 0.5f, 0.0f, 0.0f, 1.0f
2937 void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2942 // this is only called once per entity so numsurfaces is always 1, and
2943 // surfacelist is always {0}, so this code does not handle batches
2944 R_Mesh_Matrix(&ent->matrix);
2946 if (ent->flags & EF_ADDITIVE)
2948 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2949 GL_DepthMask(false);
2951 else if (ent->alpha < 1)
2953 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2954 GL_DepthMask(false);
2958 GL_BlendFunc(GL_ONE, GL_ZERO);
2961 GL_DepthRange(0, (ent->flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
2962 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
2963 GL_DepthTest(!(ent->effects & EF_NODEPTHTEST));
2964 GL_CullFace((ent->effects & EF_DOUBLESIDED) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
2965 R_Mesh_VertexPointer(nomodelvertex3f, 0, 0);
2966 if (r_refdef.fogenabled)
2969 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
2970 R_Mesh_ColorPointer(color4f, 0, 0);
2971 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2972 f1 = FogPoint_World(org);
2974 for (i = 0, c = color4f;i < 6;i++, c += 4)
2976 c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
2977 c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
2978 c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
2982 else if (ent->alpha != 1)
2984 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
2985 R_Mesh_ColorPointer(color4f, 0, 0);
2986 for (i = 0, c = color4f;i < 6;i++, c += 4)
2990 R_Mesh_ColorPointer(nomodelcolor4f, 0, 0);
2991 R_Mesh_ResetTextureState();
2992 R_Mesh_Draw(0, 6, 8, nomodelelements, 0, 0);
2995 void R_DrawNoModel(entity_render_t *ent)
2998 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2999 //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
3000 R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_view.origin : org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
3002 // R_DrawNoModelCallback(ent, 0);
3005 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
3007 vec3_t right1, right2, diff, normal;
3009 VectorSubtract (org2, org1, normal);
3011 // calculate 'right' vector for start
3012 VectorSubtract (r_view.origin, org1, diff);
3013 CrossProduct (normal, diff, right1);
3014 VectorNormalize (right1);
3016 // calculate 'right' vector for end
3017 VectorSubtract (r_view.origin, org2, diff);
3018 CrossProduct (normal, diff, right2);
3019 VectorNormalize (right2);
3021 vert[ 0] = org1[0] + width * right1[0];
3022 vert[ 1] = org1[1] + width * right1[1];
3023 vert[ 2] = org1[2] + width * right1[2];
3024 vert[ 3] = org1[0] - width * right1[0];
3025 vert[ 4] = org1[1] - width * right1[1];
3026 vert[ 5] = org1[2] - width * right1[2];
3027 vert[ 6] = org2[0] - width * right2[0];
3028 vert[ 7] = org2[1] - width * right2[1];
3029 vert[ 8] = org2[2] - width * right2[2];
3030 vert[ 9] = org2[0] + width * right2[0];
3031 vert[10] = org2[1] + width * right2[1];
3032 vert[11] = org2[2] + width * right2[2];
3035 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
3037 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)
3042 if (r_refdef.fogenabled)
3043 fog = FogPoint_World(origin);
3045 R_Mesh_Matrix(&identitymatrix);
3046 GL_BlendFunc(blendfunc1, blendfunc2);
3052 GL_CullFace(GL_BACK);
3055 GL_CullFace(GL_FRONT);
3057 GL_DepthMask(false);
3058 GL_DepthRange(0, depthshort ? 0.0625 : 1);
3059 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
3060 GL_DepthTest(!depthdisable);
3062 vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
3063 vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
3064 vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
3065 vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
3066 vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
3067 vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
3068 vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
3069 vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
3070 vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
3071 vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
3072 vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
3073 vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
3075 R_Mesh_VertexPointer(vertex3f, 0, 0);
3076 R_Mesh_ColorPointer(NULL, 0, 0);
3077 R_Mesh_ResetTextureState();
3078 R_Mesh_TexBind(0, R_GetTexture(texture));
3079 R_Mesh_TexCoordPointer(0, 2, spritetexcoord2f, 0, 0);
3080 // FIXME: fixed function path can't properly handle r_view.colorscale > 1
3081 GL_Color(cr * fog * r_view.colorscale, cg * fog * r_view.colorscale, cb * fog * r_view.colorscale, ca);
3082 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3084 if (blendfunc2 == GL_ONE_MINUS_SRC_ALPHA)
3086 R_Mesh_TexBind(0, R_GetTexture(fogtexture));
3087 GL_BlendFunc(blendfunc1, GL_ONE);
3089 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);
3090 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3094 int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
3099 VectorSet(v, x, y, z);
3100 for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
3101 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
3103 if (i == mesh->numvertices)
3105 if (mesh->numvertices < mesh->maxvertices)
3107 VectorCopy(v, vertex3f);
3108 mesh->numvertices++;
3110 return mesh->numvertices;
3116 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
3120 element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
3121 element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
3122 e = mesh->element3i + mesh->numtriangles * 3;
3123 for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
3125 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
3126 if (mesh->numtriangles < mesh->maxtriangles)
3131 mesh->numtriangles++;
3133 element[1] = element[2];
3137 void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
3141 element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
3142 element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
3143 e = mesh->element3i + mesh->numtriangles * 3;
3144 for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
3146 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
3147 if (mesh->numtriangles < mesh->maxtriangles)
3152 mesh->numtriangles++;
3154 element[1] = element[2];
3158 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
3159 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
3161 int planenum, planenum2;
3164 mplane_t *plane, *plane2;
3166 double temppoints[2][256*3];
3167 // figure out how large a bounding box we need to properly compute this brush
3169 for (w = 0;w < numplanes;w++)
3170 maxdist = max(maxdist, planes[w].dist);
3171 // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
3172 maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
3173 for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
3177 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
3178 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
3180 if (planenum2 == planenum)
3182 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);
3185 if (tempnumpoints < 3)
3187 // generate elements forming a triangle fan for this polygon
3188 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
3192 static void R_DrawCollisionBrush(const colbrushf_t *brush)
3195 R_Mesh_VertexPointer(brush->points->v, 0, 0);
3196 i = (int)(((size_t)brush) / sizeof(colbrushf_t));
3197 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, 0.2f);
3198 GL_LockArrays(0, brush->numpoints);
3199 R_Mesh_Draw(0, brush->numpoints, brush->numtriangles, brush->elements, 0, 0);
3200 GL_LockArrays(0, 0);
3203 static void R_DrawCollisionSurface(const entity_render_t *ent, const msurface_t *surface)
3206 if (!surface->num_collisiontriangles)
3208 R_Mesh_VertexPointer(surface->data_collisionvertex3f, 0, 0);
3209 i = (int)(((size_t)surface) / sizeof(msurface_t));
3210 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, 0.2f);
3211 GL_LockArrays(0, surface->num_collisionvertices);
3212 R_Mesh_Draw(0, surface->num_collisionvertices, surface->num_collisiontriangles, surface->data_collisionelement3i, 0, 0);
3213 GL_LockArrays(0, 0);
3216 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)
3218 texturelayer_t *layer;
3219 layer = t->currentlayers + t->currentnumlayers++;
3221 layer->depthmask = depthmask;
3222 layer->blendfunc1 = blendfunc1;
3223 layer->blendfunc2 = blendfunc2;
3224 layer->texture = texture;
3225 layer->texmatrix = *matrix;
3226 layer->color[0] = r * r_view.colorscale;
3227 layer->color[1] = g * r_view.colorscale;
3228 layer->color[2] = b * r_view.colorscale;
3229 layer->color[3] = a;
3232 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
3235 index = parms[2] + r_refdef.time * parms[3];
3236 index -= floor(index);
3240 case Q3WAVEFUNC_NONE:
3241 case Q3WAVEFUNC_NOISE:
3242 case Q3WAVEFUNC_COUNT:
3245 case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
3246 case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
3247 case Q3WAVEFUNC_SAWTOOTH: f = index;break;
3248 case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
3249 case Q3WAVEFUNC_TRIANGLE:
3251 f = index - floor(index);
3262 return (float)(parms[0] + parms[1] * f);
3265 void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t)
3268 model_t *model = ent->model;
3271 q3shaderinfo_layer_tcmod_t *tcmod;
3273 // switch to an alternate material if this is a q1bsp animated material
3275 texture_t *texture = t;
3276 int s = ent->skinnum;
3277 if ((unsigned int)s >= (unsigned int)model->numskins)
3279 if (model->skinscenes)
3281 if (model->skinscenes[s].framecount > 1)
3282 s = model->skinscenes[s].firstframe + (unsigned int) (r_refdef.time * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
3284 s = model->skinscenes[s].firstframe;
3287 t = t + s * model->num_surfaces;
3290 // use an alternate animation if the entity's frame is not 0,
3291 // and only if the texture has an alternate animation
3292 if (ent->frame2 != 0 && t->anim_total[1])
3293 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(r_refdef.time * 5.0f) % t->anim_total[1]) : 0];
3295 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(r_refdef.time * 5.0f) % t->anim_total[0]) : 0];
3297 texture->currentframe = t;
3300 // update currentskinframe to be a qw skin or animation frame
3301 if ((i = ent->entitynumber - 1) >= 0 && i < cl.maxclients)
3303 if (strcmp(r_qwskincache[i], cl.scores[i].qw_skin))
3305 strlcpy(r_qwskincache[i], cl.scores[i].qw_skin, sizeof(r_qwskincache[i]));
3306 Con_DPrintf("loading skins/%s\n", r_qwskincache[i]);
3307 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);
3309 t->currentskinframe = r_qwskincache_skinframe[i];
3310 if (t->currentskinframe == NULL)
3311 t->currentskinframe = t->skinframes[(int)(t->skinframerate * (cl.time - ent->frame2time)) % t->numskinframes];
3313 else if (t->numskinframes >= 2)
3314 t->currentskinframe = t->skinframes[(int)(t->skinframerate * (cl.time - ent->frame2time)) % t->numskinframes];
3315 if (t->backgroundnumskinframes >= 2)
3316 t->backgroundcurrentskinframe = t->backgroundskinframes[(int)(t->backgroundskinframerate * (cl.time - ent->frame2time)) % t->backgroundnumskinframes];
3318 t->currentmaterialflags = t->basematerialflags;
3319 t->currentalpha = ent->alpha;
3320 if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_novis.integer))
3321 t->currentalpha *= r_wateralpha.value;
3322 if (!(ent->flags & RENDER_LIGHT))
3323 t->currentmaterialflags |= MATERIALFLAG_FULLBRIGHT;
3324 if (ent->effects & EF_ADDITIVE)
3325 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
3326 else if (t->currentalpha < 1)
3327 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
3328 if (ent->effects & EF_DOUBLESIDED)
3329 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
3330 if (ent->effects & EF_NODEPTHTEST)
3331 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
3332 if (ent->flags & RENDER_VIEWMODEL)
3333 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
3334 if (t->backgroundnumskinframes && !(t->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED))
3335 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
3337 for (i = 0, tcmod = t->tcmods;i < Q3MAXTCMODS && (tcmod->tcmod || i < 1);i++, tcmod++)
3340 switch(tcmod->tcmod)
3344 if (t->currentmaterialflags & MATERIALFLAG_WATER && r_waterscroll.value != 0)
3345 matrix = r_waterscrollmatrix;
3347 matrix = identitymatrix;
3349 case Q3TCMOD_ENTITYTRANSLATE:
3350 // this is used in Q3 to allow the gamecode to control texcoord
3351 // scrolling on the entity, which is not supported in darkplaces yet.
3352 Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
3354 case Q3TCMOD_ROTATE:
3355 Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
3356 Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * r_refdef.time, 0, 0, 1);
3357 Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
3360 Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
3362 case Q3TCMOD_SCROLL:
3363 Matrix4x4_CreateTranslate(&matrix, tcmod->parms[0] * r_refdef.time, tcmod->parms[1] * r_refdef.time, 0);
3365 case Q3TCMOD_STRETCH:
3366 f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
3367 Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
3369 case Q3TCMOD_TRANSFORM:
3370 VectorSet(tcmat + 0, tcmod->parms[0], tcmod->parms[1], 0);
3371 VectorSet(tcmat + 3, tcmod->parms[2], tcmod->parms[3], 0);
3372 VectorSet(tcmat + 6, 0 , 0 , 1);
3373 VectorSet(tcmat + 9, tcmod->parms[4], tcmod->parms[5], 0);
3374 Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
3376 case Q3TCMOD_TURBULENT:
3377 // this is handled in the RSurf_PrepareVertices function
3378 matrix = identitymatrix;
3381 // either replace or concatenate the transformation
3383 t->currenttexmatrix = matrix;
3386 matrix4x4_t temp = t->currenttexmatrix;
3387 Matrix4x4_Concat(&t->currenttexmatrix, &matrix, &temp);
3391 t->colormapping = VectorLength2(ent->colormap_pantscolor) + VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f);
3392 t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
3393 t->glosstexture = r_texture_white;
3394 t->backgroundbasetexture = t->backgroundnumskinframes ? ((!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base) : r_texture_white;
3395 t->backgroundglosstexture = r_texture_white;
3396 t->specularpower = r_shadow_glossexponent.value;
3397 // TODO: store reference values for these in the texture?
3398 t->specularscale = 0;
3399 if (r_shadow_gloss.integer > 0)
3401 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
3403 if (r_shadow_glossintensity.value > 0)
3405 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_black;
3406 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_black;
3407 t->specularscale = r_shadow_glossintensity.value;
3410 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
3411 t->specularscale = r_shadow_gloss2intensity.value;
3414 // lightmaps mode looks bad with dlights using actual texturing, so turn
3415 // off the colormap and glossmap, but leave the normalmap on as it still
3416 // accurately represents the shading involved
3417 if (gl_lightmaps.integer && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
3419 t->basetexture = r_texture_white;
3420 t->specularscale = 0;
3423 t->currentpolygonfactor = r_refdef.polygonfactor;
3424 t->currentpolygonoffset = r_refdef.polygonoffset;
3425 // submodels are biased to avoid z-fighting with world surfaces that they
3426 // may be exactly overlapping (avoids z-fighting artifacts on certain
3427 // doors and things in Quake maps)
3428 if (ent->model->brush.submodel)
3430 t->currentpolygonfactor = r_refdef.polygonfactor + r_polygonoffset_submodel_factor.value;
3431 t->currentpolygonoffset = r_refdef.polygonoffset + r_polygonoffset_submodel_offset.value;
3434 VectorClear(t->dlightcolor);
3435 t->currentnumlayers = 0;
3436 if (!(t->currentmaterialflags & MATERIALFLAG_NODRAW))
3438 if (!(t->currentmaterialflags & MATERIALFLAG_SKY))
3440 int blendfunc1, blendfunc2, depthmask;
3441 if (t->currentmaterialflags & MATERIALFLAG_ADD)
3443 blendfunc1 = GL_SRC_ALPHA;
3444 blendfunc2 = GL_ONE;
3446 else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
3448 blendfunc1 = GL_SRC_ALPHA;
3449 blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
3451 else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
3453 blendfunc1 = t->customblendfunc[0];
3454 blendfunc2 = t->customblendfunc[1];
3458 blendfunc1 = GL_ONE;
3459 blendfunc2 = GL_ZERO;
3461 depthmask = !(t->currentmaterialflags & MATERIALFLAG_BLENDED);
3462 if (t->currentmaterialflags & (MATERIALFLAG_WATER | MATERIALFLAG_WALL))
3464 rtexture_t *currentbasetexture;
3466 if (r_refdef.fogenabled && (t->currentmaterialflags & MATERIALFLAG_BLENDED))
3467 layerflags |= TEXTURELAYERFLAG_FOGDARKEN;
3468 currentbasetexture = (VectorLength2(ent->colormap_pantscolor) + VectorLength2(ent->colormap_shirtcolor) < (1.0f / 1048576.0f) && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
3469 if (t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
3471 // fullbright is not affected by r_refdef.lightmapintensity
3472 R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_TEXTURE, currentbasetexture, &t->currenttexmatrix, ent->colormod[0], ent->colormod[1], ent->colormod[2], t->currentalpha);
3473 if (VectorLength2(ent->colormap_pantscolor) >= (1.0f / 1048576.0f) && t->currentskinframe->pants)
3474 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);
3475 if (VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->currentskinframe->shirt)
3476 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);
3481 // set the color tint used for lights affecting this surface
3482 VectorSet(t->dlightcolor, ent->colormod[0] * t->currentalpha, ent->colormod[1] * t->currentalpha, ent->colormod[2] * t->currentalpha);
3484 // q3bsp has no lightmap updates, so the lightstylevalue that
3485 // would normally be baked into the lightmap must be
3486 // applied to the color
3487 // FIXME: r_glsl 1 rendering doesn't support overbright lightstyles with this (the default light style is not overbright)
3488 if (ent->model->type == mod_brushq3)
3489 colorscale *= r_refdef.lightstylevalue[0] * (1.0f / 256.0f);
3490 colorscale *= r_refdef.lightmapintensity;
3491 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);
3492 if (r_ambient.value >= (1.0f/64.0f))
3493 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);
3494 if (VectorLength2(ent->colormap_pantscolor) >= (1.0f / 1048576.0f) && t->currentskinframe->pants)
3496 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);
3497 if (r_ambient.value >= (1.0f/64.0f))
3498 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);
3500 if (VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->currentskinframe->shirt)
3502 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);
3503 if (r_ambient.value >= (1.0f/64.0f))
3504 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);
3507 if (t->currentskinframe->glow != NULL)
3508 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);
3509 if (r_refdef.fogenabled && !(t->currentmaterialflags & MATERIALFLAG_ADD))
3511 // if this is opaque use alpha blend which will darken the earlier
3514 // if this is an alpha blended material, all the earlier passes
3515 // were darkened by fog already, so we only need to add the fog
3516 // color ontop through the fog mask texture
3518 // if this is an additive blended material, all the earlier passes
3519 // were darkened by fog already, and we should not add fog color
3520 // (because the background was not darkened, there is no fog color
3521 // that was lost behind it).
3522 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);
3529 void R_UpdateAllTextureInfo(entity_render_t *ent)
3533 for (i = 0;i < ent->model->num_texturesperskin;i++)
3534 R_UpdateTextureInfo(ent, ent->model->data_textures + i);
3537 rsurfacestate_t rsurface;
3539 void R_Mesh_ResizeArrays(int newvertices)
3542 if (rsurface.array_size >= newvertices)
3544 if (rsurface.array_modelvertex3f)
3545 Mem_Free(rsurface.array_modelvertex3f);
3546 rsurface.array_size = (newvertices + 1023) & ~1023;
3547 base = (float *)Mem_Alloc(r_main_mempool, rsurface.array_size * sizeof(float[33]));
3548 rsurface.array_modelvertex3f = base + rsurface.array_size * 0;
3549 rsurface.array_modelsvector3f = base + rsurface.array_size * 3;
3550 rsurface.array_modeltvector3f = base + rsurface.array_size * 6;
3551 rsurface.array_modelnormal3f = base + rsurface.array_size * 9;
3552 rsurface.array_deformedvertex3f = base + rsurface.array_size * 12;
3553 rsurface.array_deformedsvector3f = base + rsurface.array_size * 15;
3554 rsurface.array_deformedtvector3f = base + rsurface.array_size * 18;
3555 rsurface.array_deformednormal3f = base + rsurface.array_size * 21;
3556 rsurface.array_texcoord3f = base + rsurface.array_size * 24;
3557 rsurface.array_color4f = base + rsurface.array_size * 27;
3558 rsurface.array_generatedtexcoordtexture2f = base + rsurface.array_size * 31;
3561 void RSurf_CleanUp(void)
3564 if (rsurface.mode == RSURFMODE_GLSL)
3566 qglUseProgramObjectARB(0);CHECKGLERROR
3568 GL_AlphaTest(false);
3569 rsurface.mode = RSURFMODE_NONE;
3570 rsurface.uselightmaptexture = false;
3571 rsurface.texture = NULL;
3574 void RSurf_ActiveWorldEntity(void)
3576 model_t *model = r_refdef.worldmodel;
3578 if (rsurface.array_size < model->surfmesh.num_vertices)
3579 R_Mesh_ResizeArrays(model->surfmesh.num_vertices);
3580 rsurface.matrix = identitymatrix;
3581 rsurface.inversematrix = identitymatrix;
3582 R_Mesh_Matrix(&identitymatrix);
3583 VectorCopy(r_view.origin, rsurface.modelorg);
3584 VectorSet(rsurface.modellight_ambient, 0, 0, 0);
3585 VectorSet(rsurface.modellight_diffuse, 0, 0, 0);
3586 VectorSet(rsurface.modellight_lightdir, 0, 0, 1);
3587 VectorSet(rsurface.colormap_pantscolor, 0, 0, 0);
3588 VectorSet(rsurface.colormap_shirtcolor, 0, 0, 0);
3589 rsurface.frameblend[0].frame = 0;
3590 rsurface.frameblend[0].lerp = 1;
3591 rsurface.frameblend[1].frame = 0;
3592 rsurface.frameblend[1].lerp = 0;
3593 rsurface.frameblend[2].frame = 0;
3594 rsurface.frameblend[2].lerp = 0;
3595 rsurface.frameblend[3].frame = 0;
3596 rsurface.frameblend[3].lerp = 0;
3597 rsurface.modelvertex3f = model->surfmesh.data_vertex3f;
3598 rsurface.modelvertex3f_bufferobject = model->surfmesh.vbo;
3599 rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f;
3600 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
3601 rsurface.modelsvector3f_bufferobject = model->surfmesh.vbo;
3602 rsurface.modelsvector3f_bufferoffset = model->surfmesh.vbooffset_svector3f;
3603 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
3604 rsurface.modeltvector3f_bufferobject = model->surfmesh.vbo;
3605 rsurface.modeltvector3f_bufferoffset = model->surfmesh.vbooffset_tvector3f;
3606 rsurface.modelnormal3f = model->surfmesh.data_normal3f;
3607 rsurface.modelnormal3f_bufferobject = model->surfmesh.vbo;
3608 rsurface.modelnormal3f_bufferoffset = model->surfmesh.vbooffset_normal3f;
3609 rsurface.modellightmapcolor4f = model->surfmesh.data_lightmapcolor4f;
3610 rsurface.modellightmapcolor4f_bufferobject = model->surfmesh.vbo;
3611 rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.vbooffset_lightmapcolor4f;
3612 rsurface.modeltexcoordtexture2f = model->surfmesh.data_texcoordtexture2f;
3613 rsurface.modeltexcoordtexture2f_bufferobject = model->surfmesh.vbo;
3614 rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.vbooffset_texcoordtexture2f;
3615 rsurface.modeltexcoordlightmap2f = model->surfmesh.data_texcoordlightmap2f;
3616 rsurface.modeltexcoordlightmap2f_bufferobject = model->surfmesh.vbo;
3617 rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f;
3618 rsurface.modelelement3i = model->surfmesh.data_element3i;
3619 rsurface.modelelement3i_bufferobject = model->surfmesh.ebo;
3620 rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
3621 rsurface.modelnum_vertices = model->surfmesh.num_vertices;
3622 rsurface.modelnum_triangles = model->surfmesh.num_triangles;
3623 rsurface.modelsurfaces = model->data_surfaces;
3624 rsurface.generatedvertex = false;
3625 rsurface.vertex3f = rsurface.modelvertex3f;
3626 rsurface.vertex3f_bufferobject = rsurface.modelvertex3f_bufferobject;
3627 rsurface.vertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
3628 rsurface.svector3f = rsurface.modelsvector3f;
3629 rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject;
3630 rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
3631 rsurface.tvector3f = rsurface.modeltvector3f;
3632 rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject;
3633 rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
3634 rsurface.normal3f = rsurface.modelnormal3f;
3635 rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject;
3636 rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
3637 rsurface.texcoordtexture2f = rsurface.modeltexcoordtexture2f;
3640 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
3642 model_t *model = ent->model;
3644 if (rsurface.array_size < model->surfmesh.num_vertices)
3645 R_Mesh_ResizeArrays(model->surfmesh.num_vertices);
3646 rsurface.matrix = ent->matrix;
3647 rsurface.inversematrix = ent->inversematrix;
3648 R_Mesh_Matrix(&rsurface.matrix);
3649 Matrix4x4_Transform(&rsurface.inversematrix, r_view.origin, rsurface.modelorg);
3650 VectorCopy(ent->modellight_ambient, rsurface.modellight_ambient);
3651 VectorCopy(ent->modellight_diffuse, rsurface.modellight_diffuse);
3652 VectorCopy(ent->modellight_lightdir, rsurface.modellight_lightdir);
3653 VectorCopy(ent->colormap_pantscolor, rsurface.colormap_pantscolor);
3654 VectorCopy(ent->colormap_shirtcolor, rsurface.colormap_shirtcolor);
3655 rsurface.frameblend[0] = ent->frameblend[0];
3656 rsurface.frameblend[1] = ent->frameblend[1];
3657 rsurface.frameblend[2] = ent->frameblend[2];
3658 rsurface.frameblend[3] = ent->frameblend[3];
3659 if (model->surfmesh.isanimated && (rsurface.frameblend[0].lerp != 1 || rsurface.frameblend[0].frame != 0))
3663 rsurface.modelvertex3f = rsurface.array_modelvertex3f;
3664 rsurface.modelsvector3f = rsurface.array_modelsvector3f;
3665 rsurface.modeltvector3f = rsurface.array_modeltvector3f;
3666 rsurface.modelnormal3f = rsurface.array_modelnormal3f;
3667 Mod_Alias_GetMesh_Vertices(model, rsurface.frameblend, rsurface.array_modelvertex3f, rsurface.array_modelnormal3f, rsurface.array_modelsvector3f, rsurface.array_modeltvector3f);
3669 else if (wantnormals)
3671 rsurface.modelvertex3f = rsurface.array_modelvertex3f;
3672 rsurface.modelsvector3f = NULL;
3673 rsurface.modeltvector3f = NULL;
3674 rsurface.modelnormal3f = rsurface.array_modelnormal3f;
3675 Mod_Alias_GetMesh_Vertices(model, rsurface.frameblend, rsurface.array_modelvertex3f, rsurface.array_modelnormal3f, NULL, NULL);
3679 rsurface.modelvertex3f = rsurface.array_modelvertex3f;
3680 rsurface.modelsvector3f = NULL;
3681 rsurface.modeltvector3f = NULL;
3682 rsurface.modelnormal3f = NULL;
3683 Mod_Alias_GetMesh_Vertices(model, rsurface.frameblend, rsurface.array_modelvertex3f, NULL, NULL, NULL);
3685 rsurface.modelvertex3f_bufferobject = 0;
3686 rsurface.modelvertex3f_bufferoffset = 0;
3687 rsurface.modelsvector3f_bufferobject = 0;
3688 rsurface.modelsvector3f_bufferoffset = 0;
3689 rsurface.modeltvector3f_bufferobject = 0;
3690 rsurface.modeltvector3f_bufferoffset = 0;
3691 rsurface.modelnormal3f_bufferobject = 0;
3692 rsurface.modelnormal3f_bufferoffset = 0;
3693 rsurface.generatedvertex = true;
3697 rsurface.modelvertex3f = model->surfmesh.data_vertex3f;
3698 rsurface.modelvertex3f_bufferobject = model->surfmesh.vbo;
3699 rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f;
3700 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
3701 rsurface.modelsvector3f_bufferobject = model->surfmesh.vbo;
3702 rsurface.modelsvector3f_bufferoffset = model->surfmesh.vbooffset_svector3f;
3703 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
3704 rsurface.modeltvector3f_bufferobject = model->surfmesh.vbo;
3705 rsurface.modeltvector3f_bufferoffset = model->surfmesh.vbooffset_tvector3f;
3706 rsurface.modelnormal3f = model->surfmesh.data_normal3f;
3707 rsurface.modelnormal3f_bufferobject = model->surfmesh.vbo;
3708 rsurface.modelnormal3f_bufferoffset = model->surfmesh.vbooffset_normal3f;
3709 rsurface.generatedvertex = false;
3711 rsurface.modellightmapcolor4f = model->surfmesh.data_lightmapcolor4f;
3712 rsurface.modellightmapcolor4f_bufferobject = model->surfmesh.vbo;
3713 rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.vbooffset_lightmapcolor4f;
3714 rsurface.modeltexcoordtexture2f = model->surfmesh.data_texcoordtexture2f;
3715 rsurface.modeltexcoordtexture2f_bufferobject = model->surfmesh.vbo;
3716 rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.vbooffset_texcoordtexture2f;
3717 rsurface.modeltexcoordlightmap2f = model->surfmesh.data_texcoordlightmap2f;
3718 rsurface.modeltexcoordlightmap2f_bufferobject = model->surfmesh.vbo;
3719 rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f;
3720 rsurface.modelelement3i = model->surfmesh.data_element3i;
3721 rsurface.modelelement3i_bufferobject = model->surfmesh.ebo;
3722 rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
3723 rsurface.modelnum_vertices = model->surfmesh.num_vertices;
3724 rsurface.modelnum_triangles = model->surfmesh.num_triangles;
3725 rsurface.modelsurfaces = model->data_surfaces;
3726 rsurface.vertex3f = rsurface.modelvertex3f;
3727 rsurface.vertex3f_bufferobject = rsurface.modelvertex3f_bufferobject;
3728 rsurface.vertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
3729 rsurface.svector3f = rsurface.modelsvector3f;
3730 rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject;
3731 rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
3732 rsurface.tvector3f = rsurface.modeltvector3f;
3733 rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject;
3734 rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
3735 rsurface.normal3f = rsurface.modelnormal3f;
3736 rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject;
3737 rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
3738 rsurface.texcoordtexture2f = rsurface.modeltexcoordtexture2f;
3741 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
3742 void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generatetangents, int texturenumsurfaces, msurface_t **texturesurfacelist)
3745 int texturesurfaceindex;
3750 const float *v1, *in_tc;
3752 float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
3754 q3shaderinfo_deform_t *deform;
3755 // 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
3756 if (rsurface.generatedvertex)
3758 if (rsurface.texture->tcgen.tcgen == Q3TCGEN_ENVIRONMENT)
3759 generatenormals = true;
3760 for (i = 0;i < Q3MAXDEFORMS;i++)
3762 if (rsurface.texture->deforms[i].deform == Q3DEFORM_AUTOSPRITE)
3764 generatetangents = true;
3765 generatenormals = true;
3767 if (rsurface.texture->deforms[i].deform != Q3DEFORM_NONE)
3768 generatenormals = true;
3770 if (generatenormals && !rsurface.modelnormal3f)
3772 rsurface.normal3f = rsurface.modelnormal3f = rsurface.array_modelnormal3f;
3773 rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject = 0;
3774 rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset = 0;
3775 Mod_BuildNormals(0, rsurface.modelnum_vertices, rsurface.modelnum_triangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.array_modelnormal3f, r_smoothnormals_areaweighting.integer);
3777 if (generatetangents && !rsurface.modelsvector3f)
3779 rsurface.svector3f = rsurface.modelsvector3f = rsurface.array_modelsvector3f;
3780 rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject = 0;
3781 rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset = 0;
3782 rsurface.tvector3f = rsurface.modeltvector3f = rsurface.array_modeltvector3f;
3783 rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject = 0;
3784 rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset = 0;
3785 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);
3788 rsurface.vertex3f = rsurface.modelvertex3f;
3789 rsurface.vertex3f_bufferobject = rsurface.modelvertex3f_bufferobject;
3790 rsurface.vertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
3791 rsurface.svector3f = rsurface.modelsvector3f;
3792 rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject;
3793 rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
3794 rsurface.tvector3f = rsurface.modeltvector3f;
3795 rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject;
3796 rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
3797 rsurface.normal3f = rsurface.modelnormal3f;
3798 rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject;
3799 rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
3800 // if vertices are deformed (sprite flares and things in maps, possibly
3801 // water waves, bulges and other deformations), generate them into
3802 // rsurface.deform* arrays from whatever the rsurface.* arrays point to
3803 // (may be static model data or generated data for an animated model, or
3804 // the previous deform pass)
3805 for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform;deformindex++, deform++)
3807 switch (deform->deform)
3810 case Q3DEFORM_PROJECTIONSHADOW:
3811 case Q3DEFORM_TEXT0:
3812 case Q3DEFORM_TEXT1:
3813 case Q3DEFORM_TEXT2:
3814 case Q3DEFORM_TEXT3:
3815 case Q3DEFORM_TEXT4:
3816 case Q3DEFORM_TEXT5:
3817 case Q3DEFORM_TEXT6:
3818 case Q3DEFORM_TEXT7:
3821 case Q3DEFORM_AUTOSPRITE:
3822 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.forward, newforward);
3823 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.right, newright);
3824 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.up, newup);
3825 VectorNormalize(newforward);
3826 VectorNormalize(newright);
3827 VectorNormalize(newup);
3828 // make deformed versions of only the model vertices used by the specified surfaces
3829 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
3831 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
3832 // a single autosprite surface can contain multiple sprites...
3833 for (j = 0;j < surface->num_vertices - 3;j += 4)
3835 VectorClear(center);
3836 for (i = 0;i < 4;i++)
3837 VectorAdd(center, (rsurface.vertex3f + 3 * surface->num_firstvertex) + (j+i) * 3, center);
3838 VectorScale(center, 0.25f, center);
3839 VectorCopy((rsurface.normal3f + 3 * surface->num_firstvertex) + j*3, forward);
3840 VectorCopy((rsurface.svector3f + 3 * surface->num_firstvertex) + j*3, right);
3841 VectorCopy((rsurface.tvector3f + 3 * surface->num_firstvertex) + j*3, up);
3842 for (i = 0;i < 4;i++)
3844 VectorSubtract((rsurface.vertex3f + 3 * surface->num_firstvertex) + (j+i)*3, center, v);
3845 VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.array_deformedvertex3f + (surface->num_firstvertex+i+j) * 3);
3848 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);
3849 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);
3851 rsurface.vertex3f = rsurface.array_deformedvertex3f;
3852 rsurface.vertex3f_bufferobject = 0;
3853 rsurface.vertex3f_bufferoffset = 0;
3854 rsurface.svector3f = rsurface.array_deformedsvector3f;
3855 rsurface.svector3f_bufferobject = 0;
3856 rsurface.svector3f_bufferoffset = 0;
3857 rsurface.tvector3f = rsurface.array_deformedtvector3f;
3858 rsurface.tvector3f_bufferobject = 0;
3859 rsurface.tvector3f_bufferoffset = 0;
3860 rsurface.normal3f = rsurface.array_deformednormal3f;
3861 rsurface.normal3f_bufferobject = 0;
3862 rsurface.normal3f_bufferoffset = 0;
3864 case Q3DEFORM_AUTOSPRITE2:
3865 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.forward, newforward);
3866 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.right, newright);
3867 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.up, newup);
3868 VectorNormalize(newforward);
3869 VectorNormalize(newright);
3870 VectorNormalize(newup);
3871 // make deformed versions of only the model vertices used by the specified surfaces
3872 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
3874 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
3875 const float *v1, *v2;
3885 memset(shortest, 0, sizeof(shortest));
3886 // a single autosprite surface can contain multiple sprites...
3887 for (j = 0;j < surface->num_vertices - 3;j += 4)
3889 VectorClear(center);
3890 for (i = 0;i < 4;i++)
3891 VectorAdd(center, (rsurface.vertex3f + 3 * surface->num_firstvertex) + (j+i) * 3, center);
3892 VectorScale(center, 0.25f, center);
3893 // find the two shortest edges, then use them to define the
3894 // axis vectors for rotating around the central axis
3895 for (i = 0;i < 6;i++)
3897 v1 = rsurface.vertex3f + 3 * (surface->num_firstvertex + quadedges[i][0]);
3898 v2 = rsurface.vertex3f + 3 * (surface->num_firstvertex + quadedges[i][1]);
3900 Debug_PolygonBegin(NULL, 0, false, 0);
3901 Debug_PolygonVertex(v1[0], v1[1], v1[2], 0, 0, 1, 0, 0, 1);
3902 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);
3903 Debug_PolygonVertex(v2[0], v2[1], v2[2], 0, 0, 1, 0, 0, 1);
3906 l = VectorDistance2(v1, v2);
3907 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
3909 l += (1.0f / 1024.0f);
3910 if (shortest[0].length2 > l || i == 0)
3912 shortest[1] = shortest[0];
3913 shortest[0].length2 = l;
3914 shortest[0].v1 = v1;
3915 shortest[0].v2 = v2;
3917 else if (shortest[1].length2 > l || i == 1)
3919 shortest[1].length2 = l;
3920 shortest[1].v1 = v1;
3921 shortest[1].v2 = v2;
3924 VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
3925 VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
3927 Debug_PolygonBegin(NULL, 0, false, 0);
3928 Debug_PolygonVertex(start[0], start[1], start[2], 0, 0, 1, 1, 0, 1);
3929 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);
3930 Debug_PolygonVertex(end[0], end[1], end[2], 0, 0, 0, 1, 1, 1);
3933 // this calculates the right vector from the shortest edge
3934 // and the up vector from the edge midpoints
3935 VectorSubtract(shortest[0].v1, shortest[0].v2, right);
3936 VectorNormalize(right);
3937 VectorSubtract(end, start, up);
3938 VectorNormalize(up);
3939 // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
3940 //VectorSubtract(rsurface.modelorg, center, forward);
3941 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.forward, forward);
3942 VectorNegate(forward, forward);
3943 VectorReflect(forward, 0, up, forward);
3944 VectorNormalize(forward);
3945 CrossProduct(up, forward, newright);
3946 VectorNormalize(newright);
3948 Debug_PolygonBegin(NULL, 0, false, 0);
3949 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);
3950 Debug_PolygonVertex(center[0] + right[0] * 8, center[1] + right[1] * 8, center[2] + right[2] * 8, 0, 0, 0, 1, 0, 1);
3951 Debug_PolygonVertex(center[0] + up [0] * 8, center[1] + up [1] * 8, center[2] + up [2] * 8, 0, 0, 0, 0, 1, 1);
3955 Debug_PolygonBegin(NULL, 0, false, 0);
3956 Debug_PolygonVertex(center[0] + forward [0] * 8, center[1] + forward [1] * 8, center[2] + forward [2] * 8, 0, 0, 1, 0, 0, 1);
3957 Debug_PolygonVertex(center[0] + newright[0] * 8, center[1] + newright[1] * 8, center[2] + newright[2] * 8, 0, 0, 0, 1, 0, 1);
3958 Debug_PolygonVertex(center[0] + up [0] * 8, center[1] + up [1] * 8, center[2] + up [2] * 8, 0, 0, 0, 0, 1, 1);
3961 // rotate the quad around the up axis vector, this is made
3962 // especially easy by the fact we know the quad is flat,
3963 // so we only have to subtract the center position and
3964 // measure distance along the right vector, and then
3965 // multiply that by the newright vector and add back the
3967 // we also need to subtract the old position to undo the
3968 // displacement from the center, which we do with a
3969 // DotProduct, the subtraction/addition of center is also
3970 // optimized into DotProducts here
3971 l = DotProduct(right, center);
3972 for (i = 0;i < 4;i++)
3974 v1 = rsurface.vertex3f + 3 * (surface->num_firstvertex + j + i);
3975 f = DotProduct(right, v1) - l;
3976 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.array_deformedvertex3f + (surface->num_firstvertex+i+j) * 3);
3979 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);
3980 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);
3982 rsurface.vertex3f = rsurface.array_deformedvertex3f;
3983 rsurface.vertex3f_bufferobject = 0;
3984 rsurface.vertex3f_bufferoffset = 0;
3985 rsurface.svector3f = rsurface.array_deformedsvector3f;
3986 rsurface.svector3f_bufferobject = 0;
3987 rsurface.svector3f_bufferoffset = 0;
3988 rsurface.tvector3f = rsurface.array_deformedtvector3f;
3989 rsurface.tvector3f_bufferobject = 0;
3990 rsurface.tvector3f_bufferoffset = 0;
3991 rsurface.normal3f = rsurface.array_deformednormal3f;
3992 rsurface.normal3f_bufferobject = 0;
3993 rsurface.normal3f_bufferoffset = 0;
3995 case Q3DEFORM_NORMAL:
3996 // deform the normals to make reflections wavey
3997 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
3999 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4000 for (j = 0;j < surface->num_vertices;j++)
4003 float *normal = (rsurface.array_deformednormal3f + 3 * surface->num_firstvertex) + j*3;
4004 VectorScale((rsurface.vertex3f + 3 * surface->num_firstvertex) + j*3, 0.98f, vertex);
4005 VectorCopy((rsurface.normal3f + 3 * surface->num_firstvertex) + j*3, normal);
4006 normal[0] += deform->parms[0] * noise4f( vertex[0], vertex[1], vertex[2], r_refdef.time * deform->parms[1]);
4007 normal[1] += deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], r_refdef.time * deform->parms[1]);
4008 normal[2] += deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], r_refdef.time * deform->parms[1]);
4009 VectorNormalize(normal);
4011 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);
4013 rsurface.svector3f = rsurface.array_deformedsvector3f;
4014 rsurface.svector3f_bufferobject = 0;
4015 rsurface.svector3f_bufferoffset = 0;
4016 rsurface.tvector3f = rsurface.array_deformedtvector3f;
4017 rsurface.tvector3f_bufferobject = 0;
4018 rsurface.tvector3f_bufferoffset = 0;
4019 rsurface.normal3f = rsurface.array_deformednormal3f;
4020 rsurface.normal3f_bufferobject = 0;
4021 rsurface.normal3f_bufferoffset = 0;
4024 // deform vertex array to make wavey water and flags and such
4025 waveparms[0] = deform->waveparms[0];
4026 waveparms[1] = deform->waveparms[1];
4027 waveparms[2] = deform->waveparms[2];
4028 waveparms[3] = deform->waveparms[3];
4029 // this is how a divisor of vertex influence on deformation
4030 animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
4031 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
4032 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4034 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4035 for (j = 0;j < surface->num_vertices;j++)
4037 float *vertex = (rsurface.array_deformedvertex3f + 3 * surface->num_firstvertex) + j*3;
4038 VectorCopy((rsurface.vertex3f + 3 * surface->num_firstvertex) + j*3, vertex);
4039 // if the wavefunc depends on time, evaluate it per-vertex
4042 waveparms[2] = deform->waveparms[2] + (vertex[0] + vertex[1] + vertex[2]) * animpos;
4043 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
4045 VectorMA(vertex, scale, (rsurface.normal3f + 3 * surface->num_firstvertex) + j*3, vertex);
4048 rsurface.vertex3f = rsurface.array_deformedvertex3f;
4049 rsurface.vertex3f_bufferobject = 0;
4050 rsurface.vertex3f_bufferoffset = 0;
4052 case Q3DEFORM_BULGE:
4053 // deform vertex array to make the surface have moving bulges
4054 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4056 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4057 for (j = 0;j < surface->num_vertices;j++)
4059 scale = sin((rsurface.modeltexcoordtexture2f[2 * (surface->num_firstvertex + j)] * deform->parms[0] + r_refdef.time * deform->parms[2])) * deform->parms[1];
4060 VectorMA(rsurface.vertex3f + 3 * (surface->num_firstvertex + j), scale, rsurface.normal3f + 3 * (surface->num_firstvertex + j), rsurface.array_deformedvertex3f + 3 * (surface->num_firstvertex + j));
4063 rsurface.vertex3f = rsurface.array_deformedvertex3f;
4064 rsurface.vertex3f_bufferobject = 0;
4065 rsurface.vertex3f_bufferoffset = 0;
4068 // deform vertex array
4069 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
4070 VectorScale(deform->parms, scale, waveparms);
4071 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4073 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4074 for (j = 0;j < surface->num_vertices;j++)
4075 VectorAdd(rsurface.vertex3f + 3 * (surface->num_firstvertex + j), waveparms, rsurface.array_deformedvertex3f + 3 * (surface->num_firstvertex + j));
4077 rsurface.vertex3f = rsurface.array_deformedvertex3f;
4078 rsurface.vertex3f_bufferobject = 0;
4079 rsurface.vertex3f_bufferoffset = 0;
4083 // generate texcoords based on the chosen texcoord source
4084 switch(rsurface.texture->tcgen.tcgen)
4087 case Q3TCGEN_TEXTURE:
4088 rsurface.texcoordtexture2f = rsurface.modeltexcoordtexture2f;
4089 rsurface.texcoordtexture2f_bufferobject = rsurface.modeltexcoordtexture2f_bufferobject;
4090 rsurface.texcoordtexture2f_bufferoffset = rsurface.modeltexcoordtexture2f_bufferoffset;
4092 case Q3TCGEN_LIGHTMAP:
4093 rsurface.texcoordtexture2f = rsurface.modeltexcoordlightmap2f;
4094 rsurface.texcoordtexture2f_bufferobject = rsurface.modeltexcoordlightmap2f_bufferobject;
4095 rsurface.texcoordtexture2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
4097 case Q3TCGEN_VECTOR:
4098 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4100 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4101 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)
4103 out_tc[0] = DotProduct(v1, rsurface.texture->tcgen.parms);
4104 out_tc[1] = DotProduct(v1, rsurface.texture->tcgen.parms + 3);
4107 rsurface.texcoordtexture2f = rsurface.array_generatedtexcoordtexture2f;
4108 rsurface.texcoordtexture2f_bufferobject = 0;
4109 rsurface.texcoordtexture2f_bufferoffset = 0;
4111 case Q3TCGEN_ENVIRONMENT:
4112 // make environment reflections using a spheremap
4113 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4115 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4116 const float *vertex = rsurface.modelvertex3f + 3 * surface->num_firstvertex;
4117 const float *normal = rsurface.modelnormal3f + 3 * surface->num_firstvertex;
4118 float *out_tc = rsurface.array_generatedtexcoordtexture2f + 2 * surface->num_firstvertex;
4119 for (j = 0;j < surface->num_vertices;j++, vertex += 3, normal += 3, out_tc += 2)
4121 float l, d, eyedir[3];
4122 VectorSubtract(rsurface.modelorg, vertex, eyedir);
4123 l = 0.5f / VectorLength(eyedir);
4124 d = DotProduct(normal, eyedir)*2;
4125 out_tc[0] = 0.5f + (normal[1]*d - eyedir[1])*l;
4126 out_tc[1] = 0.5f - (normal[2]*d - eyedir[2])*l;
4129 rsurface.texcoordtexture2f = rsurface.array_generatedtexcoordtexture2f;
4130 rsurface.texcoordtexture2f_bufferobject = 0;
4131 rsurface.texcoordtexture2f_bufferoffset = 0;
4134 // the only tcmod that needs software vertex processing is turbulent, so
4135 // check for it here and apply the changes if needed
4136 // and we only support that as the first one
4137 // (handling a mixture of turbulent and other tcmods would be problematic
4138 // without punting it entirely to a software path)
4139 if (rsurface.texture->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
4141 amplitude = rsurface.texture->tcmods[0].parms[1];
4142 animpos = rsurface.texture->tcmods[0].parms[2] + r_refdef.time * rsurface.texture->tcmods[0].parms[3];
4143 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4145 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4146 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)
4148 out_tc[0] = in_tc[0] + amplitude * sin(((v1[0] + v1[2]) * 1.0 / 1024.0f + animpos) * M_PI * 2);
4149 out_tc[1] = in_tc[1] + amplitude * sin(((v1[1] ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
4152 rsurface.texcoordtexture2f = rsurface.array_generatedtexcoordtexture2f;
4153 rsurface.texcoordtexture2f_bufferobject = 0;
4154 rsurface.texcoordtexture2f_bufferoffset = 0;
4156 rsurface.texcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
4157 rsurface.texcoordlightmap2f_bufferobject = rsurface.modeltexcoordlightmap2f_bufferobject;
4158 rsurface.texcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
4159 R_Mesh_VertexPointer(rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
4162 void RSurf_DrawBatch_Simple(int texturenumsurfaces, msurface_t **texturesurfacelist)
4165 const msurface_t *surface = texturesurfacelist[0];
4166 const msurface_t *surface2;
4171 // TODO: lock all array ranges before render, rather than on each surface
4172 if (texturenumsurfaces == 1)
4174 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
4175 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));
4177 else if (r_batchmode.integer == 2)
4179 #define MAXBATCHTRIANGLES 4096
4180 int batchtriangles = 0;
4181 int batchelements[MAXBATCHTRIANGLES*3];
4182 for (i = 0;i < texturenumsurfaces;i = j)
4184 surface = texturesurfacelist[i];
4186 if (surface->num_triangles > MAXBATCHTRIANGLES)
4188 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));
4191 memcpy(batchelements, rsurface.modelelement3i + 3 * surface->num_firsttriangle, surface->num_triangles * sizeof(int[3]));
4192 batchtriangles = surface->num_triangles;
4193 firstvertex = surface->num_firstvertex;
4194 endvertex = surface->num_firstvertex + surface->num_vertices;
4195 for (;j < texturenumsurfaces;j++)
4197 surface2 = texturesurfacelist[j];
4198 if (batchtriangles + surface2->num_triangles > MAXBATCHTRIANGLES)
4200 memcpy(batchelements + batchtriangles * 3, rsurface.modelelement3i + 3 * surface2->num_firsttriangle, surface2->num_triangles * sizeof(int[3]));
4201 batchtriangles += surface2->num_triangles;
4202 firstvertex = min(firstvertex, surface2->num_firstvertex);
4203 endvertex = max(endvertex, surface2->num_firstvertex + surface2->num_vertices);
4205 surface2 = texturesurfacelist[j-1];
4206 numvertices = endvertex - firstvertex;
4207 R_Mesh_Draw(firstvertex, numvertices, batchtriangles, batchelements, 0, 0);
4210 else if (r_batchmode.integer == 1)
4212 for (i = 0;i < texturenumsurfaces;i = j)
4214 surface = texturesurfacelist[i];
4215 for (j = i + 1, surface2 = surface + 1;j < texturenumsurfaces;j++, surface2++)
4216 if (texturesurfacelist[j] != surface2)
4218 surface2 = texturesurfacelist[j-1];
4219 numvertices = surface2->num_firstvertex + surface2->num_vertices - surface->num_firstvertex;
4220 numtriangles = surface2->num_firsttriangle + surface2->num_triangles - surface->num_firsttriangle;
4221 GL_LockArrays(surface->num_firstvertex, numvertices);
4222 R_Mesh_Draw(surface->num_firstvertex, numvertices, numtriangles, (rsurface.modelelement3i + 3 * surface->num_firsttriangle), rsurface.modelelement3i_bufferobject, (sizeof(int[3]) * surface->num_firsttriangle));
4227 for (i = 0;i < texturenumsurfaces;i++)
4229 surface = texturesurfacelist[i];
4230 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
4231 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));
4236 static void RSurf_DrawBatch_WithLightmapSwitching(int texturenumsurfaces, msurface_t **texturesurfacelist, int lightmaptexunit, int deluxemaptexunit)
4240 const msurface_t *surface = texturesurfacelist[0];
4241 const msurface_t *surface2;
4246 // TODO: lock all array ranges before render, rather than on each surface
4247 if (texturenumsurfaces == 1)
4249 R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
4250 if (deluxemaptexunit >= 0)
4251 R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
4252 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
4253 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));
4255 else if (r_batchmode.integer == 2)
4257 #define MAXBATCHTRIANGLES 4096
4258 int batchtriangles = 0;
4259 int batchelements[MAXBATCHTRIANGLES*3];
4260 for (i = 0;i < texturenumsurfaces;i = j)
4262 surface = texturesurfacelist[i];
4263 R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
4264 if (deluxemaptexunit >= 0)
4265 R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
4267 if (surface->num_triangles > MAXBATCHTRIANGLES)
4269 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));
4272 memcpy(batchelements, rsurface.modelelement3i + 3 * surface->num_firsttriangle, surface->num_triangles * sizeof(int[3]));
4273 batchtriangles = surface->num_triangles;
4274 firstvertex = surface->num_firstvertex;
4275 endvertex = surface->num_firstvertex + surface->num_vertices;
4276 for (;j < texturenumsurfaces;j++)
4278 surface2 = texturesurfacelist[j];
4279 if (surface2->lightmaptexture != surface->lightmaptexture || batchtriangles + surface2->num_triangles > MAXBATCHTRIANGLES)
4281 memcpy(batchelements + batchtriangles * 3, rsurface.modelelement3i + 3 * surface2->num_firsttriangle, surface2->num_triangles * sizeof(int[3]));
4282 batchtriangles += surface2->num_triangles;
4283 firstvertex = min(firstvertex, surface2->num_firstvertex);
4284 endvertex = max(endvertex, surface2->num_firstvertex + surface2->num_vertices);
4286 surface2 = texturesurfacelist[j-1];
4287 numvertices = endvertex - firstvertex;
4288 R_Mesh_Draw(firstvertex, numvertices, batchtriangles, batchelements, 0, 0);
4291 else if (r_batchmode.integer == 1)
4294 Con_Printf("%s batch sizes ignoring lightmap:", rsurface.texture->name);
4295 for (i = 0;i < texturenumsurfaces;i = j)
4297 surface = texturesurfacelist[i];
4298 for (j = i + 1, surface2 = surface + 1;j < texturenumsurfaces;j++, surface2++)
4299 if (texturesurfacelist[j] != surface2)
4301 Con_Printf(" %i", j - i);
4304 Con_Printf("%s batch sizes honoring lightmap:", rsurface.texture->name);
4306 for (i = 0;i < texturenumsurfaces;i = j)
4308 surface = texturesurfacelist[i];
4309 R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
4310 if (deluxemaptexunit >= 0)
4311 R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
4312 for (j = i + 1, surface2 = surface + 1;j < texturenumsurfaces;j++, surface2++)
4313 if (texturesurfacelist[j] != surface2 || texturesurfacelist[j]->lightmaptexture != surface->lightmaptexture)
4316 Con_Printf(" %i", j - i);
4318 surface2 = texturesurfacelist[j-1];
4319 numvertices = surface2->num_firstvertex + surface2->num_vertices - surface->num_firstvertex;
4320 numtriangles = surface2->num_firsttriangle + surface2->num_triangles - surface->num_firsttriangle;
4321 GL_LockArrays(surface->num_firstvertex, numvertices);
4322 R_Mesh_Draw(surface->num_firstvertex, numvertices, numtriangles, (rsurface.modelelement3i + 3 * surface->num_firsttriangle), rsurface.modelelement3i_bufferobject, (sizeof(int[3]) * surface->num_firsttriangle));
4330 for (i = 0;i < texturenumsurfaces;i++)
4332 surface = texturesurfacelist[i];
4333 R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
4334 if (deluxemaptexunit >= 0)
4335 R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
4336 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
4337 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));
4342 static void RSurf_DrawBatch_ShowSurfaces(int texturenumsurfaces, msurface_t **texturesurfacelist)
4345 int texturesurfaceindex;
4346 if (r_showsurfaces.integer == 2)
4348 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4350 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4351 for (j = 0;j < surface->num_triangles;j++)
4353 float f = ((j + surface->num_firsttriangle) & 31) * (1.0f / 31.0f) * r_view.colorscale;
4354 GL_Color(f, f, f, 1);
4355 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)));
4361 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4363 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4364 int k = (int)(((size_t)surface) / sizeof(msurface_t));
4365 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);
4366 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
4367 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));
4372 static void RSurf_DrawBatch_GL11_ApplyFog(int texturenumsurfaces, msurface_t **texturesurfacelist)
4374 int texturesurfaceindex;
4378 if (rsurface.lightmapcolor4f)
4380 // generate color arrays for the surfaces in this list
4381 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4383 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4384 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)
4386 f = FogPoint_Model(v);
4396 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4398 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4399 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)
4401 f = FogPoint_Model(v);
4409 rsurface.lightmapcolor4f = rsurface.array_color4f;
4410 rsurface.lightmapcolor4f_bufferobject = 0;
4411 rsurface.lightmapcolor4f_bufferoffset = 0;
4414 static void RSurf_DrawBatch_GL11_ApplyColor(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a)
4416 int texturesurfaceindex;
4419 if (!rsurface.lightmapcolor4f)
4421 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4423 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4424 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)
4432 rsurface.lightmapcolor4f = rsurface.array_color4f;
4433 rsurface.lightmapcolor4f_bufferobject = 0;
4434 rsurface.lightmapcolor4f_bufferoffset = 0;
4437 static void RSurf_DrawBatch_GL11_Lightmap(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
4440 rsurface.lightmapcolor4f = NULL;
4441 rsurface.lightmapcolor4f_bufferobject = 0;
4442 rsurface.lightmapcolor4f_bufferoffset = 0;
4443 if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
4444 if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
4445 R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
4446 GL_Color(r, g, b, a);
4447 RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist, 0, -1);
4450 static void RSurf_DrawBatch_GL11_Unlit(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
4452 // TODO: optimize applyfog && applycolor case
4453 // just apply fog if necessary, and tint the fog color array if necessary
4454 rsurface.lightmapcolor4f = NULL;
4455 rsurface.lightmapcolor4f_bufferobject = 0;
4456 rsurface.lightmapcolor4f_bufferoffset = 0;
4457 if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
4458 if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
4459 R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
4460 GL_Color(r, g, b, a);
4461 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
4464 static void RSurf_DrawBatch_GL11_VertexColor(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
4466 int texturesurfaceindex;
4470 if (texturesurfacelist[0]->lightmapinfo && texturesurfacelist[0]->lightmapinfo->stainsamples)
4472 // generate color arrays for the surfaces in this list
4473 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4475 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4476 for (i = 0, c = rsurface.array_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
4478 if (surface->lightmapinfo->samples)
4480 const unsigned char *lm = surface->lightmapinfo->samples + (rsurface.modellightmapoffsets + surface->num_firstvertex)[i];
4481 float scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[0]] * (1.0f / 32768.0f);
4482 VectorScale(lm, scale, c);
4483 if (surface->lightmapinfo->styles[1] != 255)
4485 int size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
4487 scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[1]] * (1.0f / 32768.0f);
4488 VectorMA(c, scale, lm, c);
4489 if (surface->lightmapinfo->styles[2] != 255)
4492 scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[2]] * (1.0f / 32768.0f);
4493 VectorMA(c, scale, lm, c);
4494 if (surface->lightmapinfo->styles[3] != 255)
4497 scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[3]] * (1.0f / 32768.0f);
4498 VectorMA(c, scale, lm, c);
4508 rsurface.lightmapcolor4f = rsurface.array_color4f;
4509 rsurface.lightmapcolor4f_bufferobject = 0;
4510 rsurface.lightmapcolor4f_bufferoffset = 0;
4514 rsurface.lightmapcolor4f = rsurface.modellightmapcolor4f;
4515 rsurface.lightmapcolor4f_bufferobject = rsurface.modellightmapcolor4f_bufferobject;
4516 rsurface.lightmapcolor4f_bufferoffset = rsurface.modellightmapcolor4f_bufferoffset;
4518 if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
4519 if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
4520 R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
4521 GL_Color(r, g, b, a);
4522 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
4525 static void RSurf_DrawBatch_GL11_VertexShade(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
4527 int texturesurfaceindex;
4531 vec3_t ambientcolor;
4532 vec3_t diffusecolor;
4536 VectorCopy(rsurface.modellight_lightdir, lightdir);
4537 ambientcolor[0] = rsurface.modellight_ambient[0] * r * 0.5f;
4538 ambientcolor[1] = rsurface.modellight_ambient[1] * g * 0.5f;
4539 ambientcolor[2] = rsurface.modellight_ambient[2] * b * 0.5f;
4540 diffusecolor[0] = rsurface.modellight_diffuse[0] * r * 0.5f;
4541 diffusecolor[1] = rsurface.modellight_diffuse[1] * g * 0.5f;
4542 diffusecolor[2] = rsurface.modellight_diffuse[2] * b * 0.5f;
4543 if (VectorLength2(diffusecolor) > 0)
4545 // generate color arrays for the surfaces in this list
4546 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4548 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4549 int numverts = surface->num_vertices;
4550 v = rsurface.vertex3f + 3 * surface->num_firstvertex;
4551 c2 = rsurface.normal3f + 3 * surface->num_firstvertex;
4552 c = rsurface.array_color4f + 4 * surface->num_firstvertex;
4553 // q3-style directional shading
4554 for (i = 0;i < numverts;i++, v += 3, c2 += 3, c += 4)
4556 if ((f = DotProduct(c2, lightdir)) > 0)
4557 VectorMA(ambientcolor, f, diffusecolor, c);
4559 VectorCopy(ambientcolor, c);
4568 rsurface.lightmapcolor4f = rsurface.array_color4f;
4569 rsurface.lightmapcolor4f_bufferobject = 0;
4570 rsurface.lightmapcolor4f_bufferoffset = 0;
4574 r = ambientcolor[0];
4575 g = ambientcolor[1];
4576 b = ambientcolor[2];
4577 rsurface.lightmapcolor4f = NULL;
4578 rsurface.lightmapcolor4f_bufferobject = 0;
4579 rsurface.lightmapcolor4f_bufferoffset = 0;
4581 if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
4582 if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
4583 R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
4584 GL_Color(r, g, b, a);
4585 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
4588 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, msurface_t **texturesurfacelist)
4590 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
4591 GL_PolygonOffset(rsurface.texture->currentpolygonfactor, rsurface.texture->currentpolygonoffset);
4592 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
4593 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
4594 if (rsurface.mode != RSURFMODE_SHOWSURFACES)
4596 rsurface.mode = RSURFMODE_SHOWSURFACES;
4598 GL_BlendFunc(GL_ONE, GL_ZERO);
4599 R_Mesh_ColorPointer(NULL, 0, 0);
4600 R_Mesh_ResetTextureState();
4602 RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
4603 RSurf_DrawBatch_ShowSurfaces(texturenumsurfaces, texturesurfacelist);
4606 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, msurface_t **texturesurfacelist)
4608 // transparent sky would be ridiculous
4609 if ((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED))
4611 if (rsurface.mode != RSURFMODE_SKY)
4613 if (rsurface.mode == RSURFMODE_GLSL)
4615 qglUseProgramObjectARB(0);CHECKGLERROR
4617 rsurface.mode = RSURFMODE_SKY;
4621 skyrendernow = false;
4623 // restore entity matrix
4624 R_Mesh_Matrix(&rsurface.matrix);
4626 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
4627 GL_PolygonOffset(rsurface.texture->currentpolygonfactor, rsurface.texture->currentpolygonoffset);
4628 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
4629 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
4631 // LordHavoc: HalfLife maps have freaky skypolys so don't use
4632 // skymasking on them, and Quake3 never did sky masking (unlike
4633 // software Quake and software Quake2), so disable the sky masking
4634 // in Quake3 maps as it causes problems with q3map2 sky tricks,
4635 // and skymasking also looks very bad when noclipping outside the
4636 // level, so don't use it then either.
4637 if (r_refdef.worldmodel && r_refdef.worldmodel->type == mod_brushq1 && r_q1bsp_skymasking.integer && !r_viewcache.world_novis)
4639 GL_Color(r_refdef.fogcolor[0] * r_view.colorscale, r_refdef.fogcolor[1] * r_view.colorscale, r_refdef.fogcolor[2] * r_view.colorscale, 1);
4640 R_Mesh_ColorPointer(NULL, 0, 0);
4641 R_Mesh_ResetTextureState();
4642 if (skyrendermasked)
4644 // depth-only (masking)
4645 GL_ColorMask(0,0,0,0);
4646 // just to make sure that braindead drivers don't draw
4647 // anything despite that colormask...
4648 GL_BlendFunc(GL_ZERO, GL_ONE);
4653 GL_BlendFunc(GL_ONE, GL_ZERO);
4655 RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
4656 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
4657 if (skyrendermasked)
4658 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
4662 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, msurface_t **texturesurfacelist)
4664 if (rsurface.mode != RSURFMODE_GLSL)
4666 rsurface.mode = RSURFMODE_GLSL;
4667 R_Mesh_ResetTextureState();
4670 R_SetupSurfaceShader(vec3_origin, rsurface.lightmode == 2, 1, 1, rsurface.texture->specularscale);
4671 if (!r_glsl_permutation)
4674 if (rsurface.lightmode == 2)
4675 RSurf_PrepareVerticesForBatch(true, r_glsl_permutation->loc_Texture_Normal >= 0, texturenumsurfaces, texturesurfacelist);
4677 RSurf_PrepareVerticesForBatch(r_glsl_permutation->loc_Texture_Normal >= 0, r_glsl_permutation->loc_Texture_Normal >= 0, texturenumsurfaces, texturesurfacelist);
4678 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
4679 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
4680 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
4681 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
4682 R_Mesh_TexCoordPointer(4, 2, rsurface.modeltexcoordlightmap2f, rsurface.modeltexcoordlightmap2f_bufferobject, rsurface.modeltexcoordlightmap2f_bufferoffset);
4684 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]);
4685 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
4687 R_Mesh_TexBind(7, R_GetTexture(r_texture_grey128));
4688 if (r_glsl_permutation->loc_Texture_Deluxemap >= 0)
4689 R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
4690 R_Mesh_ColorPointer(NULL, 0, 0);
4692 else if (rsurface.uselightmaptexture)
4694 R_Mesh_TexBind(7, R_GetTexture(texturesurfacelist[0]->lightmaptexture));
4695 if (r_glsl_permutation->loc_Texture_Deluxemap >= 0)
4696 R_Mesh_TexBind(8, R_GetTexture(texturesurfacelist[0]->deluxemaptexture));
4697 R_Mesh_ColorPointer(NULL, 0, 0);
4701 R_Mesh_TexBind(7, R_GetTexture(r_texture_white));
4702 if (r_glsl_permutation->loc_Texture_Deluxemap >= 0)
4703 R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
4704 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
4707 if (rsurface.uselightmaptexture && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT))
4708 RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist, 7, r_glsl_permutation->loc_Texture_Deluxemap >= 0 ? 8 : -1);
4710 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
4711 if (rsurface.texture->backgroundnumskinframes && !(rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED))
4716 static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, msurface_t **texturesurfacelist)
4718 // OpenGL 1.3 path - anything not completely ancient
4719 int texturesurfaceindex;
4720 qboolean applycolor;
4724 const texturelayer_t *layer;
4725 if (rsurface.mode != RSURFMODE_MULTIPASS)
4726 rsurface.mode = RSURFMODE_MULTIPASS;
4727 RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist);
4728 for (layerindex = 0, layer = rsurface.texture->currentlayers;layerindex < rsurface.texture->currentnumlayers;layerindex++, layer++)
4731 int layertexrgbscale;
4732 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
4734 if (layerindex == 0)
4738 GL_AlphaTest(false);
4739 qglDepthFunc(GL_EQUAL);CHECKGLERROR
4742 GL_DepthMask(layer->depthmask);
4743 GL_BlendFunc(layer->blendfunc1, layer->blendfunc2);
4744 if ((layer->color[0] > 2 || layer->color[1] > 2 || layer->color[2] > 2) && (gl_combine.integer || layer->depthmask))
4746 layertexrgbscale = 4;
4747 VectorScale(layer->color, 0.25f, layercolor);
4749 else if ((layer->color[0] > 1 || layer->color[1] > 1 || layer->color[2] > 1) && (gl_combine.integer || layer->depthmask))
4751 layertexrgbscale = 2;
4752 VectorScale(layer->color, 0.5f, layercolor);
4756 layertexrgbscale = 1;
4757 VectorScale(layer->color, 1.0f, layercolor);
4759 layercolor[3] = layer->color[3];
4760 applycolor = layercolor[0] != 1 || layercolor[1] != 1 || layercolor[2] != 1 || layercolor[3] != 1;
4761 R_Mesh_ColorPointer(NULL, 0, 0);
4762 applyfog = (layer->flags & TEXTURELAYERFLAG_FOGDARKEN) != 0;
4763 switch (layer->type)
4765 case TEXTURELAYERTYPE_LITTEXTURE:
4766 memset(&m, 0, sizeof(m));
4767 m.tex[0] = R_GetTexture(r_texture_white);
4768 m.pointer_texcoord[0] = rsurface.modeltexcoordlightmap2f;
4769 m.pointer_texcoord_bufferobject[0] = rsurface.modeltexcoordlightmap2f_bufferobject;
4770 m.pointer_texcoord_bufferoffset[0] = rsurface.modeltexcoordlightmap2f_bufferoffset;
4771 m.tex[1] = R_GetTexture(layer->texture);
4772 m.texmatrix[1] = layer->texmatrix;
4773 m.texrgbscale[1] = layertexrgbscale;
4774 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
4775 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
4776 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
4777 R_Mesh_TextureState(&m);
4778 if (rsurface.lightmode == 2)
4779 RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
4780 else if (rsurface.uselightmaptexture)
4781 RSurf_DrawBatch_GL11_Lightmap(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
4783 RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
4785 case TEXTURELAYERTYPE_TEXTURE:
4786 memset(&m, 0, sizeof(m));
4787 m.tex[0] = R_GetTexture(layer->texture);
4788 m.texmatrix[0] = layer->texmatrix;
4789 m.texrgbscale[0] = layertexrgbscale;
4790 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
4791 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
4792 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
4793 R_Mesh_TextureState(&m);
4794 RSurf_DrawBatch_GL11_Unlit(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
4796 case TEXTURELAYERTYPE_FOG:
4797 memset(&m, 0, sizeof(m));
4798 m.texrgbscale[0] = layertexrgbscale;
4801 m.tex[0] = R_GetTexture(layer->texture);
4802 m.texmatrix[0] = layer->texmatrix;
4803 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
4804 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
4805 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
4807 R_Mesh_TextureState(&m);
4808 // generate a color array for the fog pass
4809 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
4810 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4814 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4815 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)
4817 f = 1 - FogPoint_Model(v);
4818 c[0] = layercolor[0];
4819 c[1] = layercolor[1];
4820 c[2] = layercolor[2];
4821 c[3] = f * layercolor[3];
4824 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
4827 Con_Printf("R_DrawTextureSurfaceList: unknown layer type %i\n", layer->type);
4829 GL_LockArrays(0, 0);
4832 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
4834 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
4835 GL_AlphaTest(false);
4839 static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, msurface_t **texturesurfacelist)
4841 // OpenGL 1.1 - crusty old voodoo path
4842 int texturesurfaceindex;
4846 const texturelayer_t *layer;
4847 if (rsurface.mode != RSURFMODE_MULTIPASS)
4848 rsurface.mode = RSURFMODE_MULTIPASS;
4849 RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist);
4850 for (layerindex = 0, layer = rsurface.texture->currentlayers;layerindex < rsurface.texture->currentnumlayers;layerindex++, layer++)
4852 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
4854 if (layerindex == 0)
4858 GL_AlphaTest(false);
4859 qglDepthFunc(GL_EQUAL);CHECKGLERROR
4862 GL_DepthMask(layer->depthmask);
4863 GL_BlendFunc(layer->blendfunc1, layer->blendfunc2);
4864 R_Mesh_ColorPointer(NULL, 0, 0);
4865 applyfog = (layer->flags & TEXTURELAYERFLAG_FOGDARKEN) != 0;
4866 switch (layer->type)
4868 case TEXTURELAYERTYPE_LITTEXTURE:
4869 if (layer->blendfunc1 == GL_ONE && layer->blendfunc2 == GL_ZERO)
4871 // two-pass lit texture with 2x rgbscale
4872 // first the lightmap pass
4873 memset(&m, 0, sizeof(m));
4874 m.tex[0] = R_GetTexture(r_texture_white);
4875 m.pointer_texcoord[0] = rsurface.modeltexcoordlightmap2f;
4876 m.pointer_texcoord_bufferobject[0] = rsurface.modeltexcoordlightmap2f_bufferobject;
4877 m.pointer_texcoord_bufferoffset[0] = rsurface.modeltexcoordlightmap2f_bufferoffset;
4878 R_Mesh_TextureState(&m);
4879 if (rsurface.lightmode == 2)
4880 RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
4881 else if (rsurface.uselightmaptexture)
4882 RSurf_DrawBatch_GL11_Lightmap(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
4884 RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
4885 GL_LockArrays(0, 0);
4886 // then apply the texture to it
4887 GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
4888 memset(&m, 0, sizeof(m));
4889 m.tex[0] = R_GetTexture(layer->texture);
4890 m.texmatrix[0] = layer->texmatrix;
4891 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
4892 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
4893 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
4894 R_Mesh_TextureState(&m);
4895 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);
4899 // single pass vertex-lighting-only texture with 1x rgbscale and transparency support
4900 memset(&m, 0, sizeof(m));
4901 m.tex[0] = R_GetTexture(layer->texture);
4902 m.texmatrix[0] = layer->texmatrix;
4903 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
4904 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
4905 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
4906 R_Mesh_TextureState(&m);
4907 if (rsurface.lightmode == 2)
4908 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);
4910 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);
4913 case TEXTURELAYERTYPE_TEXTURE:
4914 // singletexture unlit texture with transparency support
4915 memset(&m, 0, sizeof(m));
4916 m.tex[0] = R_GetTexture(layer->texture);
4917 m.texmatrix[0] = layer->texmatrix;
4918 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
4919 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
4920 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
4921 R_Mesh_TextureState(&m);
4922 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);
4924 case TEXTURELAYERTYPE_FOG:
4925 // singletexture fogging
4926 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
4929 memset(&m, 0, sizeof(m));
4930 m.tex[0] = R_GetTexture(layer->texture);
4931 m.texmatrix[0] = layer->texmatrix;
4932 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
4933 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
4934 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
4935 R_Mesh_TextureState(&m);
4938 R_Mesh_ResetTextureState();
4939 // generate a color array for the fog pass
4940 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4944 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4945 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)
4947 f = 1 - FogPoint_Model(v);
4948 c[0] = layer->color[0];
4949 c[1] = layer->color[1];
4950 c[2] = layer->color[2];
4951 c[3] = f * layer->color[3];
4954 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
4957 Con_Printf("R_DrawTextureSurfaceList: unknown layer type %i\n", layer->type);
4959 GL_LockArrays(0, 0);
4962 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
4964 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
4965 GL_AlphaTest(false);
4969 static void R_DrawTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly)
4971 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW)
4973 rsurface.rtlight = NULL;
4977 if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
4979 if (rsurface.mode != RSURFMODE_MULTIPASS)
4980 rsurface.mode = RSURFMODE_MULTIPASS;
4981 if (r_depthfirst.integer == 3)
4983 int i = (int)(texturesurfacelist[0] - rsurface.modelsurfaces);
4984 GL_Color(((i >> 6) & 7) / 7.0f, ((i >> 3) & 7) / 7.0f, (i & 7) / 7.0f,1);
4988 GL_ColorMask(0,0,0,0);
4991 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
4992 GL_PolygonOffset(rsurface.texture->currentpolygonfactor, rsurface.texture->currentpolygonoffset);
4993 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
4995 GL_BlendFunc(GL_ONE, GL_ZERO);
4997 GL_AlphaTest(false);
4998 R_Mesh_ColorPointer(NULL, 0, 0);
4999 R_Mesh_ResetTextureState();
5000 RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
5001 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
5002 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
5003 r_refdef.stats.entities_surfaces += texturenumsurfaces;
5005 else if (r_depthfirst.integer == 3)
5007 else if (r_showsurfaces.integer)
5009 if (rsurface.mode != RSURFMODE_MULTIPASS)
5010 rsurface.mode = RSURFMODE_MULTIPASS;
5011 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
5012 GL_PolygonOffset(rsurface.texture->currentpolygonfactor, rsurface.texture->currentpolygonoffset);
5014 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
5015 GL_BlendFunc(GL_ONE, GL_ZERO);
5016 GL_DepthMask(writedepth);
5018 GL_AlphaTest(false);
5019 R_Mesh_ColorPointer(NULL, 0, 0);
5020 R_Mesh_ResetTextureState();
5021 RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
5022 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist);
5023 r_refdef.stats.entities_surfaces += texturenumsurfaces;
5025 else if (gl_lightmaps.integer)
5028 if (rsurface.mode != RSURFMODE_MULTIPASS)
5029 rsurface.mode = RSURFMODE_MULTIPASS;
5030 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
5032 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
5033 GL_BlendFunc(GL_ONE, GL_ZERO);
5034 GL_DepthMask(writedepth);
5036 GL_AlphaTest(false);
5037 // use lightmode 0 (fullbright or lightmap) or 2 (model lighting)
5038 rsurface.lightmode = ((rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || rsurface.modeltexcoordlightmap2f != NULL) ? 0 : 2;
5039 R_Mesh_ColorPointer(NULL, 0, 0);
5040 memset(&m, 0, sizeof(m));
5041 m.tex[0] = R_GetTexture(r_texture_white);
5042 m.pointer_texcoord[0] = rsurface.modeltexcoordlightmap2f;
5043 m.pointer_texcoord_bufferobject[0] = rsurface.modeltexcoordlightmap2f_bufferobject;
5044 m.pointer_texcoord_bufferoffset[0] = rsurface.modeltexcoordlightmap2f_bufferoffset;
5045 R_Mesh_TextureState(&m);
5046 RSurf_PrepareVerticesForBatch(rsurface.lightmode == 2, false, texturenumsurfaces, texturesurfacelist);
5047 if (rsurface.lightmode == 2)
5048 RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
5049 else if (rsurface.uselightmaptexture)
5050 RSurf_DrawBatch_GL11_Lightmap(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
5052 RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
5053 r_refdef.stats.entities_surfaces += texturenumsurfaces;
5055 else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY)
5057 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
5058 r_refdef.stats.entities_surfaces += texturenumsurfaces;
5060 else if (rsurface.texture->currentnumlayers)
5062 // write depth for anything we skipped on the depth-only pass earlier
5063 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
5065 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
5066 GL_PolygonOffset(rsurface.texture->currentpolygonfactor, rsurface.texture->currentpolygonoffset);
5067 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
5068 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
5069 GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
5070 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
5071 GL_AlphaTest((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
5072 // use lightmode 0 (fullbright or lightmap) or 2 (model lighting)
5073 rsurface.lightmode = ((rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || rsurface.modeltexcoordlightmap2f != NULL) ? 0 : 2;
5074 if (r_glsl.integer && gl_support_fragment_shader)
5075 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist);
5076 else if (gl_combine.integer && r_textureunits.integer >= 2)
5077 R_DrawTextureSurfaceList_GL13(texturenumsurfaces, texturesurfacelist);
5079 R_DrawTextureSurfaceList_GL11(texturenumsurfaces, texturesurfacelist);
5080 r_refdef.stats.entities_surfaces += texturenumsurfaces;
5083 GL_LockArrays(0, 0);
5086 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5089 int texturenumsurfaces, endsurface;
5091 msurface_t *surface;
5092 msurface_t *texturesurfacelist[1024];
5094 // if the model is static it doesn't matter what value we give for
5095 // wantnormals and wanttangents, so this logic uses only rules applicable
5096 // to a model, knowing that they are meaningless otherwise
5097 if (ent == r_refdef.worldentity)
5098 RSurf_ActiveWorldEntity();
5099 else if ((ent->effects & EF_FULLBRIGHT) || r_showsurfaces.integer || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f))
5100 RSurf_ActiveModelEntity(ent, false, false);
5102 RSurf_ActiveModelEntity(ent, true, r_glsl.integer && gl_support_fragment_shader);
5104 for (i = 0;i < numsurfaces;i = j)
5107 surface = rsurface.modelsurfaces + surfacelist[i];
5108 texture = surface->texture;
5109 R_UpdateTextureInfo(ent, texture);
5110 rsurface.texture = texture->currentframe;
5111 rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
5112 // scan ahead until we find a different texture
5113 endsurface = min(i + 1024, numsurfaces);
5114 texturenumsurfaces = 0;
5115 texturesurfacelist[texturenumsurfaces++] = surface;
5116 for (;j < endsurface;j++)
5118 surface = rsurface.modelsurfaces + surfacelist[j];
5119 if (texture != surface->texture || rsurface.uselightmaptexture != (surface->lightmaptexture != NULL))
5121 texturesurfacelist[texturenumsurfaces++] = surface;
5123 // render the range of surfaces
5124 R_DrawTextureSurfaceList(texturenumsurfaces, texturesurfacelist, true, false);
5130 void R_QueueSurfaceList(entity_render_t *ent, int numsurfaces, msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly)
5133 vec3_t tempcenter, center;
5135 // break the surface list down into batches by texture and use of lightmapping
5136 for (i = 0;i < numsurfaces;i = j)
5139 // texture is the base texture pointer, rsurface.texture is the
5140 // current frame/skin the texture is directing us to use (for example
5141 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
5142 // use skin 1 instead)
5143 texture = surfacelist[i]->texture;
5144 rsurface.texture = texture->currentframe;
5145 rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
5146 if (!(rsurface.texture->currentmaterialflags & flagsmask))
5148 // if this texture is not the kind we want, skip ahead to the next one
5149 for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
5153 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
5155 // transparent surfaces get pushed off into the transparent queue
5156 const msurface_t *surface = surfacelist[i];
5159 tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
5160 tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
5161 tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
5162 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
5163 R_MeshQueue_AddTransparent(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_view.origin : center, R_DrawSurface_TransparentCallback, ent, surface - rsurface.modelsurfaces, rsurface.rtlight);
5167 // simply scan ahead until we find a different texture or lightmap state
5168 for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.uselightmaptexture == (surfacelist[j]->lightmaptexture != NULL);j++)
5170 // render the range of surfaces
5171 R_DrawTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly);
5176 float locboxvertex3f[6*4*3] =
5178 1,0,1, 1,0,0, 1,1,0, 1,1,1,
5179 0,1,1, 0,1,0, 0,0,0, 0,0,1,
5180 1,1,1, 1,1,0, 0,1,0, 0,1,1,
5181 0,0,1, 0,0,0, 1,0,0, 1,0,1,
5182 0,0,1, 1,0,1, 1,1,1, 0,1,1,
5183 1,0,0, 0,0,0, 0,1,0, 1,1,0
5186 int locboxelement3i[6*2*3] =
5196 void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5199 cl_locnode_t *loc = (cl_locnode_t *)ent;
5201 float vertex3f[6*4*3];
5203 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5204 GL_DepthMask(false);
5205 GL_DepthRange(0, 1);
5206 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
5208 GL_CullFace(GL_NONE);
5209 R_Mesh_Matrix(&identitymatrix);
5211 R_Mesh_VertexPointer(vertex3f, 0, 0);
5212 R_Mesh_ColorPointer(NULL, 0, 0);
5213 R_Mesh_ResetTextureState();
5216 GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_view.colorscale,
5217 ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_view.colorscale,
5218 ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_view.colorscale,
5219 surfacelist[0] < 0 ? 0.5f : 0.125f);
5221 if (VectorCompare(loc->mins, loc->maxs))
5223 VectorSet(size, 2, 2, 2);
5224 VectorMA(loc->mins, -0.5f, size, mins);
5228 VectorCopy(loc->mins, mins);
5229 VectorSubtract(loc->maxs, loc->mins, size);
5232 for (i = 0;i < 6*4*3;)
5233 for (j = 0;j < 3;j++, i++)
5234 vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
5236 R_Mesh_Draw(0, 6*4, 6*2, locboxelement3i, 0, 0);
5239 void R_DrawLocs(void)
5242 cl_locnode_t *loc, *nearestloc;
5244 nearestloc = CL_Locs_FindNearest(cl.movement_origin);
5245 for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
5247 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
5248 R_MeshQueue_AddTransparent(center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
5252 void R_DrawCollisionBrushes(entity_render_t *ent)
5256 msurface_t *surface;
5257 model_t *model = ent->model;
5258 if (!model->brush.num_brushes)
5261 R_Mesh_ColorPointer(NULL, 0, 0);
5262 R_Mesh_ResetTextureState();
5263 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
5264 GL_DepthMask(false);
5265 GL_DepthRange(0, 1);
5266 GL_DepthTest(!r_showdisabledepthtest.integer);
5267 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
5268 for (i = 0, brush = model->brush.data_brushes + model->firstmodelbrush;i < model->nummodelbrushes;i++, brush++)
5269 if (brush->colbrushf && brush->colbrushf->numtriangles)
5270 R_DrawCollisionBrush(brush->colbrushf);
5271 for (i = 0, surface = model->data_surfaces + model->firstmodelsurface;i < model->nummodelsurfaces;i++, surface++)
5272 if (surface->num_collisiontriangles)
5273 R_DrawCollisionSurface(ent, surface);
5274 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
5277 void R_DrawTrianglesAndNormals(entity_render_t *ent, qboolean drawtris, qboolean drawnormals, int flagsmask)
5280 const int *elements;
5281 msurface_t *surface;
5282 model_t *model = ent->model;
5285 GL_DepthRange(0, 1);
5286 GL_DepthTest(!r_showdisabledepthtest.integer);
5287 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
5289 GL_BlendFunc(GL_ONE, GL_ZERO);
5290 R_Mesh_ColorPointer(NULL, 0, 0);
5291 R_Mesh_ResetTextureState();
5292 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
5294 if (ent == r_refdef.worldentity && !r_viewcache.world_surfacevisible[j])
5296 rsurface.texture = surface->texture->currentframe;
5297 if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
5299 RSurf_PrepareVerticesForBatch(true, true, 1, &surface);
5302 if (!rsurface.texture->currentlayers->depthmask)
5303 GL_Color(r_showtris.value * r_view.colorscale, 0, 0, 1);
5304 else if (ent == r_refdef.worldentity)
5305 GL_Color(r_showtris.value * r_view.colorscale, r_showtris.value * r_view.colorscale, r_showtris.value * r_view.colorscale, 1);
5307 GL_Color(0, r_showtris.value * r_view.colorscale, 0, 1);
5308 elements = (ent->model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);
5311 for (k = 0;k < surface->num_triangles;k++, elements += 3)
5313 #define GLVERTEXELEMENT(n) qglVertex3f(rsurface.vertex3f[elements[n]*3+0], rsurface.vertex3f[elements[n]*3+1], rsurface.vertex3f[elements[n]*3+2])
5314 GLVERTEXELEMENT(0);GLVERTEXELEMENT(1);
5315 GLVERTEXELEMENT(1);GLVERTEXELEMENT(2);
5316 GLVERTEXELEMENT(2);GLVERTEXELEMENT(0);
5323 GL_Color(r_shownormals.value * r_view.colorscale, 0, 0, 1);
5325 for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
5327 VectorCopy(rsurface.vertex3f + l * 3, v);
5328 qglVertex3f(v[0], v[1], v[2]);
5329 VectorMA(v, 8, rsurface.svector3f + l * 3, v);
5330 qglVertex3f(v[0], v[1], v[2]);
5334 GL_Color(0, 0, r_shownormals.value * r_view.colorscale, 1);
5336 for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
5338 VectorCopy(rsurface.vertex3f + l * 3, v);
5339 qglVertex3f(v[0], v[1], v[2]);
5340 VectorMA(v, 8, rsurface.tvector3f + l * 3, v);
5341 qglVertex3f(v[0], v[1], v[2]);
5345 GL_Color(0, r_shownormals.value * r_view.colorscale, 0, 1);
5347 for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
5349 VectorCopy(rsurface.vertex3f + l * 3, v);
5350 qglVertex3f(v[0], v[1], v[2]);
5351 VectorMA(v, 8, rsurface.normal3f + l * 3, v);
5352 qglVertex3f(v[0], v[1], v[2]);
5359 rsurface.texture = NULL;
5362 extern void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface);
5363 void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean depthonly)
5365 int i, j, endj, f, flagsmask;
5366 int counttriangles = 0;
5367 msurface_t *surface, **surfacechain;
5369 model_t *model = r_refdef.worldmodel;
5370 const int maxsurfacelist = 1024;
5371 int numsurfacelist = 0;
5372 msurface_t *surfacelist[1024];
5376 RSurf_ActiveWorldEntity();
5378 // update light styles
5379 if (!skysurfaces && !depthonly && model->brushq1.light_styleupdatechains)
5381 for (i = 0;i < model->brushq1.light_styles;i++)
5383 if (model->brushq1.light_stylevalue[i] != r_refdef.lightstylevalue[model->brushq1.light_style[i]])
5385 model->brushq1.light_stylevalue[i] = r_refdef.lightstylevalue[model->brushq1.light_style[i]];
5386 if ((surfacechain = model->brushq1.light_styleupdatechains[i]))
5387 for (;(surface = *surfacechain);surfacechain++)
5388 surface->cached_dlight = true;
5393 R_UpdateAllTextureInfo(r_refdef.worldentity);
5394 flagsmask = skysurfaces ? MATERIALFLAG_SKY : (MATERIALFLAG_WATER | MATERIALFLAG_WALL);
5397 rsurface.uselightmaptexture = false;
5398 rsurface.texture = NULL;
5400 j = model->firstmodelsurface;
5401 endj = j + model->nummodelsurfaces;
5404 // quickly skip over non-visible surfaces
5405 for (;j < endj && !r_viewcache.world_surfacevisible[j];j++)
5407 // quickly iterate over visible surfaces
5408 for (;j < endj && r_viewcache.world_surfacevisible[j];j++)
5410 // process this surface
5411 surface = model->data_surfaces + j;
5412 // if this surface fits the criteria, add it to the list
5413 if (surface->num_triangles)
5415 // if lightmap parameters changed, rebuild lightmap texture
5416 if (surface->cached_dlight)
5417 R_BuildLightMap(r_refdef.worldentity, surface);
5418 // add face to draw list
5419 surfacelist[numsurfacelist++] = surface;
5420 counttriangles += surface->num_triangles;
5421 if (numsurfacelist >= maxsurfacelist)
5423 R_QueueSurfaceList(r_refdef.worldentity, numsurfacelist, surfacelist, flagsmask, writedepth, depthonly);
5430 R_QueueSurfaceList(r_refdef.worldentity, numsurfacelist, surfacelist, flagsmask, writedepth, depthonly);
5431 r_refdef.stats.entities_triangles += counttriangles;
5434 if (r_showcollisionbrushes.integer && !skysurfaces && !depthonly)
5435 R_DrawCollisionBrushes(r_refdef.worldentity);
5437 if ((r_showtris.integer || r_shownormals.integer) && !depthonly)
5438 R_DrawTrianglesAndNormals(r_refdef.worldentity, r_showtris.integer, r_shownormals.integer, flagsmask);
5441 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly)
5443 int i, f, flagsmask;
5444 int counttriangles = 0;
5445 msurface_t *surface, *endsurface, **surfacechain;
5447 model_t *model = ent->model;
5448 const int maxsurfacelist = 1024;
5449 int numsurfacelist = 0;
5450 msurface_t *surfacelist[1024];
5454 // if the model is static it doesn't matter what value we give for
5455 // wantnormals and wanttangents, so this logic uses only rules applicable
5456 // to a model, knowing that they are meaningless otherwise
5457 if (ent == r_refdef.worldentity)
5458 RSurf_ActiveWorldEntity();
5459 else if ((ent->effects & EF_FULLBRIGHT) || r_showsurfaces.integer || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f))
5460 RSurf_ActiveModelEntity(ent, false, false);
5462 RSurf_ActiveModelEntity(ent, true, r_glsl.integer && gl_support_fragment_shader && !depthonly);
5464 // update light styles
5465 if (!skysurfaces && !depthonly && model->brushq1.light_styleupdatechains)
5467 for (i = 0;i < model->brushq1.light_styles;i++)
5469 if (model->brushq1.light_stylevalue[i] != r_refdef.lightstylevalue[model->brushq1.light_style[i]])
5471 model->brushq1.light_stylevalue[i] = r_refdef.lightstylevalue[model->brushq1.light_style[i]];
5472 if ((surfacechain = model->brushq1.light_styleupdatechains[i]))
5473 for (;(surface = *surfacechain);surfacechain++)
5474 surface->cached_dlight = true;
5479 R_UpdateAllTextureInfo(ent);
5480 flagsmask = skysurfaces ? MATERIALFLAG_SKY : (MATERIALFLAG_WATER | MATERIALFLAG_WALL);
5483 rsurface.uselightmaptexture = false;
5484 rsurface.texture = NULL;
5486 surface = model->data_surfaces + model->firstmodelsurface;
5487 endsurface = surface + model->nummodelsurfaces;
5488 for (;surface < endsurface;surface++)
5490 // if this surface fits the criteria, add it to the list
5491 if (surface->num_triangles)
5493 // if lightmap parameters changed, rebuild lightmap texture
5494 if (surface->cached_dlight)
5495 R_BuildLightMap(ent, surface);
5496 // add face to draw list
5497 surfacelist[numsurfacelist++] = surface;
5498 counttriangles += surface->num_triangles;
5499 if (numsurfacelist >= maxsurfacelist)
5501 R_QueueSurfaceList(ent, numsurfacelist, surfacelist, flagsmask, writedepth, depthonly);
5507 R_QueueSurfaceList(ent, numsurfacelist, surfacelist, flagsmask, writedepth, depthonly);
5508 r_refdef.stats.entities_triangles += counttriangles;
5511 if (r_showcollisionbrushes.integer && !skysurfaces && !depthonly)
5512 R_DrawCollisionBrushes(ent);
5514 if ((r_showtris.integer || r_shownormals.integer) && !depthonly)
5515 R_DrawTrianglesAndNormals(ent, r_showtris.integer, r_shownormals.integer, flagsmask);