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)
987 Con_Printf("OpenGL 2.0 shaders disabled - unable to find a working shader permutation fallback on this driver (set r_glsl 1 if you want to try again)\n");
988 Cvar_SetValueQuick(&r_glsl, 0);
989 return 0; // no bit left to clear
991 // reduce i more quickly whenever it would not remove any bits
992 if (!(permutation & i))
995 if (!r_glsl_permutations[permutation & SHADERPERMUTATION_MASK].compiled)
996 R_GLSL_CompilePermutation(shaderfilename, permutation);
997 if (r_glsl_permutations[permutation & SHADERPERMUTATION_MASK].program)
1002 r_glsl_permutation = r_glsl_permutations + (permutation & SHADERPERMUTATION_MASK);
1004 qglUseProgramObjectARB(r_glsl_permutation->program);CHECKGLERROR
1005 R_Mesh_TexMatrix(0, &rsurface.texture->currenttexmatrix);
1006 if (permutation & SHADERPERMUTATION_MODE_LIGHTSOURCE)
1008 if (r_glsl_permutation->loc_Texture_Cube >= 0 && rsurface.rtlight) R_Mesh_TexBindCubeMap(3, R_GetTexture(rsurface.rtlight->currentcubemap));
1009 if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
1010 if (permutation & SHADERPERMUTATION_DIFFUSE)
1012 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightColor, lightcolorbase[0], lightcolorbase[1], lightcolorbase[2]);
1013 if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, ambientscale);
1014 if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, diffusescale);
1015 if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, specularscale);
1019 // ambient only is simpler
1020 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3fARB(r_glsl_permutation->loc_LightColor, lightcolorbase[0] * ambientscale, lightcolorbase[1] * ambientscale, lightcolorbase[2] * ambientscale);
1021 if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, 1);
1022 if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, 0);
1023 if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, 0);
1026 else if (permutation & SHADERPERMUTATION_MODE_LIGHTDIRECTION)
1028 if (r_glsl_permutation->loc_AmbientColor >= 0)
1029 qglUniform3fARB(r_glsl_permutation->loc_AmbientColor, rsurface.modellight_ambient[0] * ambientscale, rsurface.modellight_ambient[1] * ambientscale, rsurface.modellight_ambient[2] * ambientscale);
1030 if (r_glsl_permutation->loc_DiffuseColor >= 0)
1031 qglUniform3fARB(r_glsl_permutation->loc_DiffuseColor, rsurface.modellight_diffuse[0] * diffusescale, rsurface.modellight_diffuse[1] * diffusescale, rsurface.modellight_diffuse[2] * diffusescale);
1032 if (r_glsl_permutation->loc_SpecularColor >= 0)
1033 qglUniform3fARB(r_glsl_permutation->loc_SpecularColor, rsurface.modellight_diffuse[0] * specularscale, rsurface.modellight_diffuse[1] * specularscale, rsurface.modellight_diffuse[2] * specularscale);
1034 if (r_glsl_permutation->loc_LightDir >= 0)
1035 qglUniform3fARB(r_glsl_permutation->loc_LightDir, rsurface.modellight_lightdir[0], rsurface.modellight_lightdir[1], rsurface.modellight_lightdir[2]);
1039 if (r_glsl_permutation->loc_AmbientScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_AmbientScale, r_ambient.value * 2.0f / 128.0f);
1040 if (r_glsl_permutation->loc_DiffuseScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_DiffuseScale, r_refdef.lightmapintensity * 2.0f);
1041 if (r_glsl_permutation->loc_SpecularScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularScale, r_refdef.lightmapintensity * specularscale * 2.0f);
1043 nmap = rsurface.texture->currentskinframe->nmap;
1044 if (gl_lightmaps.integer)
1045 nmap = r_texture_blanknormalmap;
1046 if (r_glsl_permutation->loc_Texture_Normal >= 0) R_Mesh_TexBind(0, R_GetTexture(nmap));
1047 if (r_glsl_permutation->loc_Texture_Color >= 0) R_Mesh_TexBind(1, R_GetTexture(rsurface.texture->basetexture));
1048 if (r_glsl_permutation->loc_Texture_Gloss >= 0) R_Mesh_TexBind(2, R_GetTexture(rsurface.texture->glosstexture));
1049 //if (r_glsl_permutation->loc_Texture_Cube >= 0 && permutation & SHADERPERMUTATION_MODE_LIGHTSOURCE) R_Mesh_TexBindCubeMap(3, R_GetTexture(rsurface.rtlight->currentcubemap));
1050 if (r_glsl_permutation->loc_Texture_Attenuation >= 0) R_Mesh_TexBind(10, R_GetTexture(r_shadow_attenuationgradienttexture));
1051 if (r_glsl_permutation->loc_Texture_FogMask >= 0) R_Mesh_TexBind(4, R_GetTexture(r_texture_fogattenuation));
1052 if (r_glsl_permutation->loc_Texture_Pants >= 0) R_Mesh_TexBind(5, R_GetTexture(rsurface.texture->currentskinframe->pants));
1053 if (r_glsl_permutation->loc_Texture_Shirt >= 0) R_Mesh_TexBind(6, R_GetTexture(rsurface.texture->currentskinframe->shirt));
1054 //if (r_glsl_permutation->loc_Texture_Lightmap >= 0) R_Mesh_TexBind(7, R_GetTexture(r_texture_white));
1055 //if (r_glsl_permutation->loc_Texture_Deluxemap >= 0) R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
1056 if (r_glsl_permutation->loc_Texture_Glow >= 0) R_Mesh_TexBind(9, R_GetTexture(rsurface.texture->currentskinframe->glow));
1057 if (r_glsl_permutation->loc_GlowScale >= 0) qglUniform1fARB(r_glsl_permutation->loc_GlowScale, r_hdr_glowintensity.value);
1058 if (r_glsl_permutation->loc_ContrastBoostCoeff >= 0)
1060 // The formula used is actually:
1061 // color.rgb *= SceneBrightness;
1062 // color.rgb *= ContrastBoost / ((ContrastBoost - 1) * color.rgb + 1);
1063 // I simplify that to
1064 // color.rgb *= [[SceneBrightness * ContrastBoost]];
1065 // color.rgb /= [[(ContrastBoost - 1) / ContrastBoost]] * color.rgb + 1;
1067 // color.rgb = [[SceneBrightness * ContrastBoost]] / ([[(ContrastBoost - 1) * SceneBrightness]] + 1 / color.rgb);
1068 // and do [[calculations]] here in the engine
1069 qglUniform1fARB(r_glsl_permutation->loc_ContrastBoostCoeff, (r_glsl_contrastboost.value - 1) * r_view.colorscale);
1070 if (r_glsl_permutation->loc_SceneBrightness >= 0) qglUniform1fARB(r_glsl_permutation->loc_SceneBrightness, r_view.colorscale * r_glsl_contrastboost.value);
1073 if (r_glsl_permutation->loc_SceneBrightness >= 0) qglUniform1fARB(r_glsl_permutation->loc_SceneBrightness, r_view.colorscale);
1074 if (r_glsl_permutation->loc_FogColor >= 0)
1076 // additive passes are only darkened by fog, not tinted
1077 if (rsurface.rtlight || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ADD))
1078 qglUniform3fARB(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1080 qglUniform3fARB(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1082 if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3fARB(r_glsl_permutation->loc_EyePosition, rsurface.modelorg[0], rsurface.modelorg[1], rsurface.modelorg[2]);
1083 if (r_glsl_permutation->loc_Color_Pants >= 0)
1085 if (rsurface.texture->currentskinframe->pants)
1086 qglUniform3fARB(r_glsl_permutation->loc_Color_Pants, rsurface.colormap_pantscolor[0], rsurface.colormap_pantscolor[1], rsurface.colormap_pantscolor[2]);
1088 qglUniform3fARB(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
1090 if (r_glsl_permutation->loc_Color_Shirt >= 0)
1092 if (rsurface.texture->currentskinframe->shirt)
1093 qglUniform3fARB(r_glsl_permutation->loc_Color_Shirt, rsurface.colormap_shirtcolor[0], rsurface.colormap_shirtcolor[1], rsurface.colormap_shirtcolor[2]);
1095 qglUniform3fARB(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
1097 if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1fARB(r_glsl_permutation->loc_FogRangeRecip, r_refdef.fograngerecip);
1098 if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1fARB(r_glsl_permutation->loc_SpecularPower, rsurface.texture->specularpower);
1099 if (r_glsl_permutation->loc_OffsetMapping_Scale >= 0) qglUniform1fARB(r_glsl_permutation->loc_OffsetMapping_Scale, r_glsl_offsetmapping_scale.value);
1104 void R_SwitchSurfaceShader(int permutation)
1106 if (r_glsl_permutation != r_glsl_permutations + (permutation & SHADERPERMUTATION_MASK))
1108 r_glsl_permutation = r_glsl_permutations + (permutation & SHADERPERMUTATION_MASK);
1110 qglUseProgramObjectARB(r_glsl_permutation->program);
1115 #define SKINFRAME_HASH 1024
1119 int loadsequence; // incremented each level change
1120 memexpandablearray_t array;
1121 skinframe_t *hash[SKINFRAME_HASH];
1125 void R_SkinFrame_PrepareForPurge(void)
1127 r_skinframe.loadsequence++;
1128 // wrap it without hitting zero
1129 if (r_skinframe.loadsequence >= 200)
1130 r_skinframe.loadsequence = 1;
1133 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
1137 // mark the skinframe as used for the purging code
1138 skinframe->loadsequence = r_skinframe.loadsequence;
1141 void R_SkinFrame_Purge(void)
1145 for (i = 0;i < SKINFRAME_HASH;i++)
1147 for (s = r_skinframe.hash[i];s;s = s->next)
1149 if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
1151 if (s->base == r_texture_notexture) s->base = NULL;
1152 if (s->nmap == r_texture_blanknormalmap)s->nmap = NULL;
1153 if (s->merged == s->base) s->merged = NULL;
1154 if (s->stain ) R_FreeTexture(s->stain );s->stain = NULL;
1155 if (s->merged) R_FreeTexture(s->merged);s->merged = NULL;
1156 if (s->base ) R_FreeTexture(s->base );s->base = NULL;
1157 if (s->pants ) R_FreeTexture(s->pants );s->pants = NULL;
1158 if (s->shirt ) R_FreeTexture(s->shirt );s->shirt = NULL;
1159 if (s->nmap ) R_FreeTexture(s->nmap );s->nmap = NULL;
1160 if (s->gloss ) R_FreeTexture(s->gloss );s->gloss = NULL;
1161 if (s->glow ) R_FreeTexture(s->glow );s->glow = NULL;
1162 if (s->fog ) R_FreeTexture(s->fog );s->fog = NULL;
1163 s->loadsequence = 0;
1169 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qboolean add)
1173 char basename[MAX_QPATH];
1175 Image_StripImageExtension(name, basename, sizeof(basename));
1177 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
1178 for (item = r_skinframe.hash[hashindex];item;item = item->next)
1179 if (!strcmp(item->basename, basename) && item->textureflags == textureflags && item->comparewidth == comparewidth && item->compareheight == compareheight && item->comparecrc == comparecrc)
1185 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
1186 memset(item, 0, sizeof(*item));
1187 strlcpy(item->basename, basename, sizeof(item->basename));
1188 item->textureflags = textureflags;
1189 item->comparewidth = comparewidth;
1190 item->compareheight = compareheight;
1191 item->comparecrc = comparecrc;
1192 item->next = r_skinframe.hash[hashindex];
1193 r_skinframe.hash[hashindex] = item;
1195 R_SkinFrame_MarkUsed(item);
1199 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain)
1201 // FIXME: it should be possible to disable loading various layers using
1202 // cvars, to prevent wasted loading time and memory usage if the user does
1204 qboolean loadnormalmap = true;
1205 qboolean loadgloss = true;
1206 qboolean loadpantsandshirt = true;
1207 qboolean loadglow = true;
1209 unsigned char *pixels;
1210 unsigned char *bumppixels;
1211 unsigned char *basepixels = NULL;
1212 int basepixels_width;
1213 int basepixels_height;
1214 skinframe_t *skinframe;
1216 if (cls.state == ca_dedicated)
1219 // return an existing skinframe if already loaded
1220 // if loading of the first image fails, don't make a new skinframe as it
1221 // would cause all future lookups of this to be missing
1222 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
1223 if (skinframe && skinframe->base)
1226 basepixels = loadimagepixels(name, complain, 0, 0);
1227 if (basepixels == NULL)
1230 // we've got some pixels to store, so really allocate this new texture now
1232 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
1233 skinframe->stain = NULL;
1234 skinframe->merged = NULL;
1235 skinframe->base = r_texture_notexture;
1236 skinframe->pants = NULL;
1237 skinframe->shirt = NULL;
1238 skinframe->nmap = r_texture_blanknormalmap;
1239 skinframe->gloss = NULL;
1240 skinframe->glow = NULL;
1241 skinframe->fog = NULL;
1243 basepixels_width = image_width;
1244 basepixels_height = image_height;
1245 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);
1247 if (textureflags & TEXF_ALPHA)
1249 for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
1250 if (basepixels[j] < 255)
1252 if (j < basepixels_width * basepixels_height * 4)
1254 // has transparent pixels
1255 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
1256 for (j = 0;j < image_width * image_height * 4;j += 4)
1261 pixels[j+3] = basepixels[j+3];
1263 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);
1268 // _norm is the name used by tenebrae and has been adopted as standard
1271 if ((pixels = loadimagepixels(va("%s_norm", skinframe->basename), false, 0, 0)) != NULL)
1273 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);
1277 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixels(va("%s_bump", skinframe->basename), false, 0, 0)) != NULL)
1279 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
1280 Image_HeightmapToNormalmap(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
1281 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);
1283 Mem_Free(bumppixels);
1285 else if (r_shadow_bumpscale_basetexture.value > 0)
1287 pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
1288 Image_HeightmapToNormalmap(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
1289 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);
1293 // _luma is supported for tenebrae compatibility
1294 // (I think it's a very stupid name, but oh well)
1295 // _glow is the preferred name
1296 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;}
1297 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;}
1298 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;}
1299 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;}
1302 Mem_Free(basepixels);
1307 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)
1312 for (i = 0;i < width*height;i++)
1313 if (((unsigned char *)&palette[in[i]])[3] > 0)
1315 if (i == width*height)
1318 return R_LoadTexture2D (r_main_texturepool, name, width, height, in, TEXTYPE_PALETTE, textureflags, palette);
1321 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)
1324 unsigned char *temp1, *temp2;
1325 skinframe_t *skinframe;
1327 if (cls.state == ca_dedicated)
1330 // if already loaded just return it, otherwise make a new skinframe
1331 skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height*bitsperpixel/8) : 0, true);
1332 if (skinframe && skinframe->base)
1335 skinframe->stain = NULL;
1336 skinframe->merged = NULL;
1337 skinframe->base = r_texture_notexture;
1338 skinframe->pants = NULL;
1339 skinframe->shirt = NULL;
1340 skinframe->nmap = r_texture_blanknormalmap;
1341 skinframe->gloss = NULL;
1342 skinframe->glow = NULL;
1343 skinframe->fog = NULL;
1345 // if no data was provided, then clearly the caller wanted to get a blank skinframe
1349 if (bitsperpixel == 32)
1351 if (r_shadow_bumpscale_basetexture.value > 0)
1353 temp1 = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
1354 temp2 = temp1 + width * height * 4;
1355 Image_HeightmapToNormalmap(skindata, temp2, width, height, false, r_shadow_bumpscale_basetexture.value);
1356 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va("%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_RGBA, skinframe->textureflags | TEXF_ALPHA, NULL);
1359 skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_RGBA, skinframe->textureflags, NULL);
1360 if (textureflags & TEXF_ALPHA)
1362 for (i = 3;i < width * height * 4;i += 4)
1363 if (skindata[i] < 255)
1365 if (i < width * height * 4)
1367 unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
1368 memcpy(fogpixels, skindata, width * height * 4);
1369 for (i = 0;i < width * height * 4;i += 4)
1370 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
1371 skinframe->fog = R_LoadTexture2D(r_main_texturepool, va("%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_RGBA, skinframe->textureflags, NULL);
1372 Mem_Free(fogpixels);
1376 else if (bitsperpixel == 8)
1378 if (r_shadow_bumpscale_basetexture.value > 0)
1380 temp1 = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
1381 temp2 = temp1 + width * height * 4;
1382 if (bitsperpixel == 32)
1383 Image_HeightmapToNormalmap(skindata, temp2, width, height, false, r_shadow_bumpscale_basetexture.value);
1386 // use either a custom palette or the quake palette
1387 Image_Copy8bitRGBA(skindata, temp1, width * height, palette ? palette : palette_complete);
1388 Image_HeightmapToNormalmap(temp1, temp2, width, height, false, r_shadow_bumpscale_basetexture.value);
1390 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va("%s_nmap", skinframe->basename), width, height, temp2, TEXTYPE_RGBA, skinframe->textureflags | TEXF_ALPHA, NULL);
1393 // use either a custom palette, or the quake palette
1394 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
1395 if (!palette && loadglowtexture)
1396 skinframe->glow = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_glow", skinframe->basename), palette_onlyfullbrights, skinframe->textureflags, false); // glow
1397 if (!palette && loadpantsandshirt)
1399 skinframe->pants = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_pants", skinframe->basename), palette_pantsaswhite, skinframe->textureflags, false); // pants
1400 skinframe->shirt = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_shirt", skinframe->basename), palette_shirtaswhite, skinframe->textureflags, false); // shirt
1402 if (skinframe->pants || skinframe->shirt)
1403 skinframe->base = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_nospecial", skinframe->basename),loadglowtexture ? palette_nocolormapnofullbrights : palette_nocolormap, skinframe->textureflags, false); // no special colors
1404 if (textureflags & TEXF_ALPHA)
1406 // if not using a custom alphapalette, use the quake one
1408 alphapalette = palette_alpha;
1409 for (i = 0;i < width * height;i++)
1410 if (((unsigned char *)alphapalette)[skindata[i]*4+3] < 255)
1412 if (i < width * height)
1413 skinframe->fog = R_SkinFrame_TextureForSkinLayer(skindata, width, height, va("%s_fog", skinframe->basename), alphapalette, skinframe->textureflags, true); // fog mask
1420 skinframe_t *R_SkinFrame_LoadMissing(void)
1422 skinframe_t *skinframe;
1424 if (cls.state == ca_dedicated)
1427 skinframe = R_SkinFrame_Find("missing", TEXF_PRECACHE, 0, 0, 0, true);
1428 skinframe->stain = NULL;
1429 skinframe->merged = NULL;
1430 skinframe->base = r_texture_notexture;
1431 skinframe->pants = NULL;
1432 skinframe->shirt = NULL;
1433 skinframe->nmap = r_texture_blanknormalmap;
1434 skinframe->gloss = NULL;
1435 skinframe->glow = NULL;
1436 skinframe->fog = NULL;
1441 void gl_main_start(void)
1446 r = (-1.0/256.0) * (FOGMASKTABLEWIDTH * FOGMASKTABLEWIDTH);
1447 for (x = 0;x < FOGMASKTABLEWIDTH;x++)
1449 alpha = 1 - exp(r / ((double)x*(double)x));
1450 if (x == FOGMASKTABLEWIDTH - 1)
1452 r_refdef.fogmasktable[x] = bound(0, alpha, 1);
1455 memset(r_qwskincache, 0, sizeof(r_qwskincache));
1456 memset(r_qwskincache_skinframe, 0, sizeof(r_qwskincache_skinframe));
1458 // set up r_skinframe loading system for textures
1459 memset(&r_skinframe, 0, sizeof(r_skinframe));
1460 r_skinframe.loadsequence = 1;
1461 Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
1463 r_main_texturepool = R_AllocTexturePool();
1464 R_BuildBlankTextures();
1466 if (gl_texturecubemap)
1469 R_BuildNormalizationCube();
1471 R_BuildFogTexture();
1472 memset(&r_bloomstate, 0, sizeof(r_bloomstate));
1473 memset(r_glsl_permutations, 0, sizeof(r_glsl_permutations));
1474 memset(&r_svbsp, 0, sizeof (r_svbsp));
1477 void gl_main_shutdown(void)
1479 memset(r_qwskincache, 0, sizeof(r_qwskincache));
1480 memset(r_qwskincache_skinframe, 0, sizeof(r_qwskincache_skinframe));
1482 // clear out the r_skinframe state
1483 Mem_ExpandableArray_FreeArray(&r_skinframe.array);
1484 memset(&r_skinframe, 0, sizeof(r_skinframe));
1487 Mem_Free(r_svbsp.nodes);
1488 memset(&r_svbsp, 0, sizeof (r_svbsp));
1489 R_FreeTexturePool(&r_main_texturepool);
1490 r_texture_blanknormalmap = NULL;
1491 r_texture_white = NULL;
1492 r_texture_grey128 = NULL;
1493 r_texture_black = NULL;
1494 r_texture_whitecube = NULL;
1495 r_texture_normalizationcube = NULL;
1496 memset(&r_bloomstate, 0, sizeof(r_bloomstate));
1500 extern void CL_ParseEntityLump(char *entitystring);
1501 void gl_main_newmap(void)
1503 // FIXME: move this code to client
1505 char *entities, entname[MAX_QPATH];
1508 strlcpy(entname, cl.worldmodel->name, sizeof(entname));
1509 l = (int)strlen(entname) - 4;
1510 if (l >= 0 && !strcmp(entname + l, ".bsp"))
1512 memcpy(entname + l, ".ent", 5);
1513 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
1515 CL_ParseEntityLump(entities);
1520 if (cl.worldmodel->brush.entities)
1521 CL_ParseEntityLump(cl.worldmodel->brush.entities);
1525 void GL_Main_Init(void)
1527 r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
1529 Cmd_AddCommand("r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
1530 Cmd_AddCommand("r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
1531 // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
1532 if (gamemode == GAME_NEHAHRA)
1534 Cvar_RegisterVariable (&gl_fogenable);
1535 Cvar_RegisterVariable (&gl_fogdensity);
1536 Cvar_RegisterVariable (&gl_fogred);
1537 Cvar_RegisterVariable (&gl_foggreen);
1538 Cvar_RegisterVariable (&gl_fogblue);
1539 Cvar_RegisterVariable (&gl_fogstart);
1540 Cvar_RegisterVariable (&gl_fogend);
1542 Cvar_RegisterVariable(&r_depthfirst);
1543 Cvar_RegisterVariable(&r_nearclip);
1544 Cvar_RegisterVariable(&r_showbboxes);
1545 Cvar_RegisterVariable(&r_showsurfaces);
1546 Cvar_RegisterVariable(&r_showtris);
1547 Cvar_RegisterVariable(&r_shownormals);
1548 Cvar_RegisterVariable(&r_showlighting);
1549 Cvar_RegisterVariable(&r_showshadowvolumes);
1550 Cvar_RegisterVariable(&r_showcollisionbrushes);
1551 Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
1552 Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
1553 Cvar_RegisterVariable(&r_showdisabledepthtest);
1554 Cvar_RegisterVariable(&r_drawportals);
1555 Cvar_RegisterVariable(&r_drawentities);
1556 Cvar_RegisterVariable(&r_cullentities_trace);
1557 Cvar_RegisterVariable(&r_cullentities_trace_samples);
1558 Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
1559 Cvar_RegisterVariable(&r_cullentities_trace_delay);
1560 Cvar_RegisterVariable(&r_drawviewmodel);
1561 Cvar_RegisterVariable(&r_speeds);
1562 Cvar_RegisterVariable(&r_fullbrights);
1563 Cvar_RegisterVariable(&r_wateralpha);
1564 Cvar_RegisterVariable(&r_dynamic);
1565 Cvar_RegisterVariable(&r_fullbright);
1566 Cvar_RegisterVariable(&r_shadows);
1567 Cvar_RegisterVariable(&r_shadows_throwdistance);
1568 Cvar_RegisterVariable(&r_q1bsp_skymasking);
1569 Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
1570 Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
1571 Cvar_RegisterVariable(&r_textureunits);
1572 Cvar_RegisterVariable(&r_glsl);
1573 Cvar_RegisterVariable(&r_glsl_offsetmapping);
1574 Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
1575 Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
1576 Cvar_RegisterVariable(&r_glsl_deluxemapping);
1577 Cvar_RegisterVariable(&r_lerpsprites);
1578 Cvar_RegisterVariable(&r_lerpmodels);
1579 Cvar_RegisterVariable(&r_waterscroll);
1580 Cvar_RegisterVariable(&r_bloom);
1581 Cvar_RegisterVariable(&r_bloom_colorscale);
1582 Cvar_RegisterVariable(&r_bloom_brighten);
1583 Cvar_RegisterVariable(&r_bloom_blur);
1584 Cvar_RegisterVariable(&r_bloom_resolution);
1585 Cvar_RegisterVariable(&r_bloom_colorexponent);
1586 Cvar_RegisterVariable(&r_bloom_colorsubtract);
1587 Cvar_RegisterVariable(&r_hdr);
1588 Cvar_RegisterVariable(&r_hdr_scenebrightness);
1589 Cvar_RegisterVariable(&r_glsl_contrastboost);
1590 Cvar_RegisterVariable(&r_hdr_glowintensity);
1591 Cvar_RegisterVariable(&r_hdr_range);
1592 Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
1593 Cvar_RegisterVariable(&developer_texturelogging);
1594 Cvar_RegisterVariable(&gl_lightmaps);
1595 Cvar_RegisterVariable(&r_test);
1596 Cvar_RegisterVariable(&r_batchmode);
1597 if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
1598 Cvar_SetValue("r_fullbrights", 0);
1599 R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap);
1602 extern void R_Textures_Init(void);
1603 extern void GL_Draw_Init(void);
1604 extern void GL_Main_Init(void);
1605 extern void R_Shadow_Init(void);
1606 extern void R_Sky_Init(void);
1607 extern void GL_Surf_Init(void);
1608 extern void R_Light_Init(void);
1609 extern void R_Particles_Init(void);
1610 extern void R_Explosion_Init(void);
1611 extern void gl_backend_init(void);
1612 extern void Sbar_Init(void);
1613 extern void R_LightningBeams_Init(void);
1614 extern void Mod_RenderInit(void);
1616 void Render_Init(void)
1629 R_LightningBeams_Init();
1638 extern char *ENGINE_EXTENSIONS;
1641 VID_CheckExtensions();
1643 // LordHavoc: report supported extensions
1644 Con_DPrintf("\nQuakeC extensions for server and client: %s\nQuakeC extensions for menu: %s\n", vm_sv_extensions, vm_m_extensions );
1646 // clear to black (loading plaque will be seen over this)
1648 qglClearColor(0,0,0,1);CHECKGLERROR
1649 qglClear(GL_COLOR_BUFFER_BIT);CHECKGLERROR
1652 int R_CullBox(const vec3_t mins, const vec3_t maxs)
1656 for (i = 0;i < 4;i++)
1658 p = r_view.frustum + i;
1663 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
1667 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
1671 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
1675 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
1679 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
1683 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
1687 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
1691 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
1699 int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
1703 for (i = 0;i < numplanes;i++)
1710 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
1714 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
1718 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
1722 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
1726 if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
1730 if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
1734 if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
1738 if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
1746 //==================================================================================
1748 static void R_UpdateEntityLighting(entity_render_t *ent)
1750 vec3_t tempdiffusenormal;
1752 // fetch the lighting from the worldmodel data
1753 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));
1754 VectorClear(ent->modellight_diffuse);
1755 VectorClear(tempdiffusenormal);
1756 if ((ent->flags & RENDER_LIGHT) && r_refdef.worldmodel && r_refdef.worldmodel->brush.LightPoint)
1759 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
1760 r_refdef.worldmodel->brush.LightPoint(r_refdef.worldmodel, org, ent->modellight_ambient, ent->modellight_diffuse, tempdiffusenormal);
1763 VectorSet(ent->modellight_ambient, 1, 1, 1);
1765 // move the light direction into modelspace coordinates for lighting code
1766 Matrix4x4_Transform3x3(&ent->inversematrix, tempdiffusenormal, ent->modellight_lightdir);
1767 if(VectorLength2(ent->modellight_lightdir) > 0)
1769 VectorNormalize(ent->modellight_lightdir);
1773 VectorSet(ent->modellight_lightdir, 0, 0, 1); // have to set SOME valid vector here
1776 // scale ambient and directional light contributions according to rendering variables
1777 ent->modellight_ambient[0] *= ent->colormod[0] * r_refdef.lightmapintensity;
1778 ent->modellight_ambient[1] *= ent->colormod[1] * r_refdef.lightmapintensity;
1779 ent->modellight_ambient[2] *= ent->colormod[2] * r_refdef.lightmapintensity;
1780 ent->modellight_diffuse[0] *= ent->colormod[0] * r_refdef.lightmapintensity;
1781 ent->modellight_diffuse[1] *= ent->colormod[1] * r_refdef.lightmapintensity;
1782 ent->modellight_diffuse[2] *= ent->colormod[2] * r_refdef.lightmapintensity;
1785 static void R_View_UpdateEntityVisible (void)
1788 entity_render_t *ent;
1790 if (!r_drawentities.integer)
1793 renderimask = r_refdef.envmap ? (RENDER_EXTERIORMODEL | RENDER_VIEWMODEL) : (chase_active.integer ? 0 : RENDER_EXTERIORMODEL);
1794 if (r_refdef.worldmodel && r_refdef.worldmodel->brush.BoxTouchingVisibleLeafs)
1796 // worldmodel can check visibility
1797 for (i = 0;i < r_refdef.numentities;i++)
1799 ent = r_refdef.entities[i];
1800 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));
1802 if(r_cullentities_trace.integer)
1804 for (i = 0;i < r_refdef.numentities;i++)
1806 ent = r_refdef.entities[i];
1807 if(r_viewcache.entityvisible[i] && !(ent->effects & EF_NODEPTHTEST) && !(ent->flags & RENDER_VIEWMODEL) && !(ent->model && (ent->model->name[0] == '*')))
1809 if(Mod_CanSeeBox_Trace(r_cullentities_trace_samples.integer, r_cullentities_trace_enlarge.value, r_refdef.worldmodel, r_view.origin, ent->mins, ent->maxs))
1810 ent->last_trace_visibility = realtime;
1811 if(ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
1812 r_viewcache.entityvisible[i] = 0;
1819 // no worldmodel or it can't check visibility
1820 for (i = 0;i < r_refdef.numentities;i++)
1822 ent = r_refdef.entities[i];
1823 r_viewcache.entityvisible[i] = !(ent->flags & renderimask) && !R_CullBox(ent->mins, ent->maxs);
1827 // update entity lighting (even on hidden entities for r_shadows)
1828 for (i = 0;i < r_refdef.numentities;i++)
1829 R_UpdateEntityLighting(r_refdef.entities[i]);
1832 // only used if skyrendermasked, and normally returns false
1833 int R_DrawBrushModelsSky (void)
1836 entity_render_t *ent;
1838 if (!r_drawentities.integer)
1842 for (i = 0;i < r_refdef.numentities;i++)
1844 if (!r_viewcache.entityvisible[i])
1846 ent = r_refdef.entities[i];
1847 if (!ent->model || !ent->model->DrawSky)
1849 ent->model->DrawSky(ent);
1855 void R_DrawNoModel(entity_render_t *ent);
1856 void R_DrawModels(void)
1859 entity_render_t *ent;
1861 if (!r_drawentities.integer)
1864 for (i = 0;i < r_refdef.numentities;i++)
1866 if (!r_viewcache.entityvisible[i])
1868 ent = r_refdef.entities[i];
1869 r_refdef.stats.entities++;
1870 if (ent->model && ent->model->Draw != NULL)
1871 ent->model->Draw(ent);
1877 void R_DrawModelsDepth(void)
1880 entity_render_t *ent;
1882 if (!r_drawentities.integer)
1885 for (i = 0;i < r_refdef.numentities;i++)
1887 if (!r_viewcache.entityvisible[i])
1889 ent = r_refdef.entities[i];
1890 r_refdef.stats.entities++;
1891 if (ent->model && ent->model->DrawDepth != NULL)
1892 ent->model->DrawDepth(ent);
1896 static void R_View_SetFrustum(void)
1898 double slopex, slopey;
1900 // break apart the view matrix into vectors for various purposes
1901 Matrix4x4_ToVectors(&r_view.matrix, r_view.forward, r_view.left, r_view.up, r_view.origin);
1902 VectorNegate(r_view.left, r_view.right);
1905 r_view.frustum[0].normal[0] = 0 - 1.0 / r_view.frustum_x;
1906 r_view.frustum[0].normal[1] = 0 - 0;
1907 r_view.frustum[0].normal[2] = -1 - 0;
1908 r_view.frustum[1].normal[0] = 0 + 1.0 / r_view.frustum_x;
1909 r_view.frustum[1].normal[1] = 0 + 0;
1910 r_view.frustum[1].normal[2] = -1 + 0;
1911 r_view.frustum[2].normal[0] = 0 - 0;
1912 r_view.frustum[2].normal[1] = 0 - 1.0 / r_view.frustum_y;
1913 r_view.frustum[2].normal[2] = -1 - 0;
1914 r_view.frustum[3].normal[0] = 0 + 0;
1915 r_view.frustum[3].normal[1] = 0 + 1.0 / r_view.frustum_y;
1916 r_view.frustum[3].normal[2] = -1 + 0;
1920 zNear = r_refdef.nearclip;
1921 nudge = 1.0 - 1.0 / (1<<23);
1922 r_view.frustum[4].normal[0] = 0 - 0;
1923 r_view.frustum[4].normal[1] = 0 - 0;
1924 r_view.frustum[4].normal[2] = -1 - -nudge;
1925 r_view.frustum[4].dist = 0 - -2 * zNear * nudge;
1926 r_view.frustum[5].normal[0] = 0 + 0;
1927 r_view.frustum[5].normal[1] = 0 + 0;
1928 r_view.frustum[5].normal[2] = -1 + -nudge;
1929 r_view.frustum[5].dist = 0 + -2 * zNear * nudge;
1935 r_view.frustum[0].normal[0] = m[3] - m[0];
1936 r_view.frustum[0].normal[1] = m[7] - m[4];
1937 r_view.frustum[0].normal[2] = m[11] - m[8];
1938 r_view.frustum[0].dist = m[15] - m[12];
1940 r_view.frustum[1].normal[0] = m[3] + m[0];
1941 r_view.frustum[1].normal[1] = m[7] + m[4];
1942 r_view.frustum[1].normal[2] = m[11] + m[8];
1943 r_view.frustum[1].dist = m[15] + m[12];
1945 r_view.frustum[2].normal[0] = m[3] - m[1];
1946 r_view.frustum[2].normal[1] = m[7] - m[5];
1947 r_view.frustum[2].normal[2] = m[11] - m[9];
1948 r_view.frustum[2].dist = m[15] - m[13];
1950 r_view.frustum[3].normal[0] = m[3] + m[1];
1951 r_view.frustum[3].normal[1] = m[7] + m[5];
1952 r_view.frustum[3].normal[2] = m[11] + m[9];
1953 r_view.frustum[3].dist = m[15] + m[13];
1955 r_view.frustum[4].normal[0] = m[3] - m[2];
1956 r_view.frustum[4].normal[1] = m[7] - m[6];
1957 r_view.frustum[4].normal[2] = m[11] - m[10];
1958 r_view.frustum[4].dist = m[15] - m[14];
1960 r_view.frustum[5].normal[0] = m[3] + m[2];
1961 r_view.frustum[5].normal[1] = m[7] + m[6];
1962 r_view.frustum[5].normal[2] = m[11] + m[10];
1963 r_view.frustum[5].dist = m[15] + m[14];
1968 if (r_view.useperspective)
1970 slopex = 1.0 / r_view.frustum_x;
1971 slopey = 1.0 / r_view.frustum_y;
1972 VectorMA(r_view.forward, -slopex, r_view.left, r_view.frustum[0].normal);
1973 VectorMA(r_view.forward, slopex, r_view.left, r_view.frustum[1].normal);
1974 VectorMA(r_view.forward, -slopey, r_view.up , r_view.frustum[2].normal);
1975 VectorMA(r_view.forward, slopey, r_view.up , r_view.frustum[3].normal);
1976 VectorCopy(r_view.forward, r_view.frustum[4].normal);
1978 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
1979 VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, -1024 * slopex, r_view.left, -1024 * slopey, r_view.up, r_view.frustumcorner[0]);
1980 VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, 1024 * slopex, r_view.left, -1024 * slopey, r_view.up, r_view.frustumcorner[1]);
1981 VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, -1024 * slopex, r_view.left, 1024 * slopey, r_view.up, r_view.frustumcorner[2]);
1982 VectorMAMAMAM(1, r_view.origin, 1024, r_view.forward, 1024 * slopex, r_view.left, 1024 * slopey, r_view.up, r_view.frustumcorner[3]);
1984 r_view.frustum[0].dist = DotProduct (r_view.origin, r_view.frustum[0].normal);
1985 r_view.frustum[1].dist = DotProduct (r_view.origin, r_view.frustum[1].normal);
1986 r_view.frustum[2].dist = DotProduct (r_view.origin, r_view.frustum[2].normal);
1987 r_view.frustum[3].dist = DotProduct (r_view.origin, r_view.frustum[3].normal);
1988 r_view.frustum[4].dist = DotProduct (r_view.origin, r_view.frustum[4].normal) + r_refdef.nearclip;
1992 VectorScale(r_view.left, -r_view.ortho_x, r_view.frustum[0].normal);
1993 VectorScale(r_view.left, r_view.ortho_x, r_view.frustum[1].normal);
1994 VectorScale(r_view.up, -r_view.ortho_y, r_view.frustum[2].normal);
1995 VectorScale(r_view.up, r_view.ortho_y, r_view.frustum[3].normal);
1996 VectorCopy(r_view.forward, r_view.frustum[4].normal);
1997 r_view.frustum[0].dist = DotProduct (r_view.origin, r_view.frustum[0].normal) + r_view.ortho_x;
1998 r_view.frustum[1].dist = DotProduct (r_view.origin, r_view.frustum[1].normal) + r_view.ortho_x;
1999 r_view.frustum[2].dist = DotProduct (r_view.origin, r_view.frustum[2].normal) + r_view.ortho_y;
2000 r_view.frustum[3].dist = DotProduct (r_view.origin, r_view.frustum[3].normal) + r_view.ortho_y;
2001 r_view.frustum[4].dist = DotProduct (r_view.origin, r_view.frustum[4].normal) + r_refdef.nearclip;
2004 PlaneClassify(&r_view.frustum[0]);
2005 PlaneClassify(&r_view.frustum[1]);
2006 PlaneClassify(&r_view.frustum[2]);
2007 PlaneClassify(&r_view.frustum[3]);
2008 PlaneClassify(&r_view.frustum[4]);
2010 // LordHavoc: note to all quake engine coders, Quake had a special case
2011 // for 90 degrees which assumed a square view (wrong), so I removed it,
2012 // Quake2 has it disabled as well.
2014 // rotate R_VIEWFORWARD right by FOV_X/2 degrees
2015 //RotatePointAroundVector( r_view.frustum[0].normal, r_view.up, r_view.forward, -(90 - r_refdef.fov_x / 2));
2016 //r_view.frustum[0].dist = DotProduct (r_view.origin, frustum[0].normal);
2017 //PlaneClassify(&frustum[0]);
2019 // rotate R_VIEWFORWARD left by FOV_X/2 degrees
2020 //RotatePointAroundVector( r_view.frustum[1].normal, r_view.up, r_view.forward, (90 - r_refdef.fov_x / 2));
2021 //r_view.frustum[1].dist = DotProduct (r_view.origin, frustum[1].normal);
2022 //PlaneClassify(&frustum[1]);
2024 // rotate R_VIEWFORWARD up by FOV_X/2 degrees
2025 //RotatePointAroundVector( r_view.frustum[2].normal, r_view.left, r_view.forward, -(90 - r_refdef.fov_y / 2));
2026 //r_view.frustum[2].dist = DotProduct (r_view.origin, frustum[2].normal);
2027 //PlaneClassify(&frustum[2]);
2029 // rotate R_VIEWFORWARD down by FOV_X/2 degrees
2030 //RotatePointAroundVector( r_view.frustum[3].normal, r_view.left, r_view.forward, (90 - r_refdef.fov_y / 2));
2031 //r_view.frustum[3].dist = DotProduct (r_view.origin, frustum[3].normal);
2032 //PlaneClassify(&frustum[3]);
2035 //VectorCopy(r_view.forward, r_view.frustum[4].normal);
2036 //r_view.frustum[4].dist = DotProduct (r_view.origin, frustum[4].normal) + r_nearclip.value;
2037 //PlaneClassify(&frustum[4]);
2040 void R_View_Update(void)
2042 R_View_SetFrustum();
2043 R_View_WorldVisibility();
2044 R_View_UpdateEntityVisible();
2047 void R_SetupView(const matrix4x4_t *matrix)
2049 if (!r_view.useperspective)
2050 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);
2051 else if (r_refdef.rtworldshadows || r_refdef.rtdlightshadows)
2052 GL_SetupView_Mode_PerspectiveInfiniteFarClip(r_view.frustum_x, r_view.frustum_y, r_refdef.nearclip);
2054 GL_SetupView_Mode_Perspective(r_view.frustum_x, r_view.frustum_y, r_refdef.nearclip, r_refdef.farclip);
2056 GL_SetupView_Orientation_FromEntity(matrix);
2059 void R_ResetViewRendering2D(void)
2061 if (gl_support_fragment_shader)
2063 qglUseProgramObjectARB(0);CHECKGLERROR
2068 // GL is weird because it's bottom to top, r_view.y is top to bottom
2069 qglViewport(r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
2070 GL_SetupView_Mode_Ortho(0, 0, 1, 1, -10, 100);
2071 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2072 GL_Color(1, 1, 1, 1);
2073 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2074 GL_BlendFunc(GL_ONE, GL_ZERO);
2075 GL_AlphaTest(false);
2076 GL_ScissorTest(false);
2077 GL_DepthMask(false);
2078 GL_DepthRange(0, 1);
2079 GL_DepthTest(false);
2080 R_Mesh_Matrix(&identitymatrix);
2081 R_Mesh_ResetTextureState();
2082 GL_PolygonOffset(0, 0);
2083 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
2084 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2085 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
2086 qglStencilMask(~0);CHECKGLERROR
2087 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
2088 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
2089 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
2092 void R_ResetViewRendering3D(void)
2094 if (gl_support_fragment_shader)
2096 qglUseProgramObjectARB(0);CHECKGLERROR
2101 // GL is weird because it's bottom to top, r_view.y is top to bottom
2102 qglViewport(r_view.x, vid.height - (r_view.y + r_view.height), r_view.width, r_view.height);CHECKGLERROR
2103 R_SetupView(&r_view.matrix);
2104 GL_Scissor(r_view.x, r_view.y, r_view.width, r_view.height);
2105 GL_Color(1, 1, 1, 1);
2106 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
2107 GL_BlendFunc(GL_ONE, GL_ZERO);
2108 GL_AlphaTest(false);
2109 GL_ScissorTest(true);
2111 GL_DepthRange(0, 1);
2113 R_Mesh_Matrix(&identitymatrix);
2114 R_Mesh_ResetTextureState();
2115 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
2116 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
2117 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
2118 qglDisable(GL_STENCIL_TEST);CHECKGLERROR
2119 qglStencilMask(~0);CHECKGLERROR
2120 qglStencilFunc(GL_ALWAYS, 128, ~0);CHECKGLERROR
2121 qglStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);CHECKGLERROR
2122 GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces
2126 R_Bloom_SetupShader(
2128 "// written by Forest 'LordHavoc' Hale\n"
2130 "// common definitions between vertex shader and fragment shader:\n"
2132 "#ifdef __GLSL_CG_DATA_TYPES\n"
2133 "#define myhalf half\n"
2134 "#define myhvec2 hvec2\n"
2135 "#define myhvec3 hvec3\n"
2136 "#define myhvec4 hvec4\n"
2138 "#define myhalf float\n"
2139 "#define myhvec2 vec2\n"
2140 "#define myhvec3 vec3\n"
2141 "#define myhvec4 vec4\n"
2144 "varying vec2 ScreenTexCoord;\n"
2145 "varying vec2 BloomTexCoord;\n"
2150 "// vertex shader specific:\n"
2151 "#ifdef VERTEX_SHADER\n"
2155 " ScreenTexCoord = vec2(gl_MultiTexCoord0);\n"
2156 " BloomTexCoord = vec2(gl_MultiTexCoord1);\n"
2157 " // transform vertex to camera space, using ftransform to match non-VS\n"
2159 " gl_Position = ftransform();\n"
2162 "#endif // VERTEX_SHADER\n"
2167 "// fragment shader specific:\n"
2168 "#ifdef FRAGMENT_SHADER\n"
2173 " myhvec3 color = myhvec3(texture2D(Texture_Screen, ScreenTexCoord));\n"
2174 " for (x = -BLUR_X;x <= BLUR_X;x++)
2175 " color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
2176 " color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
2177 " color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
2178 " color.rgb += myhvec3(texture2D(Texture_Bloom, BloomTexCoord));\n"
2180 " gl_FragColor = vec4(color);\n"
2183 "#endif // FRAGMENT_SHADER\n"
2186 void R_RenderScene(void);
2188 void R_Bloom_StartFrame(void)
2190 int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight;
2192 // set bloomwidth and bloomheight to the bloom resolution that will be
2193 // used (often less than the screen resolution for faster rendering)
2194 r_bloomstate.bloomwidth = bound(1, r_bloom_resolution.integer, r_view.width);
2195 r_bloomstate.bloomheight = r_bloomstate.bloomwidth * r_view.height / r_view.width;
2196 r_bloomstate.bloomheight = bound(1, r_bloomstate.bloomheight, r_view.height);
2198 // calculate desired texture sizes
2199 if (gl_support_arb_texture_non_power_of_two)
2201 screentexturewidth = r_view.width;
2202 screentextureheight = r_view.height;
2203 bloomtexturewidth = r_bloomstate.bloomwidth;
2204 bloomtextureheight = r_bloomstate.bloomheight;
2208 for (screentexturewidth = 1;screentexturewidth < vid.width ;screentexturewidth *= 2);
2209 for (screentextureheight = 1;screentextureheight < vid.height ;screentextureheight *= 2);
2210 for (bloomtexturewidth = 1;bloomtexturewidth < r_bloomstate.bloomwidth ;bloomtexturewidth *= 2);
2211 for (bloomtextureheight = 1;bloomtextureheight < r_bloomstate.bloomheight;bloomtextureheight *= 2);
2216 screentexturewidth = screentextureheight = 0;
2218 else if (r_bloom.integer)
2223 screentexturewidth = screentextureheight = 0;
2224 bloomtexturewidth = bloomtextureheight = 0;
2227 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)
2229 // can't use bloom if the parameters are too weird
2230 // can't use bloom if the card does not support the texture size
2231 if (r_bloomstate.texture_screen)
2232 R_FreeTexture(r_bloomstate.texture_screen);
2233 if (r_bloomstate.texture_bloom)
2234 R_FreeTexture(r_bloomstate.texture_bloom);
2235 memset(&r_bloomstate, 0, sizeof(r_bloomstate));
2239 r_bloomstate.enabled = true;
2240 r_bloomstate.hdr = r_hdr.integer != 0;
2242 // allocate textures as needed
2243 if (r_bloomstate.screentexturewidth != screentexturewidth || r_bloomstate.screentextureheight != screentextureheight)
2245 if (r_bloomstate.texture_screen)
2246 R_FreeTexture(r_bloomstate.texture_screen);
2247 r_bloomstate.texture_screen = NULL;
2248 r_bloomstate.screentexturewidth = screentexturewidth;
2249 r_bloomstate.screentextureheight = screentextureheight;
2250 if (r_bloomstate.screentexturewidth && r_bloomstate.screentextureheight)
2251 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);
2253 if (r_bloomstate.bloomtexturewidth != bloomtexturewidth || r_bloomstate.bloomtextureheight != bloomtextureheight)
2255 if (r_bloomstate.texture_bloom)
2256 R_FreeTexture(r_bloomstate.texture_bloom);
2257 r_bloomstate.texture_bloom = NULL;
2258 r_bloomstate.bloomtexturewidth = bloomtexturewidth;
2259 r_bloomstate.bloomtextureheight = bloomtextureheight;
2260 if (r_bloomstate.bloomtexturewidth && r_bloomstate.bloomtextureheight)
2261 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);
2264 // set up a texcoord array for the full resolution screen image
2265 // (we have to keep this around to copy back during final render)
2266 r_bloomstate.screentexcoord2f[0] = 0;
2267 r_bloomstate.screentexcoord2f[1] = (float)r_view.height / (float)r_bloomstate.screentextureheight;
2268 r_bloomstate.screentexcoord2f[2] = (float)r_view.width / (float)r_bloomstate.screentexturewidth;
2269 r_bloomstate.screentexcoord2f[3] = (float)r_view.height / (float)r_bloomstate.screentextureheight;
2270 r_bloomstate.screentexcoord2f[4] = (float)r_view.width / (float)r_bloomstate.screentexturewidth;
2271 r_bloomstate.screentexcoord2f[5] = 0;
2272 r_bloomstate.screentexcoord2f[6] = 0;
2273 r_bloomstate.screentexcoord2f[7] = 0;
2275 // set up a texcoord array for the reduced resolution bloom image
2276 // (which will be additive blended over the screen image)
2277 r_bloomstate.bloomtexcoord2f[0] = 0;
2278 r_bloomstate.bloomtexcoord2f[1] = (float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
2279 r_bloomstate.bloomtexcoord2f[2] = (float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
2280 r_bloomstate.bloomtexcoord2f[3] = (float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
2281 r_bloomstate.bloomtexcoord2f[4] = (float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
2282 r_bloomstate.bloomtexcoord2f[5] = 0;
2283 r_bloomstate.bloomtexcoord2f[6] = 0;
2284 r_bloomstate.bloomtexcoord2f[7] = 0;
2287 void R_Bloom_CopyScreenTexture(float colorscale)
2289 r_refdef.stats.bloom++;
2291 R_ResetViewRendering2D();
2292 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
2293 R_Mesh_ColorPointer(NULL, 0, 0);
2294 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
2295 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
2297 // copy view into the screen texture
2298 GL_ActiveTexture(0);
2300 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
2301 r_refdef.stats.bloom_copypixels += r_view.width * r_view.height;
2303 // now scale it down to the bloom texture size
2305 qglViewport(r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
2306 GL_BlendFunc(GL_ONE, GL_ZERO);
2307 GL_Color(colorscale, colorscale, colorscale, 1);
2308 // TODO: optimize with multitexture or GLSL
2309 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2310 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2312 // we now have a bloom image in the framebuffer
2313 // copy it into the bloom image texture for later processing
2314 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2315 GL_ActiveTexture(0);
2317 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
2318 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2321 void R_Bloom_CopyHDRTexture(void)
2323 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2324 GL_ActiveTexture(0);
2326 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
2327 r_refdef.stats.bloom_copypixels += r_view.width * r_view.height;
2330 void R_Bloom_MakeTexture(void)
2333 float xoffset, yoffset, r, brighten;
2335 r_refdef.stats.bloom++;
2337 R_ResetViewRendering2D();
2338 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
2339 R_Mesh_ColorPointer(NULL, 0, 0);
2341 // we have a bloom image in the framebuffer
2343 qglViewport(r_view.x, vid.height - (r_view.y + r_bloomstate.bloomheight), r_bloomstate.bloomwidth, r_bloomstate.bloomheight);CHECKGLERROR
2345 for (x = 1;x < r_bloom_colorexponent.value;)
2348 r = bound(0, r_bloom_colorexponent.value / x, 1);
2349 GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
2350 GL_Color(r, r, r, 1);
2351 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2352 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
2353 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2354 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2356 // copy the vertically blurred bloom view to a texture
2357 GL_ActiveTexture(0);
2359 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
2360 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2363 range = r_bloom_blur.integer * r_bloomstate.bloomwidth / 320;
2364 brighten = r_bloom_brighten.value;
2366 brighten *= r_hdr_range.value;
2367 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2368 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.offsettexcoord2f, 0, 0);
2370 for (dir = 0;dir < 2;dir++)
2372 // blend on at multiple vertical offsets to achieve a vertical blur
2373 // TODO: do offset blends using GLSL
2374 GL_BlendFunc(GL_ONE, GL_ZERO);
2375 for (x = -range;x <= range;x++)
2377 if (!dir){xoffset = 0;yoffset = x;}
2378 else {xoffset = x;yoffset = 0;}
2379 xoffset /= (float)r_bloomstate.bloomtexturewidth;
2380 yoffset /= (float)r_bloomstate.bloomtextureheight;
2381 // compute a texcoord array with the specified x and y offset
2382 r_bloomstate.offsettexcoord2f[0] = xoffset+0;
2383 r_bloomstate.offsettexcoord2f[1] = yoffset+(float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
2384 r_bloomstate.offsettexcoord2f[2] = xoffset+(float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
2385 r_bloomstate.offsettexcoord2f[3] = yoffset+(float)r_bloomstate.bloomheight / (float)r_bloomstate.bloomtextureheight;
2386 r_bloomstate.offsettexcoord2f[4] = xoffset+(float)r_bloomstate.bloomwidth / (float)r_bloomstate.bloomtexturewidth;
2387 r_bloomstate.offsettexcoord2f[5] = yoffset+0;
2388 r_bloomstate.offsettexcoord2f[6] = xoffset+0;
2389 r_bloomstate.offsettexcoord2f[7] = yoffset+0;
2390 // this r value looks like a 'dot' particle, fading sharply to
2391 // black at the edges
2392 // (probably not realistic but looks good enough)
2393 //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
2394 //r = (dir ? 1.0f : brighten)/(range*2+1);
2395 r = (dir ? 1.0f : brighten)/(range*2+1)*(1 - x*x/(float)(range*range));
2396 GL_Color(r, r, r, 1);
2397 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2398 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2399 GL_BlendFunc(GL_ONE, GL_ONE);
2402 // copy the vertically blurred bloom view to a texture
2403 GL_ActiveTexture(0);
2405 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
2406 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2409 // apply subtract last
2410 // (just like it would be in a GLSL shader)
2411 if (r_bloom_colorsubtract.value > 0 && gl_support_ext_blend_subtract)
2413 GL_BlendFunc(GL_ONE, GL_ZERO);
2414 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2415 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
2416 GL_Color(1, 1, 1, 1);
2417 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2418 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2420 GL_BlendFunc(GL_ONE, GL_ONE);
2421 qglBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT);
2422 R_Mesh_TexBind(0, R_GetTexture(r_texture_white));
2423 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
2424 GL_Color(r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, 1);
2425 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2426 r_refdef.stats.bloom_drawpixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2427 qglBlendEquationEXT(GL_FUNC_ADD_EXT);
2429 // copy the darkened bloom view to a texture
2430 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2431 GL_ActiveTexture(0);
2433 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
2434 r_refdef.stats.bloom_copypixels += r_bloomstate.bloomwidth * r_bloomstate.bloomheight;
2438 void R_HDR_RenderBloomTexture(void)
2440 int oldwidth, oldheight;
2442 oldwidth = r_view.width;
2443 oldheight = r_view.height;
2444 r_view.width = r_bloomstate.bloomwidth;
2445 r_view.height = r_bloomstate.bloomheight;
2447 // TODO: support GL_EXT_framebuffer_object rather than reusing the framebuffer? it might improve SLI performance.
2448 // TODO: add exposure compensation features
2449 // TODO: add fp16 framebuffer support
2451 r_view.colorscale = r_bloom_colorscale.value * r_hdr_scenebrightness.value;
2453 r_view.colorscale /= r_hdr_range.value;
2456 R_ResetViewRendering2D();
2458 R_Bloom_CopyHDRTexture();
2459 R_Bloom_MakeTexture();
2461 R_ResetViewRendering3D();
2464 if (r_timereport_active)
2465 R_TimeReport("clear");
2468 // restore the view settings
2469 r_view.width = oldwidth;
2470 r_view.height = oldheight;
2473 static void R_BlendView(void)
2475 if (r_bloomstate.enabled && r_bloomstate.hdr)
2477 // render high dynamic range bloom effect
2478 // the bloom texture was made earlier this render, so we just need to
2479 // blend it onto the screen...
2480 R_ResetViewRendering2D();
2481 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
2482 R_Mesh_ColorPointer(NULL, 0, 0);
2483 GL_Color(1, 1, 1, 1);
2484 GL_BlendFunc(GL_ONE, GL_ONE);
2485 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2486 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
2487 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2488 r_refdef.stats.bloom_drawpixels += r_view.width * r_view.height;
2490 else if (r_bloomstate.enabled)
2492 // render simple bloom effect
2493 // copy the screen and shrink it and darken it for the bloom process
2494 R_Bloom_CopyScreenTexture(r_bloom_colorscale.value);
2495 // make the bloom texture
2496 R_Bloom_MakeTexture();
2497 // put the original screen image back in place and blend the bloom
2499 R_ResetViewRendering2D();
2500 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
2501 R_Mesh_ColorPointer(NULL, 0, 0);
2502 GL_Color(1, 1, 1, 1);
2503 GL_BlendFunc(GL_ONE, GL_ZERO);
2504 // do both in one pass if possible
2505 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_bloom));
2506 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.bloomtexcoord2f, 0, 0);
2507 if (r_textureunits.integer >= 2 && gl_combine.integer)
2509 R_Mesh_TexCombine(1, GL_ADD, GL_ADD, 1, 1);
2510 R_Mesh_TexBind(1, R_GetTexture(r_bloomstate.texture_screen));
2511 R_Mesh_TexCoordPointer(1, 2, r_bloomstate.screentexcoord2f, 0, 0);
2515 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2516 r_refdef.stats.bloom_drawpixels += r_view.width * r_view.height;
2517 // now blend on the bloom texture
2518 GL_BlendFunc(GL_ONE, GL_ONE);
2519 R_Mesh_TexBind(0, R_GetTexture(r_bloomstate.texture_screen));
2520 R_Mesh_TexCoordPointer(0, 2, r_bloomstate.screentexcoord2f, 0, 0);
2522 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2523 r_refdef.stats.bloom_drawpixels += r_view.width * r_view.height;
2525 if (r_refdef.viewblend[3] >= (1.0f / 256.0f))
2527 // apply a color tint to the whole view
2528 R_ResetViewRendering2D();
2529 R_Mesh_VertexPointer(r_screenvertex3f, 0, 0);
2530 R_Mesh_ColorPointer(NULL, 0, 0);
2531 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2532 GL_Color(r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
2533 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
2537 void R_RenderScene(void);
2539 matrix4x4_t r_waterscrollmatrix;
2541 void R_UpdateVariables(void)
2545 r_refdef.farclip = 4096;
2546 if (r_refdef.worldmodel)
2547 r_refdef.farclip += VectorDistance(r_refdef.worldmodel->normalmins, r_refdef.worldmodel->normalmaxs);
2548 r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
2550 if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
2551 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
2552 r_refdef.polygonfactor = 0;
2553 r_refdef.polygonoffset = 0;
2554 r_refdef.shadowpolygonfactor = r_refdef.polygonfactor + r_shadow_polygonfactor.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
2555 r_refdef.shadowpolygonoffset = r_refdef.polygonoffset + r_shadow_polygonoffset.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
2557 r_refdef.rtworld = r_shadow_realtime_world.integer;
2558 r_refdef.rtworldshadows = r_shadow_realtime_world_shadows.integer && gl_stencil;
2559 r_refdef.rtdlight = (r_shadow_realtime_world.integer || r_shadow_realtime_dlight.integer) && !gl_flashblend.integer && r_dynamic.integer;
2560 r_refdef.rtdlightshadows = r_refdef.rtdlight && r_shadow_realtime_dlight_shadows.integer && gl_stencil;
2561 r_refdef.lightmapintensity = r_refdef.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
2562 if (r_showsurfaces.integer)
2564 r_refdef.rtworld = false;
2565 r_refdef.rtworldshadows = false;
2566 r_refdef.rtdlight = false;
2567 r_refdef.rtdlightshadows = false;
2568 r_refdef.lightmapintensity = 0;
2571 if (gamemode == GAME_NEHAHRA)
2573 if (gl_fogenable.integer)
2575 r_refdef.oldgl_fogenable = true;
2576 r_refdef.fog_density = gl_fogdensity.value;
2577 r_refdef.fog_red = gl_fogred.value;
2578 r_refdef.fog_green = gl_foggreen.value;
2579 r_refdef.fog_blue = gl_fogblue.value;
2581 else if (r_refdef.oldgl_fogenable)
2583 r_refdef.oldgl_fogenable = false;
2584 r_refdef.fog_density = 0;
2585 r_refdef.fog_red = 0;
2586 r_refdef.fog_green = 0;
2587 r_refdef.fog_blue = 0;
2590 if (r_refdef.fog_density)
2592 r_refdef.fogcolor[0] = bound(0.0f, r_refdef.fog_red , 1.0f);
2593 r_refdef.fogcolor[1] = bound(0.0f, r_refdef.fog_green, 1.0f);
2594 r_refdef.fogcolor[2] = bound(0.0f, r_refdef.fog_blue , 1.0f);
2596 if (r_refdef.fog_density)
2598 r_refdef.fogenabled = true;
2599 // this is the point where the fog reaches 0.9986 alpha, which we
2600 // consider a good enough cutoff point for the texture
2601 // (0.9986 * 256 == 255.6)
2602 r_refdef.fogrange = 400 / r_refdef.fog_density;
2603 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
2604 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
2605 // fog color was already set
2608 r_refdef.fogenabled = false;
2616 void R_RenderView(void)
2618 if (!r_refdef.entities/* || !r_refdef.worldmodel*/)
2619 return; //Host_Error ("R_RenderView: NULL worldmodel");
2621 R_Shadow_UpdateWorldLightSelection();
2624 if (r_timereport_active)
2625 R_TimeReport("setup");
2628 if (r_timereport_active)
2629 R_TimeReport("visibility");
2631 R_ResetViewRendering3D();
2634 if (r_timereport_active)
2635 R_TimeReport("clear");
2637 R_Bloom_StartFrame();
2639 // this produces a bloom texture to be used in R_BlendView() later
2641 R_HDR_RenderBloomTexture();
2643 r_view.colorscale = r_hdr_scenebrightness.value;
2647 if (r_timereport_active)
2648 R_TimeReport("blendview");
2650 GL_Scissor(0, 0, vid.width, vid.height);
2651 GL_ScissorTest(false);
2655 extern void R_DrawLightningBeams (void);
2656 extern void VM_CL_AddPolygonsToMeshQueue (void);
2657 extern void R_DrawPortals (void);
2658 extern cvar_t cl_locs_show;
2659 static void R_DrawLocs(void);
2660 static void R_DrawEntityBBoxes(void);
2661 void R_RenderScene(void)
2663 // don't let sound skip if going slow
2664 if (r_refdef.extraupdate)
2667 R_ResetViewRendering3D();
2669 R_MeshQueue_BeginScene();
2673 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);
2675 if (cl.csqc_vidvars.drawworld)
2677 // don't let sound skip if going slow
2678 if (r_refdef.extraupdate)
2681 if (r_refdef.worldmodel && r_refdef.worldmodel->DrawSky)
2683 r_refdef.worldmodel->DrawSky(r_refdef.worldentity);
2684 if (r_timereport_active)
2685 R_TimeReport("worldsky");
2688 if (R_DrawBrushModelsSky() && r_timereport_active)
2689 R_TimeReport("bmodelsky");
2692 if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.worldmodel && r_refdef.worldmodel->DrawDepth)
2694 r_refdef.worldmodel->DrawDepth(r_refdef.worldentity);
2695 if (r_timereport_active)
2696 R_TimeReport("worlddepth");
2698 if (r_depthfirst.integer >= 2)
2700 R_DrawModelsDepth();
2701 if (r_timereport_active)
2702 R_TimeReport("modeldepth");
2705 if (cl.csqc_vidvars.drawworld && r_refdef.worldmodel && r_refdef.worldmodel->Draw)
2707 r_refdef.worldmodel->Draw(r_refdef.worldentity);
2708 if (r_timereport_active)
2709 R_TimeReport("world");
2712 // don't let sound skip if going slow
2713 if (r_refdef.extraupdate)
2717 if (r_timereport_active)
2718 R_TimeReport("models");
2720 // don't let sound skip if going slow
2721 if (r_refdef.extraupdate)
2724 if (r_shadows.integer > 0 && r_refdef.lightmapintensity > 0)
2726 R_DrawModelShadows();
2728 R_ResetViewRendering3D();
2730 // don't let sound skip if going slow
2731 if (r_refdef.extraupdate)
2735 R_ShadowVolumeLighting(false);
2736 if (r_timereport_active)
2737 R_TimeReport("rtlights");
2739 // don't let sound skip if going slow
2740 if (r_refdef.extraupdate)
2743 if (cl.csqc_vidvars.drawworld)
2745 R_DrawLightningBeams();
2746 if (r_timereport_active)
2747 R_TimeReport("lightning");
2750 if (r_timereport_active)
2751 R_TimeReport("particles");
2754 if (r_timereport_active)
2755 R_TimeReport("explosions");
2758 if (gl_support_fragment_shader)
2760 qglUseProgramObjectARB(0);CHECKGLERROR
2762 VM_CL_AddPolygonsToMeshQueue();
2764 if (cl_locs_show.integer)
2767 if (r_timereport_active)
2768 R_TimeReport("showlocs");
2771 if (r_drawportals.integer)
2774 if (r_timereport_active)
2775 R_TimeReport("portals");
2778 if (r_showbboxes.value > 0)
2780 R_DrawEntityBBoxes();
2781 if (r_timereport_active)
2782 R_TimeReport("bboxes");
2785 if (gl_support_fragment_shader)
2787 qglUseProgramObjectARB(0);CHECKGLERROR
2789 R_MeshQueue_RenderTransparent();
2790 if (r_timereport_active)
2791 R_TimeReport("drawtrans");
2793 if (gl_support_fragment_shader)
2795 qglUseProgramObjectARB(0);CHECKGLERROR
2798 if (cl.csqc_vidvars.drawworld)
2801 if (r_timereport_active)
2802 R_TimeReport("coronas");
2805 // don't let sound skip if going slow
2806 if (r_refdef.extraupdate)
2809 R_ResetViewRendering2D();
2812 static const int bboxelements[36] =
2822 void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
2825 float *v, *c, f1, f2, vertex3f[8*3], color4f[8*4];
2826 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2827 GL_DepthMask(false);
2828 GL_DepthRange(0, 1);
2829 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
2830 R_Mesh_Matrix(&identitymatrix);
2831 R_Mesh_ResetTextureState();
2833 vertex3f[ 0] = mins[0];vertex3f[ 1] = mins[1];vertex3f[ 2] = mins[2]; //
2834 vertex3f[ 3] = maxs[0];vertex3f[ 4] = mins[1];vertex3f[ 5] = mins[2];
2835 vertex3f[ 6] = mins[0];vertex3f[ 7] = maxs[1];vertex3f[ 8] = mins[2];
2836 vertex3f[ 9] = maxs[0];vertex3f[10] = maxs[1];vertex3f[11] = mins[2];
2837 vertex3f[12] = mins[0];vertex3f[13] = mins[1];vertex3f[14] = maxs[2];
2838 vertex3f[15] = maxs[0];vertex3f[16] = mins[1];vertex3f[17] = maxs[2];
2839 vertex3f[18] = mins[0];vertex3f[19] = maxs[1];vertex3f[20] = maxs[2];
2840 vertex3f[21] = maxs[0];vertex3f[22] = maxs[1];vertex3f[23] = maxs[2];
2841 R_FillColors(color4f, 8, cr, cg, cb, ca);
2842 if (r_refdef.fogenabled)
2844 for (i = 0, v = vertex3f, c = color4f;i < 8;i++, v += 3, c += 4)
2846 f1 = FogPoint_World(v);
2848 c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
2849 c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
2850 c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
2853 R_Mesh_VertexPointer(vertex3f, 0, 0);
2854 R_Mesh_ColorPointer(color4f, 0, 0);
2855 R_Mesh_ResetTextureState();
2856 R_Mesh_Draw(0, 8, 12, bboxelements, 0, 0);
2859 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2863 prvm_edict_t *edict;
2864 // this function draws bounding boxes of server entities
2868 for (i = 0;i < numsurfaces;i++)
2870 edict = PRVM_EDICT_NUM(surfacelist[i]);
2871 switch ((int)edict->fields.server->solid)
2873 case SOLID_NOT: Vector4Set(color, 1, 1, 1, 0.05);break;
2874 case SOLID_TRIGGER: Vector4Set(color, 1, 0, 1, 0.10);break;
2875 case SOLID_BBOX: Vector4Set(color, 0, 1, 0, 0.10);break;
2876 case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
2877 case SOLID_BSP: Vector4Set(color, 0, 0, 1, 0.05);break;
2878 default: Vector4Set(color, 0, 0, 0, 0.50);break;
2880 color[3] *= r_showbboxes.value;
2881 color[3] = bound(0, color[3], 1);
2882 GL_DepthTest(!r_showdisabledepthtest.integer);
2883 GL_CullFace(GL_BACK);
2884 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
2889 static void R_DrawEntityBBoxes(void)
2892 prvm_edict_t *edict;
2894 // this function draws bounding boxes of server entities
2898 for (i = 0;i < prog->num_edicts;i++)
2900 edict = PRVM_EDICT_NUM(i);
2901 if (edict->priv.server->free)
2903 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
2904 R_MeshQueue_AddTransparent(center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)NULL);
2909 int nomodelelements[24] =
2921 float nomodelvertex3f[6*3] =
2931 float nomodelcolor4f[6*4] =
2933 0.0f, 0.0f, 0.5f, 1.0f,
2934 0.0f, 0.0f, 0.5f, 1.0f,
2935 0.0f, 0.5f, 0.0f, 1.0f,
2936 0.0f, 0.5f, 0.0f, 1.0f,
2937 0.5f, 0.0f, 0.0f, 1.0f,
2938 0.5f, 0.0f, 0.0f, 1.0f
2941 void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
2946 // this is only called once per entity so numsurfaces is always 1, and
2947 // surfacelist is always {0}, so this code does not handle batches
2948 R_Mesh_Matrix(&ent->matrix);
2950 if (ent->flags & EF_ADDITIVE)
2952 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
2953 GL_DepthMask(false);
2955 else if (ent->alpha < 1)
2957 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2958 GL_DepthMask(false);
2962 GL_BlendFunc(GL_ONE, GL_ZERO);
2965 GL_DepthRange(0, (ent->flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
2966 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
2967 GL_DepthTest(!(ent->effects & EF_NODEPTHTEST));
2968 GL_CullFace((ent->effects & EF_DOUBLESIDED) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
2969 R_Mesh_VertexPointer(nomodelvertex3f, 0, 0);
2970 if (r_refdef.fogenabled)
2973 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
2974 R_Mesh_ColorPointer(color4f, 0, 0);
2975 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
2976 f1 = FogPoint_World(org);
2978 for (i = 0, c = color4f;i < 6;i++, c += 4)
2980 c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
2981 c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
2982 c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
2986 else if (ent->alpha != 1)
2988 memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
2989 R_Mesh_ColorPointer(color4f, 0, 0);
2990 for (i = 0, c = color4f;i < 6;i++, c += 4)
2994 R_Mesh_ColorPointer(nomodelcolor4f, 0, 0);
2995 R_Mesh_ResetTextureState();
2996 R_Mesh_Draw(0, 6, 8, nomodelelements, 0, 0);
2999 void R_DrawNoModel(entity_render_t *ent)
3002 Matrix4x4_OriginFromMatrix(&ent->matrix, org);
3003 //if ((ent->effects & EF_ADDITIVE) || (ent->alpha < 1))
3004 R_MeshQueue_AddTransparent(ent->effects & EF_NODEPTHTEST ? r_view.origin : org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
3006 // R_DrawNoModelCallback(ent, 0);
3009 void R_CalcBeam_Vertex3f (float *vert, const vec3_t org1, const vec3_t org2, float width)
3011 vec3_t right1, right2, diff, normal;
3013 VectorSubtract (org2, org1, normal);
3015 // calculate 'right' vector for start
3016 VectorSubtract (r_view.origin, org1, diff);
3017 CrossProduct (normal, diff, right1);
3018 VectorNormalize (right1);
3020 // calculate 'right' vector for end
3021 VectorSubtract (r_view.origin, org2, diff);
3022 CrossProduct (normal, diff, right2);
3023 VectorNormalize (right2);
3025 vert[ 0] = org1[0] + width * right1[0];
3026 vert[ 1] = org1[1] + width * right1[1];
3027 vert[ 2] = org1[2] + width * right1[2];
3028 vert[ 3] = org1[0] - width * right1[0];
3029 vert[ 4] = org1[1] - width * right1[1];
3030 vert[ 5] = org1[2] - width * right1[2];
3031 vert[ 6] = org2[0] - width * right2[0];
3032 vert[ 7] = org2[1] - width * right2[1];
3033 vert[ 8] = org2[2] - width * right2[2];
3034 vert[ 9] = org2[0] + width * right2[0];
3035 vert[10] = org2[1] + width * right2[1];
3036 vert[11] = org2[2] + width * right2[2];
3039 float spritetexcoord2f[4*2] = {0, 1, 0, 0, 1, 0, 1, 1};
3041 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)
3046 if (r_refdef.fogenabled)
3047 fog = FogPoint_World(origin);
3049 R_Mesh_Matrix(&identitymatrix);
3050 GL_BlendFunc(blendfunc1, blendfunc2);
3056 GL_CullFace(GL_BACK);
3059 GL_CullFace(GL_FRONT);
3061 GL_DepthMask(false);
3062 GL_DepthRange(0, depthshort ? 0.0625 : 1);
3063 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
3064 GL_DepthTest(!depthdisable);
3066 vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
3067 vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
3068 vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
3069 vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
3070 vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
3071 vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
3072 vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
3073 vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
3074 vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
3075 vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
3076 vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
3077 vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
3079 R_Mesh_VertexPointer(vertex3f, 0, 0);
3080 R_Mesh_ColorPointer(NULL, 0, 0);
3081 R_Mesh_ResetTextureState();
3082 R_Mesh_TexBind(0, R_GetTexture(texture));
3083 R_Mesh_TexCoordPointer(0, 2, spritetexcoord2f, 0, 0);
3084 // FIXME: fixed function path can't properly handle r_view.colorscale > 1
3085 GL_Color(cr * fog * r_view.colorscale, cg * fog * r_view.colorscale, cb * fog * r_view.colorscale, ca);
3086 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3088 if (blendfunc2 == GL_ONE_MINUS_SRC_ALPHA)
3090 R_Mesh_TexBind(0, R_GetTexture(fogtexture));
3091 GL_BlendFunc(blendfunc1, GL_ONE);
3093 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);
3094 R_Mesh_Draw(0, 4, 2, polygonelements, 0, 0);
3098 int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
3103 VectorSet(v, x, y, z);
3104 for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
3105 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
3107 if (i == mesh->numvertices)
3109 if (mesh->numvertices < mesh->maxvertices)
3111 VectorCopy(v, vertex3f);
3112 mesh->numvertices++;
3114 return mesh->numvertices;
3120 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
3124 element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
3125 element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
3126 e = mesh->element3i + mesh->numtriangles * 3;
3127 for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
3129 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
3130 if (mesh->numtriangles < mesh->maxtriangles)
3135 mesh->numtriangles++;
3137 element[1] = element[2];
3141 void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
3145 element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
3146 element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
3147 e = mesh->element3i + mesh->numtriangles * 3;
3148 for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
3150 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
3151 if (mesh->numtriangles < mesh->maxtriangles)
3156 mesh->numtriangles++;
3158 element[1] = element[2];
3162 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
3163 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
3165 int planenum, planenum2;
3168 mplane_t *plane, *plane2;
3170 double temppoints[2][256*3];
3171 // figure out how large a bounding box we need to properly compute this brush
3173 for (w = 0;w < numplanes;w++)
3174 maxdist = max(maxdist, planes[w].dist);
3175 // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
3176 maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
3177 for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
3181 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
3182 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
3184 if (planenum2 == planenum)
3186 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);
3189 if (tempnumpoints < 3)
3191 // generate elements forming a triangle fan for this polygon
3192 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
3196 static void R_DrawCollisionBrush(const colbrushf_t *brush)
3199 R_Mesh_VertexPointer(brush->points->v, 0, 0);
3200 i = (int)(((size_t)brush) / sizeof(colbrushf_t));
3201 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);
3202 GL_LockArrays(0, brush->numpoints);
3203 R_Mesh_Draw(0, brush->numpoints, brush->numtriangles, brush->elements, 0, 0);
3204 GL_LockArrays(0, 0);
3207 static void R_DrawCollisionSurface(const entity_render_t *ent, const msurface_t *surface)
3210 if (!surface->num_collisiontriangles)
3212 R_Mesh_VertexPointer(surface->data_collisionvertex3f, 0, 0);
3213 i = (int)(((size_t)surface) / sizeof(msurface_t));
3214 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);
3215 GL_LockArrays(0, surface->num_collisionvertices);
3216 R_Mesh_Draw(0, surface->num_collisionvertices, surface->num_collisiontriangles, surface->data_collisionelement3i, 0, 0);
3217 GL_LockArrays(0, 0);
3220 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)
3222 texturelayer_t *layer;
3223 layer = t->currentlayers + t->currentnumlayers++;
3225 layer->depthmask = depthmask;
3226 layer->blendfunc1 = blendfunc1;
3227 layer->blendfunc2 = blendfunc2;
3228 layer->texture = texture;
3229 layer->texmatrix = *matrix;
3230 layer->color[0] = r * r_view.colorscale;
3231 layer->color[1] = g * r_view.colorscale;
3232 layer->color[2] = b * r_view.colorscale;
3233 layer->color[3] = a;
3236 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
3239 index = parms[2] + r_refdef.time * parms[3];
3240 index -= floor(index);
3244 case Q3WAVEFUNC_NONE:
3245 case Q3WAVEFUNC_NOISE:
3246 case Q3WAVEFUNC_COUNT:
3249 case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
3250 case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
3251 case Q3WAVEFUNC_SAWTOOTH: f = index;break;
3252 case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
3253 case Q3WAVEFUNC_TRIANGLE:
3255 f = index - floor(index);
3266 return (float)(parms[0] + parms[1] * f);
3269 void R_UpdateTextureInfo(const entity_render_t *ent, texture_t *t)
3272 model_t *model = ent->model;
3275 q3shaderinfo_layer_tcmod_t *tcmod;
3277 // switch to an alternate material if this is a q1bsp animated material
3279 texture_t *texture = t;
3280 int s = ent->skinnum;
3281 if ((unsigned int)s >= (unsigned int)model->numskins)
3283 if (model->skinscenes)
3285 if (model->skinscenes[s].framecount > 1)
3286 s = model->skinscenes[s].firstframe + (unsigned int) (r_refdef.time * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
3288 s = model->skinscenes[s].firstframe;
3291 t = t + s * model->num_surfaces;
3294 // use an alternate animation if the entity's frame is not 0,
3295 // and only if the texture has an alternate animation
3296 if (ent->frame2 != 0 && t->anim_total[1])
3297 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(r_refdef.time * 5.0f) % t->anim_total[1]) : 0];
3299 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(r_refdef.time * 5.0f) % t->anim_total[0]) : 0];
3301 texture->currentframe = t;
3304 // update currentskinframe to be a qw skin or animation frame
3305 if ((i = ent->entitynumber - 1) >= 0 && i < cl.maxclients)
3307 if (strcmp(r_qwskincache[i], cl.scores[i].qw_skin))
3309 strlcpy(r_qwskincache[i], cl.scores[i].qw_skin, sizeof(r_qwskincache[i]));
3310 Con_DPrintf("loading skins/%s\n", r_qwskincache[i]);
3311 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);
3313 t->currentskinframe = r_qwskincache_skinframe[i];
3314 if (t->currentskinframe == NULL)
3315 t->currentskinframe = t->skinframes[(int)(t->skinframerate * (cl.time - ent->frame2time)) % t->numskinframes];
3317 else if (t->numskinframes >= 2)
3318 t->currentskinframe = t->skinframes[(int)(t->skinframerate * (cl.time - ent->frame2time)) % t->numskinframes];
3319 if (t->backgroundnumskinframes >= 2)
3320 t->backgroundcurrentskinframe = t->backgroundskinframes[(int)(t->backgroundskinframerate * (cl.time - ent->frame2time)) % t->backgroundnumskinframes];
3322 t->currentmaterialflags = t->basematerialflags;
3323 t->currentalpha = ent->alpha;
3324 if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_novis.integer))
3325 t->currentalpha *= r_wateralpha.value;
3326 if (!(ent->flags & RENDER_LIGHT))
3327 t->currentmaterialflags |= MATERIALFLAG_FULLBRIGHT;
3328 if (ent->effects & EF_ADDITIVE)
3329 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
3330 else if (t->currentalpha < 1)
3331 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
3332 if (ent->effects & EF_DOUBLESIDED)
3333 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
3334 if (ent->effects & EF_NODEPTHTEST)
3335 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
3336 if (ent->flags & RENDER_VIEWMODEL)
3337 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
3338 if (t->backgroundnumskinframes && !(t->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED))
3339 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
3341 for (i = 0, tcmod = t->tcmods;i < Q3MAXTCMODS && (tcmod->tcmod || i < 1);i++, tcmod++)
3344 switch(tcmod->tcmod)
3348 if (t->currentmaterialflags & MATERIALFLAG_WATER && r_waterscroll.value != 0)
3349 matrix = r_waterscrollmatrix;
3351 matrix = identitymatrix;
3353 case Q3TCMOD_ENTITYTRANSLATE:
3354 // this is used in Q3 to allow the gamecode to control texcoord
3355 // scrolling on the entity, which is not supported in darkplaces yet.
3356 Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
3358 case Q3TCMOD_ROTATE:
3359 Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
3360 Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * r_refdef.time, 0, 0, 1);
3361 Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
3364 Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
3366 case Q3TCMOD_SCROLL:
3367 Matrix4x4_CreateTranslate(&matrix, tcmod->parms[0] * r_refdef.time, tcmod->parms[1] * r_refdef.time, 0);
3369 case Q3TCMOD_STRETCH:
3370 f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
3371 Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
3373 case Q3TCMOD_TRANSFORM:
3374 VectorSet(tcmat + 0, tcmod->parms[0], tcmod->parms[1], 0);
3375 VectorSet(tcmat + 3, tcmod->parms[2], tcmod->parms[3], 0);
3376 VectorSet(tcmat + 6, 0 , 0 , 1);
3377 VectorSet(tcmat + 9, tcmod->parms[4], tcmod->parms[5], 0);
3378 Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
3380 case Q3TCMOD_TURBULENT:
3381 // this is handled in the RSurf_PrepareVertices function
3382 matrix = identitymatrix;
3385 // either replace or concatenate the transformation
3387 t->currenttexmatrix = matrix;
3390 matrix4x4_t temp = t->currenttexmatrix;
3391 Matrix4x4_Concat(&t->currenttexmatrix, &matrix, &temp);
3395 t->colormapping = VectorLength2(ent->colormap_pantscolor) + VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f);
3396 t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
3397 t->glosstexture = r_texture_white;
3398 t->backgroundbasetexture = t->backgroundnumskinframes ? ((!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base) : r_texture_white;
3399 t->backgroundglosstexture = r_texture_white;
3400 t->specularpower = r_shadow_glossexponent.value;
3401 // TODO: store reference values for these in the texture?
3402 t->specularscale = 0;
3403 if (r_shadow_gloss.integer > 0)
3405 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
3407 if (r_shadow_glossintensity.value > 0)
3409 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_black;
3410 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_black;
3411 t->specularscale = r_shadow_glossintensity.value;
3414 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
3415 t->specularscale = r_shadow_gloss2intensity.value;
3418 // lightmaps mode looks bad with dlights using actual texturing, so turn
3419 // off the colormap and glossmap, but leave the normalmap on as it still
3420 // accurately represents the shading involved
3421 if (gl_lightmaps.integer && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
3423 t->basetexture = r_texture_white;
3424 t->specularscale = 0;
3427 t->currentpolygonfactor = r_refdef.polygonfactor + t->basepolygonfactor;
3428 t->currentpolygonoffset = r_refdef.polygonoffset + t->basepolygonoffset;
3429 // submodels are biased to avoid z-fighting with world surfaces that they
3430 // may be exactly overlapping (avoids z-fighting artifacts on certain
3431 // doors and things in Quake maps)
3432 if (ent->model->brush.submodel)
3434 t->currentpolygonfactor += r_polygonoffset_submodel_factor.value;
3435 t->currentpolygonoffset += r_polygonoffset_submodel_offset.value;
3438 VectorClear(t->dlightcolor);
3439 t->currentnumlayers = 0;
3440 if (!(t->currentmaterialflags & MATERIALFLAG_NODRAW))
3442 if (!(t->currentmaterialflags & MATERIALFLAG_SKY))
3444 int blendfunc1, blendfunc2, depthmask;
3445 if (t->currentmaterialflags & MATERIALFLAG_ADD)
3447 blendfunc1 = GL_SRC_ALPHA;
3448 blendfunc2 = GL_ONE;
3450 else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
3452 blendfunc1 = GL_SRC_ALPHA;
3453 blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
3455 else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
3457 blendfunc1 = t->customblendfunc[0];
3458 blendfunc2 = t->customblendfunc[1];
3462 blendfunc1 = GL_ONE;
3463 blendfunc2 = GL_ZERO;
3465 depthmask = !(t->currentmaterialflags & MATERIALFLAG_BLENDED);
3466 if (t->currentmaterialflags & (MATERIALFLAG_WATER | MATERIALFLAG_WALL))
3468 rtexture_t *currentbasetexture;
3470 if (r_refdef.fogenabled && (t->currentmaterialflags & MATERIALFLAG_BLENDED))
3471 layerflags |= TEXTURELAYERFLAG_FOGDARKEN;
3472 currentbasetexture = (VectorLength2(ent->colormap_pantscolor) + VectorLength2(ent->colormap_shirtcolor) < (1.0f / 1048576.0f) && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
3473 if (t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
3475 // fullbright is not affected by r_refdef.lightmapintensity
3476 R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_TEXTURE, currentbasetexture, &t->currenttexmatrix, ent->colormod[0], ent->colormod[1], ent->colormod[2], t->currentalpha);
3477 if (VectorLength2(ent->colormap_pantscolor) >= (1.0f / 1048576.0f) && t->currentskinframe->pants)
3478 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);
3479 if (VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->currentskinframe->shirt)
3480 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);
3485 // set the color tint used for lights affecting this surface
3486 VectorSet(t->dlightcolor, ent->colormod[0] * t->currentalpha, ent->colormod[1] * t->currentalpha, ent->colormod[2] * t->currentalpha);
3488 // q3bsp has no lightmap updates, so the lightstylevalue that
3489 // would normally be baked into the lightmap must be
3490 // applied to the color
3491 // FIXME: r_glsl 1 rendering doesn't support overbright lightstyles with this (the default light style is not overbright)
3492 if (ent->model->type == mod_brushq3)
3493 colorscale *= r_refdef.lightstylevalue[0] * (1.0f / 256.0f);
3494 colorscale *= r_refdef.lightmapintensity;
3495 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);
3496 if (r_ambient.value >= (1.0f/64.0f))
3497 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);
3498 if (VectorLength2(ent->colormap_pantscolor) >= (1.0f / 1048576.0f) && t->currentskinframe->pants)
3500 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);
3501 if (r_ambient.value >= (1.0f/64.0f))
3502 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);
3504 if (VectorLength2(ent->colormap_shirtcolor) >= (1.0f / 1048576.0f) && t->currentskinframe->shirt)
3506 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);
3507 if (r_ambient.value >= (1.0f/64.0f))
3508 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);
3511 if (t->currentskinframe->glow != NULL)
3512 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);
3513 if (r_refdef.fogenabled && !(t->currentmaterialflags & MATERIALFLAG_ADD))
3515 // if this is opaque use alpha blend which will darken the earlier
3518 // if this is an alpha blended material, all the earlier passes
3519 // were darkened by fog already, so we only need to add the fog
3520 // color ontop through the fog mask texture
3522 // if this is an additive blended material, all the earlier passes
3523 // were darkened by fog already, and we should not add fog color
3524 // (because the background was not darkened, there is no fog color
3525 // that was lost behind it).
3526 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);
3533 void R_UpdateAllTextureInfo(entity_render_t *ent)
3537 for (i = 0;i < ent->model->num_texturesperskin;i++)
3538 R_UpdateTextureInfo(ent, ent->model->data_textures + i);
3541 rsurfacestate_t rsurface;
3543 void R_Mesh_ResizeArrays(int newvertices)
3546 if (rsurface.array_size >= newvertices)
3548 if (rsurface.array_modelvertex3f)
3549 Mem_Free(rsurface.array_modelvertex3f);
3550 rsurface.array_size = (newvertices + 1023) & ~1023;
3551 base = (float *)Mem_Alloc(r_main_mempool, rsurface.array_size * sizeof(float[33]));
3552 rsurface.array_modelvertex3f = base + rsurface.array_size * 0;
3553 rsurface.array_modelsvector3f = base + rsurface.array_size * 3;
3554 rsurface.array_modeltvector3f = base + rsurface.array_size * 6;
3555 rsurface.array_modelnormal3f = base + rsurface.array_size * 9;
3556 rsurface.array_deformedvertex3f = base + rsurface.array_size * 12;
3557 rsurface.array_deformedsvector3f = base + rsurface.array_size * 15;
3558 rsurface.array_deformedtvector3f = base + rsurface.array_size * 18;
3559 rsurface.array_deformednormal3f = base + rsurface.array_size * 21;
3560 rsurface.array_texcoord3f = base + rsurface.array_size * 24;
3561 rsurface.array_color4f = base + rsurface.array_size * 27;
3562 rsurface.array_generatedtexcoordtexture2f = base + rsurface.array_size * 31;
3565 void RSurf_CleanUp(void)
3568 if (rsurface.mode == RSURFMODE_GLSL)
3570 qglUseProgramObjectARB(0);CHECKGLERROR
3572 GL_AlphaTest(false);
3573 rsurface.mode = RSURFMODE_NONE;
3574 rsurface.uselightmaptexture = false;
3575 rsurface.texture = NULL;
3578 void RSurf_ActiveWorldEntity(void)
3580 model_t *model = r_refdef.worldmodel;
3582 if (rsurface.array_size < model->surfmesh.num_vertices)
3583 R_Mesh_ResizeArrays(model->surfmesh.num_vertices);
3584 rsurface.matrix = identitymatrix;
3585 rsurface.inversematrix = identitymatrix;
3586 R_Mesh_Matrix(&identitymatrix);
3587 VectorCopy(r_view.origin, rsurface.modelorg);
3588 VectorSet(rsurface.modellight_ambient, 0, 0, 0);
3589 VectorSet(rsurface.modellight_diffuse, 0, 0, 0);
3590 VectorSet(rsurface.modellight_lightdir, 0, 0, 1);
3591 VectorSet(rsurface.colormap_pantscolor, 0, 0, 0);
3592 VectorSet(rsurface.colormap_shirtcolor, 0, 0, 0);
3593 rsurface.frameblend[0].frame = 0;
3594 rsurface.frameblend[0].lerp = 1;
3595 rsurface.frameblend[1].frame = 0;
3596 rsurface.frameblend[1].lerp = 0;
3597 rsurface.frameblend[2].frame = 0;
3598 rsurface.frameblend[2].lerp = 0;
3599 rsurface.frameblend[3].frame = 0;
3600 rsurface.frameblend[3].lerp = 0;
3601 rsurface.modelvertex3f = model->surfmesh.data_vertex3f;
3602 rsurface.modelvertex3f_bufferobject = model->surfmesh.vbo;
3603 rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f;
3604 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
3605 rsurface.modelsvector3f_bufferobject = model->surfmesh.vbo;
3606 rsurface.modelsvector3f_bufferoffset = model->surfmesh.vbooffset_svector3f;
3607 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
3608 rsurface.modeltvector3f_bufferobject = model->surfmesh.vbo;
3609 rsurface.modeltvector3f_bufferoffset = model->surfmesh.vbooffset_tvector3f;
3610 rsurface.modelnormal3f = model->surfmesh.data_normal3f;
3611 rsurface.modelnormal3f_bufferobject = model->surfmesh.vbo;
3612 rsurface.modelnormal3f_bufferoffset = model->surfmesh.vbooffset_normal3f;
3613 rsurface.modellightmapcolor4f = model->surfmesh.data_lightmapcolor4f;
3614 rsurface.modellightmapcolor4f_bufferobject = model->surfmesh.vbo;
3615 rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.vbooffset_lightmapcolor4f;
3616 rsurface.modeltexcoordtexture2f = model->surfmesh.data_texcoordtexture2f;
3617 rsurface.modeltexcoordtexture2f_bufferobject = model->surfmesh.vbo;
3618 rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.vbooffset_texcoordtexture2f;
3619 rsurface.modeltexcoordlightmap2f = model->surfmesh.data_texcoordlightmap2f;
3620 rsurface.modeltexcoordlightmap2f_bufferobject = model->surfmesh.vbo;
3621 rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f;
3622 rsurface.modelelement3i = model->surfmesh.data_element3i;
3623 rsurface.modelelement3i_bufferobject = model->surfmesh.ebo;
3624 rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
3625 rsurface.modelnum_vertices = model->surfmesh.num_vertices;
3626 rsurface.modelnum_triangles = model->surfmesh.num_triangles;
3627 rsurface.modelsurfaces = model->data_surfaces;
3628 rsurface.generatedvertex = false;
3629 rsurface.vertex3f = rsurface.modelvertex3f;
3630 rsurface.vertex3f_bufferobject = rsurface.modelvertex3f_bufferobject;
3631 rsurface.vertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
3632 rsurface.svector3f = rsurface.modelsvector3f;
3633 rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject;
3634 rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
3635 rsurface.tvector3f = rsurface.modeltvector3f;
3636 rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject;
3637 rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
3638 rsurface.normal3f = rsurface.modelnormal3f;
3639 rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject;
3640 rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
3641 rsurface.texcoordtexture2f = rsurface.modeltexcoordtexture2f;
3644 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
3646 model_t *model = ent->model;
3648 if (rsurface.array_size < model->surfmesh.num_vertices)
3649 R_Mesh_ResizeArrays(model->surfmesh.num_vertices);
3650 rsurface.matrix = ent->matrix;
3651 rsurface.inversematrix = ent->inversematrix;
3652 R_Mesh_Matrix(&rsurface.matrix);
3653 Matrix4x4_Transform(&rsurface.inversematrix, r_view.origin, rsurface.modelorg);
3654 VectorCopy(ent->modellight_ambient, rsurface.modellight_ambient);
3655 VectorCopy(ent->modellight_diffuse, rsurface.modellight_diffuse);
3656 VectorCopy(ent->modellight_lightdir, rsurface.modellight_lightdir);
3657 VectorCopy(ent->colormap_pantscolor, rsurface.colormap_pantscolor);
3658 VectorCopy(ent->colormap_shirtcolor, rsurface.colormap_shirtcolor);
3659 rsurface.frameblend[0] = ent->frameblend[0];
3660 rsurface.frameblend[1] = ent->frameblend[1];
3661 rsurface.frameblend[2] = ent->frameblend[2];
3662 rsurface.frameblend[3] = ent->frameblend[3];
3663 if (model->surfmesh.isanimated && (rsurface.frameblend[0].lerp != 1 || rsurface.frameblend[0].frame != 0))
3667 rsurface.modelvertex3f = rsurface.array_modelvertex3f;
3668 rsurface.modelsvector3f = rsurface.array_modelsvector3f;
3669 rsurface.modeltvector3f = rsurface.array_modeltvector3f;
3670 rsurface.modelnormal3f = rsurface.array_modelnormal3f;
3671 Mod_Alias_GetMesh_Vertices(model, rsurface.frameblend, rsurface.array_modelvertex3f, rsurface.array_modelnormal3f, rsurface.array_modelsvector3f, rsurface.array_modeltvector3f);
3673 else if (wantnormals)
3675 rsurface.modelvertex3f = rsurface.array_modelvertex3f;
3676 rsurface.modelsvector3f = NULL;
3677 rsurface.modeltvector3f = NULL;
3678 rsurface.modelnormal3f = rsurface.array_modelnormal3f;
3679 Mod_Alias_GetMesh_Vertices(model, rsurface.frameblend, rsurface.array_modelvertex3f, rsurface.array_modelnormal3f, NULL, NULL);
3683 rsurface.modelvertex3f = rsurface.array_modelvertex3f;
3684 rsurface.modelsvector3f = NULL;
3685 rsurface.modeltvector3f = NULL;
3686 rsurface.modelnormal3f = NULL;
3687 Mod_Alias_GetMesh_Vertices(model, rsurface.frameblend, rsurface.array_modelvertex3f, NULL, NULL, NULL);
3689 rsurface.modelvertex3f_bufferobject = 0;
3690 rsurface.modelvertex3f_bufferoffset = 0;
3691 rsurface.modelsvector3f_bufferobject = 0;
3692 rsurface.modelsvector3f_bufferoffset = 0;
3693 rsurface.modeltvector3f_bufferobject = 0;
3694 rsurface.modeltvector3f_bufferoffset = 0;
3695 rsurface.modelnormal3f_bufferobject = 0;
3696 rsurface.modelnormal3f_bufferoffset = 0;
3697 rsurface.generatedvertex = true;
3701 rsurface.modelvertex3f = model->surfmesh.data_vertex3f;
3702 rsurface.modelvertex3f_bufferobject = model->surfmesh.vbo;
3703 rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f;
3704 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
3705 rsurface.modelsvector3f_bufferobject = model->surfmesh.vbo;
3706 rsurface.modelsvector3f_bufferoffset = model->surfmesh.vbooffset_svector3f;
3707 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
3708 rsurface.modeltvector3f_bufferobject = model->surfmesh.vbo;
3709 rsurface.modeltvector3f_bufferoffset = model->surfmesh.vbooffset_tvector3f;
3710 rsurface.modelnormal3f = model->surfmesh.data_normal3f;
3711 rsurface.modelnormal3f_bufferobject = model->surfmesh.vbo;
3712 rsurface.modelnormal3f_bufferoffset = model->surfmesh.vbooffset_normal3f;
3713 rsurface.generatedvertex = false;
3715 rsurface.modellightmapcolor4f = model->surfmesh.data_lightmapcolor4f;
3716 rsurface.modellightmapcolor4f_bufferobject = model->surfmesh.vbo;
3717 rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.vbooffset_lightmapcolor4f;
3718 rsurface.modeltexcoordtexture2f = model->surfmesh.data_texcoordtexture2f;
3719 rsurface.modeltexcoordtexture2f_bufferobject = model->surfmesh.vbo;
3720 rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.vbooffset_texcoordtexture2f;
3721 rsurface.modeltexcoordlightmap2f = model->surfmesh.data_texcoordlightmap2f;
3722 rsurface.modeltexcoordlightmap2f_bufferobject = model->surfmesh.vbo;
3723 rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f;
3724 rsurface.modelelement3i = model->surfmesh.data_element3i;
3725 rsurface.modelelement3i_bufferobject = model->surfmesh.ebo;
3726 rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
3727 rsurface.modelnum_vertices = model->surfmesh.num_vertices;
3728 rsurface.modelnum_triangles = model->surfmesh.num_triangles;
3729 rsurface.modelsurfaces = model->data_surfaces;
3730 rsurface.vertex3f = rsurface.modelvertex3f;
3731 rsurface.vertex3f_bufferobject = rsurface.modelvertex3f_bufferobject;
3732 rsurface.vertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
3733 rsurface.svector3f = rsurface.modelsvector3f;
3734 rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject;
3735 rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
3736 rsurface.tvector3f = rsurface.modeltvector3f;
3737 rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject;
3738 rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
3739 rsurface.normal3f = rsurface.modelnormal3f;
3740 rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject;
3741 rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
3742 rsurface.texcoordtexture2f = rsurface.modeltexcoordtexture2f;
3745 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
3746 void RSurf_PrepareVerticesForBatch(qboolean generatenormals, qboolean generatetangents, int texturenumsurfaces, msurface_t **texturesurfacelist)
3749 int texturesurfaceindex;
3754 const float *v1, *in_tc;
3756 float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
3758 q3shaderinfo_deform_t *deform;
3759 // 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
3760 if (rsurface.generatedvertex)
3762 if (rsurface.texture->tcgen.tcgen == Q3TCGEN_ENVIRONMENT)
3763 generatenormals = true;
3764 for (i = 0;i < Q3MAXDEFORMS;i++)
3766 if (rsurface.texture->deforms[i].deform == Q3DEFORM_AUTOSPRITE)
3768 generatetangents = true;
3769 generatenormals = true;
3771 if (rsurface.texture->deforms[i].deform != Q3DEFORM_NONE)
3772 generatenormals = true;
3774 if (generatenormals && !rsurface.modelnormal3f)
3776 rsurface.normal3f = rsurface.modelnormal3f = rsurface.array_modelnormal3f;
3777 rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject = 0;
3778 rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset = 0;
3779 Mod_BuildNormals(0, rsurface.modelnum_vertices, rsurface.modelnum_triangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.array_modelnormal3f, r_smoothnormals_areaweighting.integer);
3781 if (generatetangents && !rsurface.modelsvector3f)
3783 rsurface.svector3f = rsurface.modelsvector3f = rsurface.array_modelsvector3f;
3784 rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject = 0;
3785 rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset = 0;
3786 rsurface.tvector3f = rsurface.modeltvector3f = rsurface.array_modeltvector3f;
3787 rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject = 0;
3788 rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset = 0;
3789 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);
3792 rsurface.vertex3f = rsurface.modelvertex3f;
3793 rsurface.vertex3f_bufferobject = rsurface.modelvertex3f_bufferobject;
3794 rsurface.vertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
3795 rsurface.svector3f = rsurface.modelsvector3f;
3796 rsurface.svector3f_bufferobject = rsurface.modelsvector3f_bufferobject;
3797 rsurface.svector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
3798 rsurface.tvector3f = rsurface.modeltvector3f;
3799 rsurface.tvector3f_bufferobject = rsurface.modeltvector3f_bufferobject;
3800 rsurface.tvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
3801 rsurface.normal3f = rsurface.modelnormal3f;
3802 rsurface.normal3f_bufferobject = rsurface.modelnormal3f_bufferobject;
3803 rsurface.normal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
3804 // if vertices are deformed (sprite flares and things in maps, possibly
3805 // water waves, bulges and other deformations), generate them into
3806 // rsurface.deform* arrays from whatever the rsurface.* arrays point to
3807 // (may be static model data or generated data for an animated model, or
3808 // the previous deform pass)
3809 for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform;deformindex++, deform++)
3811 switch (deform->deform)
3814 case Q3DEFORM_PROJECTIONSHADOW:
3815 case Q3DEFORM_TEXT0:
3816 case Q3DEFORM_TEXT1:
3817 case Q3DEFORM_TEXT2:
3818 case Q3DEFORM_TEXT3:
3819 case Q3DEFORM_TEXT4:
3820 case Q3DEFORM_TEXT5:
3821 case Q3DEFORM_TEXT6:
3822 case Q3DEFORM_TEXT7:
3825 case Q3DEFORM_AUTOSPRITE:
3826 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.forward, newforward);
3827 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.right, newright);
3828 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.up, newup);
3829 VectorNormalize(newforward);
3830 VectorNormalize(newright);
3831 VectorNormalize(newup);
3832 // make deformed versions of only the model vertices used by the specified surfaces
3833 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
3835 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
3836 // a single autosprite surface can contain multiple sprites...
3837 for (j = 0;j < surface->num_vertices - 3;j += 4)
3839 VectorClear(center);
3840 for (i = 0;i < 4;i++)
3841 VectorAdd(center, (rsurface.vertex3f + 3 * surface->num_firstvertex) + (j+i) * 3, center);
3842 VectorScale(center, 0.25f, center);
3843 VectorCopy((rsurface.normal3f + 3 * surface->num_firstvertex) + j*3, forward);
3844 VectorCopy((rsurface.svector3f + 3 * surface->num_firstvertex) + j*3, right);
3845 VectorCopy((rsurface.tvector3f + 3 * surface->num_firstvertex) + j*3, up);
3846 for (i = 0;i < 4;i++)
3848 VectorSubtract((rsurface.vertex3f + 3 * surface->num_firstvertex) + (j+i)*3, center, v);
3849 VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.array_deformedvertex3f + (surface->num_firstvertex+i+j) * 3);
3852 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);
3853 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);
3855 rsurface.vertex3f = rsurface.array_deformedvertex3f;
3856 rsurface.vertex3f_bufferobject = 0;
3857 rsurface.vertex3f_bufferoffset = 0;
3858 rsurface.svector3f = rsurface.array_deformedsvector3f;
3859 rsurface.svector3f_bufferobject = 0;
3860 rsurface.svector3f_bufferoffset = 0;
3861 rsurface.tvector3f = rsurface.array_deformedtvector3f;
3862 rsurface.tvector3f_bufferobject = 0;
3863 rsurface.tvector3f_bufferoffset = 0;
3864 rsurface.normal3f = rsurface.array_deformednormal3f;
3865 rsurface.normal3f_bufferobject = 0;
3866 rsurface.normal3f_bufferoffset = 0;
3868 case Q3DEFORM_AUTOSPRITE2:
3869 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.forward, newforward);
3870 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.right, newright);
3871 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.up, newup);
3872 VectorNormalize(newforward);
3873 VectorNormalize(newright);
3874 VectorNormalize(newup);
3875 // make deformed versions of only the model vertices used by the specified surfaces
3876 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
3878 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
3879 const float *v1, *v2;
3889 memset(shortest, 0, sizeof(shortest));
3890 // a single autosprite surface can contain multiple sprites...
3891 for (j = 0;j < surface->num_vertices - 3;j += 4)
3893 VectorClear(center);
3894 for (i = 0;i < 4;i++)
3895 VectorAdd(center, (rsurface.vertex3f + 3 * surface->num_firstvertex) + (j+i) * 3, center);
3896 VectorScale(center, 0.25f, center);
3897 // find the two shortest edges, then use them to define the
3898 // axis vectors for rotating around the central axis
3899 for (i = 0;i < 6;i++)
3901 v1 = rsurface.vertex3f + 3 * (surface->num_firstvertex + quadedges[i][0]);
3902 v2 = rsurface.vertex3f + 3 * (surface->num_firstvertex + quadedges[i][1]);
3904 Debug_PolygonBegin(NULL, 0, false, 0);
3905 Debug_PolygonVertex(v1[0], v1[1], v1[2], 0, 0, 1, 0, 0, 1);
3906 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);
3907 Debug_PolygonVertex(v2[0], v2[1], v2[2], 0, 0, 1, 0, 0, 1);
3910 l = VectorDistance2(v1, v2);
3911 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
3913 l += (1.0f / 1024.0f);
3914 if (shortest[0].length2 > l || i == 0)
3916 shortest[1] = shortest[0];
3917 shortest[0].length2 = l;
3918 shortest[0].v1 = v1;
3919 shortest[0].v2 = v2;
3921 else if (shortest[1].length2 > l || i == 1)
3923 shortest[1].length2 = l;
3924 shortest[1].v1 = v1;
3925 shortest[1].v2 = v2;
3928 VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
3929 VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
3931 Debug_PolygonBegin(NULL, 0, false, 0);
3932 Debug_PolygonVertex(start[0], start[1], start[2], 0, 0, 1, 1, 0, 1);
3933 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);
3934 Debug_PolygonVertex(end[0], end[1], end[2], 0, 0, 0, 1, 1, 1);
3937 // this calculates the right vector from the shortest edge
3938 // and the up vector from the edge midpoints
3939 VectorSubtract(shortest[0].v1, shortest[0].v2, right);
3940 VectorNormalize(right);
3941 VectorSubtract(end, start, up);
3942 VectorNormalize(up);
3943 // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
3944 //VectorSubtract(rsurface.modelorg, center, forward);
3945 Matrix4x4_Transform3x3(&rsurface.inversematrix, r_view.forward, forward);
3946 VectorNegate(forward, forward);
3947 VectorReflect(forward, 0, up, forward);
3948 VectorNormalize(forward);
3949 CrossProduct(up, forward, newright);
3950 VectorNormalize(newright);
3952 Debug_PolygonBegin(NULL, 0, false, 0);
3953 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);
3954 Debug_PolygonVertex(center[0] + right[0] * 8, center[1] + right[1] * 8, center[2] + right[2] * 8, 0, 0, 0, 1, 0, 1);
3955 Debug_PolygonVertex(center[0] + up [0] * 8, center[1] + up [1] * 8, center[2] + up [2] * 8, 0, 0, 0, 0, 1, 1);
3959 Debug_PolygonBegin(NULL, 0, false, 0);
3960 Debug_PolygonVertex(center[0] + forward [0] * 8, center[1] + forward [1] * 8, center[2] + forward [2] * 8, 0, 0, 1, 0, 0, 1);
3961 Debug_PolygonVertex(center[0] + newright[0] * 8, center[1] + newright[1] * 8, center[2] + newright[2] * 8, 0, 0, 0, 1, 0, 1);
3962 Debug_PolygonVertex(center[0] + up [0] * 8, center[1] + up [1] * 8, center[2] + up [2] * 8, 0, 0, 0, 0, 1, 1);
3965 // rotate the quad around the up axis vector, this is made
3966 // especially easy by the fact we know the quad is flat,
3967 // so we only have to subtract the center position and
3968 // measure distance along the right vector, and then
3969 // multiply that by the newright vector and add back the
3971 // we also need to subtract the old position to undo the
3972 // displacement from the center, which we do with a
3973 // DotProduct, the subtraction/addition of center is also
3974 // optimized into DotProducts here
3975 l = DotProduct(right, center);
3976 for (i = 0;i < 4;i++)
3978 v1 = rsurface.vertex3f + 3 * (surface->num_firstvertex + j + i);
3979 f = DotProduct(right, v1) - l;
3980 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.array_deformedvertex3f + (surface->num_firstvertex+i+j) * 3);
3983 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);
3984 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);
3986 rsurface.vertex3f = rsurface.array_deformedvertex3f;
3987 rsurface.vertex3f_bufferobject = 0;
3988 rsurface.vertex3f_bufferoffset = 0;
3989 rsurface.svector3f = rsurface.array_deformedsvector3f;
3990 rsurface.svector3f_bufferobject = 0;
3991 rsurface.svector3f_bufferoffset = 0;
3992 rsurface.tvector3f = rsurface.array_deformedtvector3f;
3993 rsurface.tvector3f_bufferobject = 0;
3994 rsurface.tvector3f_bufferoffset = 0;
3995 rsurface.normal3f = rsurface.array_deformednormal3f;
3996 rsurface.normal3f_bufferobject = 0;
3997 rsurface.normal3f_bufferoffset = 0;
3999 case Q3DEFORM_NORMAL:
4000 // deform the normals to make reflections wavey
4001 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4003 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4004 for (j = 0;j < surface->num_vertices;j++)
4007 float *normal = (rsurface.array_deformednormal3f + 3 * surface->num_firstvertex) + j*3;
4008 VectorScale((rsurface.vertex3f + 3 * surface->num_firstvertex) + j*3, 0.98f, vertex);
4009 VectorCopy((rsurface.normal3f + 3 * surface->num_firstvertex) + j*3, normal);
4010 normal[0] += deform->parms[0] * noise4f( vertex[0], vertex[1], vertex[2], r_refdef.time * deform->parms[1]);
4011 normal[1] += deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], r_refdef.time * deform->parms[1]);
4012 normal[2] += deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], r_refdef.time * deform->parms[1]);
4013 VectorNormalize(normal);
4015 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);
4017 rsurface.svector3f = rsurface.array_deformedsvector3f;
4018 rsurface.svector3f_bufferobject = 0;
4019 rsurface.svector3f_bufferoffset = 0;
4020 rsurface.tvector3f = rsurface.array_deformedtvector3f;
4021 rsurface.tvector3f_bufferobject = 0;
4022 rsurface.tvector3f_bufferoffset = 0;
4023 rsurface.normal3f = rsurface.array_deformednormal3f;
4024 rsurface.normal3f_bufferobject = 0;
4025 rsurface.normal3f_bufferoffset = 0;
4028 // deform vertex array to make wavey water and flags and such
4029 waveparms[0] = deform->waveparms[0];
4030 waveparms[1] = deform->waveparms[1];
4031 waveparms[2] = deform->waveparms[2];
4032 waveparms[3] = deform->waveparms[3];
4033 // this is how a divisor of vertex influence on deformation
4034 animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
4035 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
4036 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4038 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4039 for (j = 0;j < surface->num_vertices;j++)
4041 float *vertex = (rsurface.array_deformedvertex3f + 3 * surface->num_firstvertex) + j*3;
4042 VectorCopy((rsurface.vertex3f + 3 * surface->num_firstvertex) + j*3, vertex);
4043 // if the wavefunc depends on time, evaluate it per-vertex
4046 waveparms[2] = deform->waveparms[2] + (vertex[0] + vertex[1] + vertex[2]) * animpos;
4047 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
4049 VectorMA(vertex, scale, (rsurface.normal3f + 3 * surface->num_firstvertex) + j*3, vertex);
4052 rsurface.vertex3f = rsurface.array_deformedvertex3f;
4053 rsurface.vertex3f_bufferobject = 0;
4054 rsurface.vertex3f_bufferoffset = 0;
4056 case Q3DEFORM_BULGE:
4057 // deform vertex array to make the surface have moving bulges
4058 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4060 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4061 for (j = 0;j < surface->num_vertices;j++)
4063 scale = sin((rsurface.modeltexcoordtexture2f[2 * (surface->num_firstvertex + j)] * deform->parms[0] + r_refdef.time * deform->parms[2])) * deform->parms[1];
4064 VectorMA(rsurface.vertex3f + 3 * (surface->num_firstvertex + j), scale, rsurface.normal3f + 3 * (surface->num_firstvertex + j), rsurface.array_deformedvertex3f + 3 * (surface->num_firstvertex + j));
4067 rsurface.vertex3f = rsurface.array_deformedvertex3f;
4068 rsurface.vertex3f_bufferobject = 0;
4069 rsurface.vertex3f_bufferoffset = 0;
4072 // deform vertex array
4073 scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
4074 VectorScale(deform->parms, scale, waveparms);
4075 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4077 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4078 for (j = 0;j < surface->num_vertices;j++)
4079 VectorAdd(rsurface.vertex3f + 3 * (surface->num_firstvertex + j), waveparms, rsurface.array_deformedvertex3f + 3 * (surface->num_firstvertex + j));
4081 rsurface.vertex3f = rsurface.array_deformedvertex3f;
4082 rsurface.vertex3f_bufferobject = 0;
4083 rsurface.vertex3f_bufferoffset = 0;
4087 // generate texcoords based on the chosen texcoord source
4088 switch(rsurface.texture->tcgen.tcgen)
4091 case Q3TCGEN_TEXTURE:
4092 rsurface.texcoordtexture2f = rsurface.modeltexcoordtexture2f;
4093 rsurface.texcoordtexture2f_bufferobject = rsurface.modeltexcoordtexture2f_bufferobject;
4094 rsurface.texcoordtexture2f_bufferoffset = rsurface.modeltexcoordtexture2f_bufferoffset;
4096 case Q3TCGEN_LIGHTMAP:
4097 rsurface.texcoordtexture2f = rsurface.modeltexcoordlightmap2f;
4098 rsurface.texcoordtexture2f_bufferobject = rsurface.modeltexcoordlightmap2f_bufferobject;
4099 rsurface.texcoordtexture2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
4101 case Q3TCGEN_VECTOR:
4102 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4104 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4105 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)
4107 out_tc[0] = DotProduct(v1, rsurface.texture->tcgen.parms);
4108 out_tc[1] = DotProduct(v1, rsurface.texture->tcgen.parms + 3);
4111 rsurface.texcoordtexture2f = rsurface.array_generatedtexcoordtexture2f;
4112 rsurface.texcoordtexture2f_bufferobject = 0;
4113 rsurface.texcoordtexture2f_bufferoffset = 0;
4115 case Q3TCGEN_ENVIRONMENT:
4116 // make environment reflections using a spheremap
4117 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4119 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4120 const float *vertex = rsurface.modelvertex3f + 3 * surface->num_firstvertex;
4121 const float *normal = rsurface.modelnormal3f + 3 * surface->num_firstvertex;
4122 float *out_tc = rsurface.array_generatedtexcoordtexture2f + 2 * surface->num_firstvertex;
4123 for (j = 0;j < surface->num_vertices;j++, vertex += 3, normal += 3, out_tc += 2)
4125 float l, d, eyedir[3];
4126 VectorSubtract(rsurface.modelorg, vertex, eyedir);
4127 l = 0.5f / VectorLength(eyedir);
4128 d = DotProduct(normal, eyedir)*2;
4129 out_tc[0] = 0.5f + (normal[1]*d - eyedir[1])*l;
4130 out_tc[1] = 0.5f - (normal[2]*d - eyedir[2])*l;
4133 rsurface.texcoordtexture2f = rsurface.array_generatedtexcoordtexture2f;
4134 rsurface.texcoordtexture2f_bufferobject = 0;
4135 rsurface.texcoordtexture2f_bufferoffset = 0;
4138 // the only tcmod that needs software vertex processing is turbulent, so
4139 // check for it here and apply the changes if needed
4140 // and we only support that as the first one
4141 // (handling a mixture of turbulent and other tcmods would be problematic
4142 // without punting it entirely to a software path)
4143 if (rsurface.texture->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
4145 amplitude = rsurface.texture->tcmods[0].parms[1];
4146 animpos = rsurface.texture->tcmods[0].parms[2] + r_refdef.time * rsurface.texture->tcmods[0].parms[3];
4147 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4149 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4150 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)
4152 out_tc[0] = in_tc[0] + amplitude * sin(((v1[0] + v1[2]) * 1.0 / 1024.0f + animpos) * M_PI * 2);
4153 out_tc[1] = in_tc[1] + amplitude * sin(((v1[1] ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
4156 rsurface.texcoordtexture2f = rsurface.array_generatedtexcoordtexture2f;
4157 rsurface.texcoordtexture2f_bufferobject = 0;
4158 rsurface.texcoordtexture2f_bufferoffset = 0;
4160 rsurface.texcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
4161 rsurface.texcoordlightmap2f_bufferobject = rsurface.modeltexcoordlightmap2f_bufferobject;
4162 rsurface.texcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
4163 R_Mesh_VertexPointer(rsurface.vertex3f, rsurface.vertex3f_bufferobject, rsurface.vertex3f_bufferoffset);
4166 void RSurf_DrawBatch_Simple(int texturenumsurfaces, msurface_t **texturesurfacelist)
4169 const msurface_t *surface = texturesurfacelist[0];
4170 const msurface_t *surface2;
4175 // TODO: lock all array ranges before render, rather than on each surface
4176 if (texturenumsurfaces == 1)
4178 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
4179 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));
4181 else if (r_batchmode.integer == 2)
4183 #define MAXBATCHTRIANGLES 4096
4184 int batchtriangles = 0;
4185 int batchelements[MAXBATCHTRIANGLES*3];
4186 for (i = 0;i < texturenumsurfaces;i = j)
4188 surface = texturesurfacelist[i];
4190 if (surface->num_triangles > MAXBATCHTRIANGLES)
4192 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));
4195 memcpy(batchelements, rsurface.modelelement3i + 3 * surface->num_firsttriangle, surface->num_triangles * sizeof(int[3]));
4196 batchtriangles = surface->num_triangles;
4197 firstvertex = surface->num_firstvertex;
4198 endvertex = surface->num_firstvertex + surface->num_vertices;
4199 for (;j < texturenumsurfaces;j++)
4201 surface2 = texturesurfacelist[j];
4202 if (batchtriangles + surface2->num_triangles > MAXBATCHTRIANGLES)
4204 memcpy(batchelements + batchtriangles * 3, rsurface.modelelement3i + 3 * surface2->num_firsttriangle, surface2->num_triangles * sizeof(int[3]));
4205 batchtriangles += surface2->num_triangles;
4206 firstvertex = min(firstvertex, surface2->num_firstvertex);
4207 endvertex = max(endvertex, surface2->num_firstvertex + surface2->num_vertices);
4209 surface2 = texturesurfacelist[j-1];
4210 numvertices = endvertex - firstvertex;
4211 R_Mesh_Draw(firstvertex, numvertices, batchtriangles, batchelements, 0, 0);
4214 else if (r_batchmode.integer == 1)
4216 for (i = 0;i < texturenumsurfaces;i = j)
4218 surface = texturesurfacelist[i];
4219 for (j = i + 1, surface2 = surface + 1;j < texturenumsurfaces;j++, surface2++)
4220 if (texturesurfacelist[j] != surface2)
4222 surface2 = texturesurfacelist[j-1];
4223 numvertices = surface2->num_firstvertex + surface2->num_vertices - surface->num_firstvertex;
4224 numtriangles = surface2->num_firsttriangle + surface2->num_triangles - surface->num_firsttriangle;
4225 GL_LockArrays(surface->num_firstvertex, numvertices);
4226 R_Mesh_Draw(surface->num_firstvertex, numvertices, numtriangles, (rsurface.modelelement3i + 3 * surface->num_firsttriangle), rsurface.modelelement3i_bufferobject, (sizeof(int[3]) * surface->num_firsttriangle));
4231 for (i = 0;i < texturenumsurfaces;i++)
4233 surface = texturesurfacelist[i];
4234 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
4235 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));
4240 static void RSurf_DrawBatch_WithLightmapSwitching(int texturenumsurfaces, msurface_t **texturesurfacelist, int lightmaptexunit, int deluxemaptexunit)
4244 const msurface_t *surface = texturesurfacelist[0];
4245 const msurface_t *surface2;
4250 // TODO: lock all array ranges before render, rather than on each surface
4251 if (texturenumsurfaces == 1)
4253 R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
4254 if (deluxemaptexunit >= 0)
4255 R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
4256 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
4257 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));
4259 else if (r_batchmode.integer == 2)
4261 #define MAXBATCHTRIANGLES 4096
4262 int batchtriangles = 0;
4263 int batchelements[MAXBATCHTRIANGLES*3];
4264 for (i = 0;i < texturenumsurfaces;i = j)
4266 surface = texturesurfacelist[i];
4267 R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
4268 if (deluxemaptexunit >= 0)
4269 R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
4271 if (surface->num_triangles > MAXBATCHTRIANGLES)
4273 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));
4276 memcpy(batchelements, rsurface.modelelement3i + 3 * surface->num_firsttriangle, surface->num_triangles * sizeof(int[3]));
4277 batchtriangles = surface->num_triangles;
4278 firstvertex = surface->num_firstvertex;
4279 endvertex = surface->num_firstvertex + surface->num_vertices;
4280 for (;j < texturenumsurfaces;j++)
4282 surface2 = texturesurfacelist[j];
4283 if (surface2->lightmaptexture != surface->lightmaptexture || batchtriangles + surface2->num_triangles > MAXBATCHTRIANGLES)
4285 memcpy(batchelements + batchtriangles * 3, rsurface.modelelement3i + 3 * surface2->num_firsttriangle, surface2->num_triangles * sizeof(int[3]));
4286 batchtriangles += surface2->num_triangles;
4287 firstvertex = min(firstvertex, surface2->num_firstvertex);
4288 endvertex = max(endvertex, surface2->num_firstvertex + surface2->num_vertices);
4290 surface2 = texturesurfacelist[j-1];
4291 numvertices = endvertex - firstvertex;
4292 R_Mesh_Draw(firstvertex, numvertices, batchtriangles, batchelements, 0, 0);
4295 else if (r_batchmode.integer == 1)
4298 Con_Printf("%s batch sizes ignoring lightmap:", rsurface.texture->name);
4299 for (i = 0;i < texturenumsurfaces;i = j)
4301 surface = texturesurfacelist[i];
4302 for (j = i + 1, surface2 = surface + 1;j < texturenumsurfaces;j++, surface2++)
4303 if (texturesurfacelist[j] != surface2)
4305 Con_Printf(" %i", j - i);
4308 Con_Printf("%s batch sizes honoring lightmap:", rsurface.texture->name);
4310 for (i = 0;i < texturenumsurfaces;i = j)
4312 surface = texturesurfacelist[i];
4313 R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
4314 if (deluxemaptexunit >= 0)
4315 R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
4316 for (j = i + 1, surface2 = surface + 1;j < texturenumsurfaces;j++, surface2++)
4317 if (texturesurfacelist[j] != surface2 || texturesurfacelist[j]->lightmaptexture != surface->lightmaptexture)
4320 Con_Printf(" %i", j - i);
4322 surface2 = texturesurfacelist[j-1];
4323 numvertices = surface2->num_firstvertex + surface2->num_vertices - surface->num_firstvertex;
4324 numtriangles = surface2->num_firsttriangle + surface2->num_triangles - surface->num_firsttriangle;
4325 GL_LockArrays(surface->num_firstvertex, numvertices);
4326 R_Mesh_Draw(surface->num_firstvertex, numvertices, numtriangles, (rsurface.modelelement3i + 3 * surface->num_firsttriangle), rsurface.modelelement3i_bufferobject, (sizeof(int[3]) * surface->num_firsttriangle));
4334 for (i = 0;i < texturenumsurfaces;i++)
4336 surface = texturesurfacelist[i];
4337 R_Mesh_TexBind(lightmaptexunit, R_GetTexture(surface->lightmaptexture));
4338 if (deluxemaptexunit >= 0)
4339 R_Mesh_TexBind(deluxemaptexunit, R_GetTexture(surface->deluxemaptexture));
4340 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
4341 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));
4346 static void RSurf_DrawBatch_ShowSurfaces(int texturenumsurfaces, msurface_t **texturesurfacelist)
4349 int texturesurfaceindex;
4350 if (r_showsurfaces.integer == 2)
4352 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4354 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4355 for (j = 0;j < surface->num_triangles;j++)
4357 float f = ((j + surface->num_firsttriangle) & 31) * (1.0f / 31.0f) * r_view.colorscale;
4358 GL_Color(f, f, f, 1);
4359 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)));
4365 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4367 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4368 int k = (int)(((size_t)surface) / sizeof(msurface_t));
4369 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);
4370 GL_LockArrays(surface->num_firstvertex, surface->num_vertices);
4371 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));
4376 static void RSurf_DrawBatch_GL11_ApplyFog(int texturenumsurfaces, msurface_t **texturesurfacelist)
4378 int texturesurfaceindex;
4382 if (rsurface.lightmapcolor4f)
4384 // generate color arrays for the surfaces in this list
4385 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4387 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4388 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)
4390 f = FogPoint_Model(v);
4400 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4402 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4403 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)
4405 f = FogPoint_Model(v);
4413 rsurface.lightmapcolor4f = rsurface.array_color4f;
4414 rsurface.lightmapcolor4f_bufferobject = 0;
4415 rsurface.lightmapcolor4f_bufferoffset = 0;
4418 static void RSurf_DrawBatch_GL11_ApplyColor(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a)
4420 int texturesurfaceindex;
4423 if (!rsurface.lightmapcolor4f)
4425 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4427 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4428 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)
4436 rsurface.lightmapcolor4f = rsurface.array_color4f;
4437 rsurface.lightmapcolor4f_bufferobject = 0;
4438 rsurface.lightmapcolor4f_bufferoffset = 0;
4441 static void RSurf_DrawBatch_GL11_Lightmap(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
4444 rsurface.lightmapcolor4f = NULL;
4445 rsurface.lightmapcolor4f_bufferobject = 0;
4446 rsurface.lightmapcolor4f_bufferoffset = 0;
4447 if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
4448 if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
4449 R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
4450 GL_Color(r, g, b, a);
4451 RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist, 0, -1);
4454 static void RSurf_DrawBatch_GL11_Unlit(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
4456 // TODO: optimize applyfog && applycolor case
4457 // just apply fog if necessary, and tint the fog color array if necessary
4458 rsurface.lightmapcolor4f = NULL;
4459 rsurface.lightmapcolor4f_bufferobject = 0;
4460 rsurface.lightmapcolor4f_bufferoffset = 0;
4461 if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
4462 if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
4463 R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
4464 GL_Color(r, g, b, a);
4465 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
4468 static void RSurf_DrawBatch_GL11_VertexColor(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
4470 int texturesurfaceindex;
4474 if (texturesurfacelist[0]->lightmapinfo && texturesurfacelist[0]->lightmapinfo->stainsamples)
4476 // generate color arrays for the surfaces in this list
4477 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4479 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4480 for (i = 0, c = rsurface.array_color4f + 4 * surface->num_firstvertex;i < surface->num_vertices;i++, c += 4)
4482 if (surface->lightmapinfo->samples)
4484 const unsigned char *lm = surface->lightmapinfo->samples + (rsurface.modellightmapoffsets + surface->num_firstvertex)[i];
4485 float scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[0]] * (1.0f / 32768.0f);
4486 VectorScale(lm, scale, c);
4487 if (surface->lightmapinfo->styles[1] != 255)
4489 int size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
4491 scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[1]] * (1.0f / 32768.0f);
4492 VectorMA(c, scale, lm, c);
4493 if (surface->lightmapinfo->styles[2] != 255)
4496 scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[2]] * (1.0f / 32768.0f);
4497 VectorMA(c, scale, lm, c);
4498 if (surface->lightmapinfo->styles[3] != 255)
4501 scale = r_refdef.lightstylevalue[surface->lightmapinfo->styles[3]] * (1.0f / 32768.0f);
4502 VectorMA(c, scale, lm, c);
4512 rsurface.lightmapcolor4f = rsurface.array_color4f;
4513 rsurface.lightmapcolor4f_bufferobject = 0;
4514 rsurface.lightmapcolor4f_bufferoffset = 0;
4518 rsurface.lightmapcolor4f = rsurface.modellightmapcolor4f;
4519 rsurface.lightmapcolor4f_bufferobject = rsurface.modellightmapcolor4f_bufferobject;
4520 rsurface.lightmapcolor4f_bufferoffset = rsurface.modellightmapcolor4f_bufferoffset;
4522 if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
4523 if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
4524 R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
4525 GL_Color(r, g, b, a);
4526 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
4529 static void RSurf_DrawBatch_GL11_VertexShade(int texturenumsurfaces, msurface_t **texturesurfacelist, float r, float g, float b, float a, qboolean applycolor, qboolean applyfog)
4531 int texturesurfaceindex;
4535 vec3_t ambientcolor;
4536 vec3_t diffusecolor;
4540 VectorCopy(rsurface.modellight_lightdir, lightdir);
4541 ambientcolor[0] = rsurface.modellight_ambient[0] * r * 0.5f;
4542 ambientcolor[1] = rsurface.modellight_ambient[1] * g * 0.5f;
4543 ambientcolor[2] = rsurface.modellight_ambient[2] * b * 0.5f;
4544 diffusecolor[0] = rsurface.modellight_diffuse[0] * r * 0.5f;
4545 diffusecolor[1] = rsurface.modellight_diffuse[1] * g * 0.5f;
4546 diffusecolor[2] = rsurface.modellight_diffuse[2] * b * 0.5f;
4547 if (VectorLength2(diffusecolor) > 0)
4549 // generate color arrays for the surfaces in this list
4550 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4552 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4553 int numverts = surface->num_vertices;
4554 v = rsurface.vertex3f + 3 * surface->num_firstvertex;
4555 c2 = rsurface.normal3f + 3 * surface->num_firstvertex;
4556 c = rsurface.array_color4f + 4 * surface->num_firstvertex;
4557 // q3-style directional shading
4558 for (i = 0;i < numverts;i++, v += 3, c2 += 3, c += 4)
4560 if ((f = DotProduct(c2, lightdir)) > 0)
4561 VectorMA(ambientcolor, f, diffusecolor, c);
4563 VectorCopy(ambientcolor, c);
4572 rsurface.lightmapcolor4f = rsurface.array_color4f;
4573 rsurface.lightmapcolor4f_bufferobject = 0;
4574 rsurface.lightmapcolor4f_bufferoffset = 0;
4578 r = ambientcolor[0];
4579 g = ambientcolor[1];
4580 b = ambientcolor[2];
4581 rsurface.lightmapcolor4f = NULL;
4582 rsurface.lightmapcolor4f_bufferobject = 0;
4583 rsurface.lightmapcolor4f_bufferoffset = 0;
4585 if (applyfog) RSurf_DrawBatch_GL11_ApplyFog(texturenumsurfaces, texturesurfacelist);
4586 if (applycolor) RSurf_DrawBatch_GL11_ApplyColor(texturenumsurfaces, texturesurfacelist, r, g, b, a);
4587 R_Mesh_ColorPointer(rsurface.lightmapcolor4f, rsurface.lightmapcolor4f_bufferobject, rsurface.lightmapcolor4f_bufferoffset);
4588 GL_Color(r, g, b, a);
4589 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
4592 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, msurface_t **texturesurfacelist)
4594 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
4595 GL_PolygonOffset(rsurface.texture->currentpolygonfactor, rsurface.texture->currentpolygonoffset);
4596 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
4597 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
4598 if (rsurface.mode != RSURFMODE_SHOWSURFACES)
4600 rsurface.mode = RSURFMODE_SHOWSURFACES;
4602 GL_BlendFunc(GL_ONE, GL_ZERO);
4603 R_Mesh_ColorPointer(NULL, 0, 0);
4604 R_Mesh_ResetTextureState();
4606 RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
4607 RSurf_DrawBatch_ShowSurfaces(texturenumsurfaces, texturesurfacelist);
4610 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, msurface_t **texturesurfacelist)
4612 // transparent sky would be ridiculous
4613 if ((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED))
4615 if (rsurface.mode != RSURFMODE_SKY)
4617 if (rsurface.mode == RSURFMODE_GLSL)
4619 qglUseProgramObjectARB(0);CHECKGLERROR
4621 rsurface.mode = RSURFMODE_SKY;
4625 skyrendernow = false;
4627 // restore entity matrix
4628 R_Mesh_Matrix(&rsurface.matrix);
4630 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
4631 GL_PolygonOffset(rsurface.texture->currentpolygonfactor, rsurface.texture->currentpolygonoffset);
4632 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
4633 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
4635 // LordHavoc: HalfLife maps have freaky skypolys so don't use
4636 // skymasking on them, and Quake3 never did sky masking (unlike
4637 // software Quake and software Quake2), so disable the sky masking
4638 // in Quake3 maps as it causes problems with q3map2 sky tricks,
4639 // and skymasking also looks very bad when noclipping outside the
4640 // level, so don't use it then either.
4641 if (r_refdef.worldmodel && r_refdef.worldmodel->type == mod_brushq1 && r_q1bsp_skymasking.integer && !r_viewcache.world_novis)
4643 GL_Color(r_refdef.fogcolor[0] * r_view.colorscale, r_refdef.fogcolor[1] * r_view.colorscale, r_refdef.fogcolor[2] * r_view.colorscale, 1);
4644 R_Mesh_ColorPointer(NULL, 0, 0);
4645 R_Mesh_ResetTextureState();
4646 if (skyrendermasked)
4648 // depth-only (masking)
4649 GL_ColorMask(0,0,0,0);
4650 // just to make sure that braindead drivers don't draw
4651 // anything despite that colormask...
4652 GL_BlendFunc(GL_ZERO, GL_ONE);
4657 GL_BlendFunc(GL_ONE, GL_ZERO);
4659 RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
4660 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
4661 if (skyrendermasked)
4662 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
4666 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, msurface_t **texturesurfacelist)
4668 if (rsurface.mode != RSURFMODE_GLSL)
4670 rsurface.mode = RSURFMODE_GLSL;
4671 R_Mesh_ResetTextureState();
4674 R_SetupSurfaceShader(vec3_origin, rsurface.lightmode == 2, 1, 1, rsurface.texture->specularscale);
4675 if (!r_glsl_permutation)
4678 if (rsurface.lightmode == 2)
4679 RSurf_PrepareVerticesForBatch(true, r_glsl_permutation->loc_Texture_Normal >= 0, texturenumsurfaces, texturesurfacelist);
4681 RSurf_PrepareVerticesForBatch(r_glsl_permutation->loc_Texture_Normal >= 0, r_glsl_permutation->loc_Texture_Normal >= 0, texturenumsurfaces, texturesurfacelist);
4682 R_Mesh_TexCoordPointer(0, 2, rsurface.texcoordtexture2f, rsurface.texcoordtexture2f_bufferobject, rsurface.texcoordtexture2f_bufferoffset);
4683 R_Mesh_TexCoordPointer(1, 3, rsurface.svector3f, rsurface.svector3f_bufferobject, rsurface.svector3f_bufferoffset);
4684 R_Mesh_TexCoordPointer(2, 3, rsurface.tvector3f, rsurface.tvector3f_bufferobject, rsurface.tvector3f_bufferoffset);
4685 R_Mesh_TexCoordPointer(3, 3, rsurface.normal3f, rsurface.normal3f_bufferobject, rsurface.normal3f_bufferoffset);
4686 R_Mesh_TexCoordPointer(4, 2, rsurface.modeltexcoordlightmap2f, rsurface.modeltexcoordlightmap2f_bufferobject, rsurface.modeltexcoordlightmap2f_bufferoffset);
4688 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]);
4689 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT)
4691 R_Mesh_TexBind(7, R_GetTexture(r_texture_grey128));
4692 if (r_glsl_permutation->loc_Texture_Deluxemap >= 0)
4693 R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
4694 R_Mesh_ColorPointer(NULL, 0, 0);
4696 else if (rsurface.uselightmaptexture)
4698 R_Mesh_TexBind(7, R_GetTexture(texturesurfacelist[0]->lightmaptexture));
4699 if (r_glsl_permutation->loc_Texture_Deluxemap >= 0)
4700 R_Mesh_TexBind(8, R_GetTexture(texturesurfacelist[0]->deluxemaptexture));
4701 R_Mesh_ColorPointer(NULL, 0, 0);
4705 R_Mesh_TexBind(7, R_GetTexture(r_texture_white));
4706 if (r_glsl_permutation->loc_Texture_Deluxemap >= 0)
4707 R_Mesh_TexBind(8, R_GetTexture(r_texture_blanknormalmap));
4708 R_Mesh_ColorPointer(rsurface.modellightmapcolor4f, rsurface.modellightmapcolor4f_bufferobject, rsurface.modellightmapcolor4f_bufferoffset);
4711 if (rsurface.uselightmaptexture && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT))
4712 RSurf_DrawBatch_WithLightmapSwitching(texturenumsurfaces, texturesurfacelist, 7, r_glsl_permutation->loc_Texture_Deluxemap >= 0 ? 8 : -1);
4714 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
4715 if (rsurface.texture->backgroundnumskinframes && !(rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED))
4720 static void R_DrawTextureSurfaceList_GL13(int texturenumsurfaces, msurface_t **texturesurfacelist)
4722 // OpenGL 1.3 path - anything not completely ancient
4723 int texturesurfaceindex;
4724 qboolean applycolor;
4728 const texturelayer_t *layer;
4729 if (rsurface.mode != RSURFMODE_MULTIPASS)
4730 rsurface.mode = RSURFMODE_MULTIPASS;
4731 RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist);
4732 for (layerindex = 0, layer = rsurface.texture->currentlayers;layerindex < rsurface.texture->currentnumlayers;layerindex++, layer++)
4735 int layertexrgbscale;
4736 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
4738 if (layerindex == 0)
4742 GL_AlphaTest(false);
4743 qglDepthFunc(GL_EQUAL);CHECKGLERROR
4746 GL_DepthMask(layer->depthmask);
4747 GL_BlendFunc(layer->blendfunc1, layer->blendfunc2);
4748 if ((layer->color[0] > 2 || layer->color[1] > 2 || layer->color[2] > 2) && (gl_combine.integer || layer->depthmask))
4750 layertexrgbscale = 4;
4751 VectorScale(layer->color, 0.25f, layercolor);
4753 else if ((layer->color[0] > 1 || layer->color[1] > 1 || layer->color[2] > 1) && (gl_combine.integer || layer->depthmask))
4755 layertexrgbscale = 2;
4756 VectorScale(layer->color, 0.5f, layercolor);
4760 layertexrgbscale = 1;
4761 VectorScale(layer->color, 1.0f, layercolor);
4763 layercolor[3] = layer->color[3];
4764 applycolor = layercolor[0] != 1 || layercolor[1] != 1 || layercolor[2] != 1 || layercolor[3] != 1;
4765 R_Mesh_ColorPointer(NULL, 0, 0);
4766 applyfog = (layer->flags & TEXTURELAYERFLAG_FOGDARKEN) != 0;
4767 switch (layer->type)
4769 case TEXTURELAYERTYPE_LITTEXTURE:
4770 memset(&m, 0, sizeof(m));
4771 m.tex[0] = R_GetTexture(r_texture_white);
4772 m.pointer_texcoord[0] = rsurface.modeltexcoordlightmap2f;
4773 m.pointer_texcoord_bufferobject[0] = rsurface.modeltexcoordlightmap2f_bufferobject;
4774 m.pointer_texcoord_bufferoffset[0] = rsurface.modeltexcoordlightmap2f_bufferoffset;
4775 m.tex[1] = R_GetTexture(layer->texture);
4776 m.texmatrix[1] = layer->texmatrix;
4777 m.texrgbscale[1] = layertexrgbscale;
4778 m.pointer_texcoord[1] = rsurface.texcoordtexture2f;
4779 m.pointer_texcoord_bufferobject[1] = rsurface.texcoordtexture2f_bufferobject;
4780 m.pointer_texcoord_bufferoffset[1] = rsurface.texcoordtexture2f_bufferoffset;
4781 R_Mesh_TextureState(&m);
4782 if (rsurface.lightmode == 2)
4783 RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
4784 else if (rsurface.uselightmaptexture)
4785 RSurf_DrawBatch_GL11_Lightmap(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
4787 RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
4789 case TEXTURELAYERTYPE_TEXTURE:
4790 memset(&m, 0, sizeof(m));
4791 m.tex[0] = R_GetTexture(layer->texture);
4792 m.texmatrix[0] = layer->texmatrix;
4793 m.texrgbscale[0] = layertexrgbscale;
4794 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
4795 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
4796 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
4797 R_Mesh_TextureState(&m);
4798 RSurf_DrawBatch_GL11_Unlit(texturenumsurfaces, texturesurfacelist, layercolor[0], layercolor[1], layercolor[2], layercolor[3], applycolor, applyfog);
4800 case TEXTURELAYERTYPE_FOG:
4801 memset(&m, 0, sizeof(m));
4802 m.texrgbscale[0] = layertexrgbscale;
4805 m.tex[0] = R_GetTexture(layer->texture);
4806 m.texmatrix[0] = layer->texmatrix;
4807 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
4808 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
4809 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
4811 R_Mesh_TextureState(&m);
4812 // generate a color array for the fog pass
4813 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
4814 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4818 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4819 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)
4821 f = 1 - FogPoint_Model(v);
4822 c[0] = layercolor[0];
4823 c[1] = layercolor[1];
4824 c[2] = layercolor[2];
4825 c[3] = f * layercolor[3];
4828 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
4831 Con_Printf("R_DrawTextureSurfaceList: unknown layer type %i\n", layer->type);
4833 GL_LockArrays(0, 0);
4836 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
4838 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
4839 GL_AlphaTest(false);
4843 static void R_DrawTextureSurfaceList_GL11(int texturenumsurfaces, msurface_t **texturesurfacelist)
4845 // OpenGL 1.1 - crusty old voodoo path
4846 int texturesurfaceindex;
4850 const texturelayer_t *layer;
4851 if (rsurface.mode != RSURFMODE_MULTIPASS)
4852 rsurface.mode = RSURFMODE_MULTIPASS;
4853 RSurf_PrepareVerticesForBatch(true, false, texturenumsurfaces, texturesurfacelist);
4854 for (layerindex = 0, layer = rsurface.texture->currentlayers;layerindex < rsurface.texture->currentnumlayers;layerindex++, layer++)
4856 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
4858 if (layerindex == 0)
4862 GL_AlphaTest(false);
4863 qglDepthFunc(GL_EQUAL);CHECKGLERROR
4866 GL_DepthMask(layer->depthmask);
4867 GL_BlendFunc(layer->blendfunc1, layer->blendfunc2);
4868 R_Mesh_ColorPointer(NULL, 0, 0);
4869 applyfog = (layer->flags & TEXTURELAYERFLAG_FOGDARKEN) != 0;
4870 switch (layer->type)
4872 case TEXTURELAYERTYPE_LITTEXTURE:
4873 if (layer->blendfunc1 == GL_ONE && layer->blendfunc2 == GL_ZERO)
4875 // two-pass lit texture with 2x rgbscale
4876 // first the lightmap pass
4877 memset(&m, 0, sizeof(m));
4878 m.tex[0] = R_GetTexture(r_texture_white);
4879 m.pointer_texcoord[0] = rsurface.modeltexcoordlightmap2f;
4880 m.pointer_texcoord_bufferobject[0] = rsurface.modeltexcoordlightmap2f_bufferobject;
4881 m.pointer_texcoord_bufferoffset[0] = rsurface.modeltexcoordlightmap2f_bufferoffset;
4882 R_Mesh_TextureState(&m);
4883 if (rsurface.lightmode == 2)
4884 RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
4885 else if (rsurface.uselightmaptexture)
4886 RSurf_DrawBatch_GL11_Lightmap(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
4888 RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
4889 GL_LockArrays(0, 0);
4890 // then apply the texture to it
4891 GL_BlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
4892 memset(&m, 0, sizeof(m));
4893 m.tex[0] = R_GetTexture(layer->texture);
4894 m.texmatrix[0] = layer->texmatrix;
4895 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
4896 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
4897 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
4898 R_Mesh_TextureState(&m);
4899 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);
4903 // single pass vertex-lighting-only texture with 1x rgbscale and transparency support
4904 memset(&m, 0, sizeof(m));
4905 m.tex[0] = R_GetTexture(layer->texture);
4906 m.texmatrix[0] = layer->texmatrix;
4907 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
4908 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
4909 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
4910 R_Mesh_TextureState(&m);
4911 if (rsurface.lightmode == 2)
4912 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);
4914 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);
4917 case TEXTURELAYERTYPE_TEXTURE:
4918 // singletexture unlit texture with transparency support
4919 memset(&m, 0, sizeof(m));
4920 m.tex[0] = R_GetTexture(layer->texture);
4921 m.texmatrix[0] = layer->texmatrix;
4922 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
4923 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
4924 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
4925 R_Mesh_TextureState(&m);
4926 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);
4928 case TEXTURELAYERTYPE_FOG:
4929 // singletexture fogging
4930 R_Mesh_ColorPointer(rsurface.array_color4f, 0, 0);
4933 memset(&m, 0, sizeof(m));
4934 m.tex[0] = R_GetTexture(layer->texture);
4935 m.texmatrix[0] = layer->texmatrix;
4936 m.pointer_texcoord[0] = rsurface.texcoordtexture2f;
4937 m.pointer_texcoord_bufferobject[0] = rsurface.texcoordtexture2f_bufferobject;
4938 m.pointer_texcoord_bufferoffset[0] = rsurface.texcoordtexture2f_bufferoffset;
4939 R_Mesh_TextureState(&m);
4942 R_Mesh_ResetTextureState();
4943 // generate a color array for the fog pass
4944 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
4948 const msurface_t *surface = texturesurfacelist[texturesurfaceindex];
4949 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)
4951 f = 1 - FogPoint_Model(v);
4952 c[0] = layer->color[0];
4953 c[1] = layer->color[1];
4954 c[2] = layer->color[2];
4955 c[3] = f * layer->color[3];
4958 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
4961 Con_Printf("R_DrawTextureSurfaceList: unknown layer type %i\n", layer->type);
4963 GL_LockArrays(0, 0);
4966 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
4968 qglDepthFunc(GL_LEQUAL);CHECKGLERROR
4969 GL_AlphaTest(false);
4973 static void R_DrawTextureSurfaceList(int texturenumsurfaces, msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly)
4975 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW)
4977 rsurface.rtlight = NULL;
4981 if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
4983 if (rsurface.mode != RSURFMODE_MULTIPASS)
4984 rsurface.mode = RSURFMODE_MULTIPASS;
4985 if (r_depthfirst.integer == 3)
4987 int i = (int)(texturesurfacelist[0] - rsurface.modelsurfaces);
4988 GL_Color(((i >> 6) & 7) / 7.0f, ((i >> 3) & 7) / 7.0f, (i & 7) / 7.0f,1);
4992 GL_ColorMask(0,0,0,0);
4995 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
4996 GL_PolygonOffset(rsurface.texture->currentpolygonfactor, rsurface.texture->currentpolygonoffset);
4997 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
4999 GL_BlendFunc(GL_ONE, GL_ZERO);
5001 GL_AlphaTest(false);
5002 R_Mesh_ColorPointer(NULL, 0, 0);
5003 R_Mesh_ResetTextureState();
5004 RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
5005 RSurf_DrawBatch_Simple(texturenumsurfaces, texturesurfacelist);
5006 GL_ColorMask(r_view.colormask[0], r_view.colormask[1], r_view.colormask[2], 1);
5007 r_refdef.stats.entities_surfaces += texturenumsurfaces;
5009 else if (r_depthfirst.integer == 3)
5011 else if (r_showsurfaces.integer)
5013 if (rsurface.mode != RSURFMODE_MULTIPASS)
5014 rsurface.mode = RSURFMODE_MULTIPASS;
5015 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
5016 GL_PolygonOffset(rsurface.texture->currentpolygonfactor, rsurface.texture->currentpolygonoffset);
5018 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
5019 GL_BlendFunc(GL_ONE, GL_ZERO);
5020 GL_DepthMask(writedepth);
5022 GL_AlphaTest(false);
5023 R_Mesh_ColorPointer(NULL, 0, 0);
5024 R_Mesh_ResetTextureState();
5025 RSurf_PrepareVerticesForBatch(false, false, texturenumsurfaces, texturesurfacelist);
5026 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist);
5027 r_refdef.stats.entities_surfaces += texturenumsurfaces;
5029 else if (gl_lightmaps.integer)
5032 if (rsurface.mode != RSURFMODE_MULTIPASS)
5033 rsurface.mode = RSURFMODE_MULTIPASS;
5034 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
5036 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
5037 GL_BlendFunc(GL_ONE, GL_ZERO);
5038 GL_DepthMask(writedepth);
5040 GL_AlphaTest(false);
5041 // use lightmode 0 (fullbright or lightmap) or 2 (model lighting)
5042 rsurface.lightmode = ((rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || rsurface.modeltexcoordlightmap2f != NULL) ? 0 : 2;
5043 R_Mesh_ColorPointer(NULL, 0, 0);
5044 memset(&m, 0, sizeof(m));
5045 m.tex[0] = R_GetTexture(r_texture_white);
5046 m.pointer_texcoord[0] = rsurface.modeltexcoordlightmap2f;
5047 m.pointer_texcoord_bufferobject[0] = rsurface.modeltexcoordlightmap2f_bufferobject;
5048 m.pointer_texcoord_bufferoffset[0] = rsurface.modeltexcoordlightmap2f_bufferoffset;
5049 R_Mesh_TextureState(&m);
5050 RSurf_PrepareVerticesForBatch(rsurface.lightmode == 2, false, texturenumsurfaces, texturesurfacelist);
5051 if (rsurface.lightmode == 2)
5052 RSurf_DrawBatch_GL11_VertexShade(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
5053 else if (rsurface.uselightmaptexture)
5054 RSurf_DrawBatch_GL11_Lightmap(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
5056 RSurf_DrawBatch_GL11_VertexColor(texturenumsurfaces, texturesurfacelist, 1, 1, 1, 1, false, false);
5057 r_refdef.stats.entities_surfaces += texturenumsurfaces;
5059 else if (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY)
5061 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
5062 r_refdef.stats.entities_surfaces += texturenumsurfaces;
5064 else if (rsurface.texture->currentnumlayers)
5066 // write depth for anything we skipped on the depth-only pass earlier
5067 if (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST)
5069 GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
5070 GL_PolygonOffset(rsurface.texture->currentpolygonfactor, rsurface.texture->currentpolygonoffset);
5071 GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
5072 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : GL_FRONT); // quake is backwards, this culls back faces
5073 GL_BlendFunc(rsurface.texture->currentlayers[0].blendfunc1, rsurface.texture->currentlayers[0].blendfunc2);
5074 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
5075 GL_AlphaTest((rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
5076 // use lightmode 0 (fullbright or lightmap) or 2 (model lighting)
5077 rsurface.lightmode = ((rsurface.texture->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || rsurface.modeltexcoordlightmap2f != NULL) ? 0 : 2;
5078 if (r_glsl.integer && gl_support_fragment_shader)
5079 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist);
5080 else if (gl_combine.integer && r_textureunits.integer >= 2)
5081 R_DrawTextureSurfaceList_GL13(texturenumsurfaces, texturesurfacelist);
5083 R_DrawTextureSurfaceList_GL11(texturenumsurfaces, texturesurfacelist);
5084 r_refdef.stats.entities_surfaces += texturenumsurfaces;
5087 GL_LockArrays(0, 0);
5090 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5093 int texturenumsurfaces, endsurface;
5095 msurface_t *surface;
5096 msurface_t *texturesurfacelist[1024];
5098 // if the model is static it doesn't matter what value we give for
5099 // wantnormals and wanttangents, so this logic uses only rules applicable
5100 // to a model, knowing that they are meaningless otherwise
5101 if (ent == r_refdef.worldentity)
5102 RSurf_ActiveWorldEntity();
5103 else if ((ent->effects & EF_FULLBRIGHT) || r_showsurfaces.integer || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f))
5104 RSurf_ActiveModelEntity(ent, false, false);
5106 RSurf_ActiveModelEntity(ent, true, r_glsl.integer && gl_support_fragment_shader);
5108 for (i = 0;i < numsurfaces;i = j)
5111 surface = rsurface.modelsurfaces + surfacelist[i];
5112 texture = surface->texture;
5113 R_UpdateTextureInfo(ent, texture);
5114 rsurface.texture = texture->currentframe;
5115 rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
5116 // scan ahead until we find a different texture
5117 endsurface = min(i + 1024, numsurfaces);
5118 texturenumsurfaces = 0;
5119 texturesurfacelist[texturenumsurfaces++] = surface;
5120 for (;j < endsurface;j++)
5122 surface = rsurface.modelsurfaces + surfacelist[j];
5123 if (texture != surface->texture || rsurface.uselightmaptexture != (surface->lightmaptexture != NULL))
5125 texturesurfacelist[texturenumsurfaces++] = surface;
5127 // render the range of surfaces
5128 R_DrawTextureSurfaceList(texturenumsurfaces, texturesurfacelist, true, false);
5134 void R_QueueSurfaceList(entity_render_t *ent, int numsurfaces, msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly)
5137 vec3_t tempcenter, center;
5139 // break the surface list down into batches by texture and use of lightmapping
5140 for (i = 0;i < numsurfaces;i = j)
5143 // texture is the base texture pointer, rsurface.texture is the
5144 // current frame/skin the texture is directing us to use (for example
5145 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
5146 // use skin 1 instead)
5147 texture = surfacelist[i]->texture;
5148 rsurface.texture = texture->currentframe;
5149 rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
5150 if (!(rsurface.texture->currentmaterialflags & flagsmask))
5152 // if this texture is not the kind we want, skip ahead to the next one
5153 for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
5157 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
5159 // transparent surfaces get pushed off into the transparent queue
5160 const msurface_t *surface = surfacelist[i];
5163 tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
5164 tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
5165 tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
5166 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
5167 R_MeshQueue_AddTransparent(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST ? r_view.origin : center, R_DrawSurface_TransparentCallback, ent, surface - rsurface.modelsurfaces, rsurface.rtlight);
5171 // simply scan ahead until we find a different texture or lightmap state
5172 for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.uselightmaptexture == (surfacelist[j]->lightmaptexture != NULL);j++)
5174 // render the range of surfaces
5175 R_DrawTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly);
5180 float locboxvertex3f[6*4*3] =
5182 1,0,1, 1,0,0, 1,1,0, 1,1,1,
5183 0,1,1, 0,1,0, 0,0,0, 0,0,1,
5184 1,1,1, 1,1,0, 0,1,0, 0,1,1,
5185 0,0,1, 0,0,0, 1,0,0, 1,0,1,
5186 0,0,1, 1,0,1, 1,1,1, 0,1,1,
5187 1,0,0, 0,0,0, 0,1,0, 1,1,0
5190 int locboxelement3i[6*2*3] =
5200 void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
5203 cl_locnode_t *loc = (cl_locnode_t *)ent;
5205 float vertex3f[6*4*3];
5207 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5208 GL_DepthMask(false);
5209 GL_DepthRange(0, 1);
5210 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
5212 GL_CullFace(GL_NONE);
5213 R_Mesh_Matrix(&identitymatrix);
5215 R_Mesh_VertexPointer(vertex3f, 0, 0);
5216 R_Mesh_ColorPointer(NULL, 0, 0);
5217 R_Mesh_ResetTextureState();
5220 GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_view.colorscale,
5221 ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_view.colorscale,
5222 ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_view.colorscale,
5223 surfacelist[0] < 0 ? 0.5f : 0.125f);
5225 if (VectorCompare(loc->mins, loc->maxs))
5227 VectorSet(size, 2, 2, 2);
5228 VectorMA(loc->mins, -0.5f, size, mins);
5232 VectorCopy(loc->mins, mins);
5233 VectorSubtract(loc->maxs, loc->mins, size);
5236 for (i = 0;i < 6*4*3;)
5237 for (j = 0;j < 3;j++, i++)
5238 vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
5240 R_Mesh_Draw(0, 6*4, 6*2, locboxelement3i, 0, 0);
5243 void R_DrawLocs(void)
5246 cl_locnode_t *loc, *nearestloc;
5248 nearestloc = CL_Locs_FindNearest(cl.movement_origin);
5249 for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
5251 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
5252 R_MeshQueue_AddTransparent(center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
5256 void R_DrawCollisionBrushes(entity_render_t *ent)
5260 msurface_t *surface;
5261 model_t *model = ent->model;
5262 if (!model->brush.num_brushes)
5265 R_Mesh_ColorPointer(NULL, 0, 0);
5266 R_Mesh_ResetTextureState();
5267 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
5268 GL_DepthMask(false);
5269 GL_DepthRange(0, 1);
5270 GL_DepthTest(!r_showdisabledepthtest.integer);
5271 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
5272 for (i = 0, brush = model->brush.data_brushes + model->firstmodelbrush;i < model->nummodelbrushes;i++, brush++)
5273 if (brush->colbrushf && brush->colbrushf->numtriangles)
5274 R_DrawCollisionBrush(brush->colbrushf);
5275 for (i = 0, surface = model->data_surfaces + model->firstmodelsurface;i < model->nummodelsurfaces;i++, surface++)
5276 if (surface->num_collisiontriangles)
5277 R_DrawCollisionSurface(ent, surface);
5278 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
5281 void R_DrawTrianglesAndNormals(entity_render_t *ent, qboolean drawtris, qboolean drawnormals, int flagsmask)
5284 const int *elements;
5285 msurface_t *surface;
5286 model_t *model = ent->model;
5289 GL_DepthRange(0, 1);
5290 GL_DepthTest(!r_showdisabledepthtest.integer);
5291 GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
5293 GL_BlendFunc(GL_ONE, GL_ZERO);
5294 R_Mesh_ColorPointer(NULL, 0, 0);
5295 R_Mesh_ResetTextureState();
5296 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
5298 if (ent == r_refdef.worldentity && !r_viewcache.world_surfacevisible[j])
5300 rsurface.texture = surface->texture->currentframe;
5301 if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
5303 RSurf_PrepareVerticesForBatch(true, true, 1, &surface);
5306 if (!rsurface.texture->currentlayers->depthmask)
5307 GL_Color(r_showtris.value * r_view.colorscale, 0, 0, 1);
5308 else if (ent == r_refdef.worldentity)
5309 GL_Color(r_showtris.value * r_view.colorscale, r_showtris.value * r_view.colorscale, r_showtris.value * r_view.colorscale, 1);
5311 GL_Color(0, r_showtris.value * r_view.colorscale, 0, 1);
5312 elements = (ent->model->surfmesh.data_element3i + 3 * surface->num_firsttriangle);
5315 for (k = 0;k < surface->num_triangles;k++, elements += 3)
5317 #define GLVERTEXELEMENT(n) qglVertex3f(rsurface.vertex3f[elements[n]*3+0], rsurface.vertex3f[elements[n]*3+1], rsurface.vertex3f[elements[n]*3+2])
5318 GLVERTEXELEMENT(0);GLVERTEXELEMENT(1);
5319 GLVERTEXELEMENT(1);GLVERTEXELEMENT(2);
5320 GLVERTEXELEMENT(2);GLVERTEXELEMENT(0);
5327 GL_Color(r_shownormals.value * r_view.colorscale, 0, 0, 1);
5329 for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
5331 VectorCopy(rsurface.vertex3f + l * 3, v);
5332 qglVertex3f(v[0], v[1], v[2]);
5333 VectorMA(v, 8, rsurface.svector3f + l * 3, v);
5334 qglVertex3f(v[0], v[1], v[2]);
5338 GL_Color(0, 0, r_shownormals.value * r_view.colorscale, 1);
5340 for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
5342 VectorCopy(rsurface.vertex3f + l * 3, v);
5343 qglVertex3f(v[0], v[1], v[2]);
5344 VectorMA(v, 8, rsurface.tvector3f + l * 3, v);
5345 qglVertex3f(v[0], v[1], v[2]);
5349 GL_Color(0, r_shownormals.value * r_view.colorscale, 0, 1);
5351 for (k = 0, l = surface->num_firstvertex;k < surface->num_vertices;k++, l++)
5353 VectorCopy(rsurface.vertex3f + l * 3, v);
5354 qglVertex3f(v[0], v[1], v[2]);
5355 VectorMA(v, 8, rsurface.normal3f + l * 3, v);
5356 qglVertex3f(v[0], v[1], v[2]);
5363 rsurface.texture = NULL;
5366 extern void R_BuildLightMap(const entity_render_t *ent, msurface_t *surface);
5367 void R_DrawWorldSurfaces(qboolean skysurfaces, qboolean writedepth, qboolean depthonly)
5369 int i, j, endj, f, flagsmask;
5370 int counttriangles = 0;
5371 msurface_t *surface, **surfacechain;
5373 model_t *model = r_refdef.worldmodel;
5374 const int maxsurfacelist = 1024;
5375 int numsurfacelist = 0;
5376 msurface_t *surfacelist[1024];
5380 RSurf_ActiveWorldEntity();
5382 // update light styles
5383 if (!skysurfaces && !depthonly && model->brushq1.light_styleupdatechains)
5385 for (i = 0;i < model->brushq1.light_styles;i++)
5387 if (model->brushq1.light_stylevalue[i] != r_refdef.lightstylevalue[model->brushq1.light_style[i]])
5389 model->brushq1.light_stylevalue[i] = r_refdef.lightstylevalue[model->brushq1.light_style[i]];
5390 if ((surfacechain = model->brushq1.light_styleupdatechains[i]))
5391 for (;(surface = *surfacechain);surfacechain++)
5392 surface->cached_dlight = true;
5397 R_UpdateAllTextureInfo(r_refdef.worldentity);
5398 flagsmask = skysurfaces ? MATERIALFLAG_SKY : (MATERIALFLAG_WATER | MATERIALFLAG_WALL);
5401 rsurface.uselightmaptexture = false;
5402 rsurface.texture = NULL;
5404 j = model->firstmodelsurface;
5405 endj = j + model->nummodelsurfaces;
5408 // quickly skip over non-visible surfaces
5409 for (;j < endj && !r_viewcache.world_surfacevisible[j];j++)
5411 // quickly iterate over visible surfaces
5412 for (;j < endj && r_viewcache.world_surfacevisible[j];j++)
5414 // process this surface
5415 surface = model->data_surfaces + j;
5416 // if this surface fits the criteria, add it to the list
5417 if (surface->num_triangles)
5419 // if lightmap parameters changed, rebuild lightmap texture
5420 if (surface->cached_dlight)
5421 R_BuildLightMap(r_refdef.worldentity, surface);
5422 // add face to draw list
5423 surfacelist[numsurfacelist++] = surface;
5424 counttriangles += surface->num_triangles;
5425 if (numsurfacelist >= maxsurfacelist)
5427 R_QueueSurfaceList(r_refdef.worldentity, numsurfacelist, surfacelist, flagsmask, writedepth, depthonly);
5434 R_QueueSurfaceList(r_refdef.worldentity, numsurfacelist, surfacelist, flagsmask, writedepth, depthonly);
5435 r_refdef.stats.entities_triangles += counttriangles;
5438 if (r_showcollisionbrushes.integer && !skysurfaces && !depthonly)
5439 R_DrawCollisionBrushes(r_refdef.worldentity);
5441 if ((r_showtris.integer || r_shownormals.integer) && !depthonly)
5442 R_DrawTrianglesAndNormals(r_refdef.worldentity, r_showtris.integer, r_shownormals.integer, flagsmask);
5445 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly)
5447 int i, f, flagsmask;
5448 int counttriangles = 0;
5449 msurface_t *surface, *endsurface, **surfacechain;
5451 model_t *model = ent->model;
5452 const int maxsurfacelist = 1024;
5453 int numsurfacelist = 0;
5454 msurface_t *surfacelist[1024];
5458 // if the model is static it doesn't matter what value we give for
5459 // wantnormals and wanttangents, so this logic uses only rules applicable
5460 // to a model, knowing that they are meaningless otherwise
5461 if (ent == r_refdef.worldentity)
5462 RSurf_ActiveWorldEntity();
5463 else if ((ent->effects & EF_FULLBRIGHT) || r_showsurfaces.integer || VectorLength2(ent->modellight_diffuse) < (1.0f / 256.0f))
5464 RSurf_ActiveModelEntity(ent, false, false);
5466 RSurf_ActiveModelEntity(ent, true, r_glsl.integer && gl_support_fragment_shader && !depthonly);
5468 // update light styles
5469 if (!skysurfaces && !depthonly && model->brushq1.light_styleupdatechains)
5471 for (i = 0;i < model->brushq1.light_styles;i++)
5473 if (model->brushq1.light_stylevalue[i] != r_refdef.lightstylevalue[model->brushq1.light_style[i]])
5475 model->brushq1.light_stylevalue[i] = r_refdef.lightstylevalue[model->brushq1.light_style[i]];
5476 if ((surfacechain = model->brushq1.light_styleupdatechains[i]))
5477 for (;(surface = *surfacechain);surfacechain++)
5478 surface->cached_dlight = true;
5483 R_UpdateAllTextureInfo(ent);
5484 flagsmask = skysurfaces ? MATERIALFLAG_SKY : (MATERIALFLAG_WATER | MATERIALFLAG_WALL);
5487 rsurface.uselightmaptexture = false;
5488 rsurface.texture = NULL;
5490 surface = model->data_surfaces + model->firstmodelsurface;
5491 endsurface = surface + model->nummodelsurfaces;
5492 for (;surface < endsurface;surface++)
5494 // if this surface fits the criteria, add it to the list
5495 if (surface->num_triangles)
5497 // if lightmap parameters changed, rebuild lightmap texture
5498 if (surface->cached_dlight)
5499 R_BuildLightMap(ent, surface);
5500 // add face to draw list
5501 surfacelist[numsurfacelist++] = surface;
5502 counttriangles += surface->num_triangles;
5503 if (numsurfacelist >= maxsurfacelist)
5505 R_QueueSurfaceList(ent, numsurfacelist, surfacelist, flagsmask, writedepth, depthonly);
5511 R_QueueSurfaceList(ent, numsurfacelist, surfacelist, flagsmask, writedepth, depthonly);
5512 r_refdef.stats.entities_triangles += counttriangles;
5515 if (r_showcollisionbrushes.integer && !skysurfaces && !depthonly)
5516 R_DrawCollisionBrushes(ent);
5518 if ((r_showtris.integer || r_shownormals.integer) && !depthonly)
5519 R_DrawTrianglesAndNormals(ent, r_showtris.integer, r_shownormals.integer, flagsmask);