]> git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rmain.c
0970fdb7257273973335590ffbd76cfa0f61bba0
[xonotic/darkplaces.git] / gl_rmain.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
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.
8
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.
12
13 See the GNU General Public License for more details.
14
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.
18
19 */
20 // r_main.c
21
22 #include "quakedef.h"
23 #include "r_shadow.h"
24 #include "polygon.h"
25 #include "image.h"
26 #include "ft2.h"
27 #include "csprogs.h"
28 #include "cl_video.h"
29 #include "cl_collision.h"
30
31 #ifdef WIN32
32 // Enable NVIDIA High Performance Graphics while using Integrated Graphics.
33 #ifdef __cplusplus
34 extern "C" {
35 #endif
36 __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
37 #ifdef __cplusplus
38 }
39 #endif
40 #endif
41
42 mempool_t *r_main_mempool;
43 rtexturepool_t *r_main_texturepool;
44
45 static int r_textureframe = 0; ///< used only by R_GetCurrentTexture
46
47 static qboolean r_loadnormalmap;
48 static qboolean r_loadgloss;
49 qboolean r_loadfog;
50 static qboolean r_loaddds;
51 static qboolean r_savedds;
52 static qboolean r_gpuskeletal;
53
54 //
55 // screen size info
56 //
57 r_refdef_t r_refdef;
58
59 cvar_t r_motionblur = {CVAR_SAVE, "r_motionblur", "0", "screen motionblur - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
60 cvar_t r_damageblur = {CVAR_SAVE, "r_damageblur", "0", "screen motionblur based on damage - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
61 cvar_t r_motionblur_averaging = {CVAR_SAVE, "r_motionblur_averaging", "0.1", "sliding average reaction time for velocity (higher = slower adaption to change)"};
62 cvar_t r_motionblur_randomize = {CVAR_SAVE, "r_motionblur_randomize", "0.1", "randomizing coefficient to workaround ghosting"};
63 cvar_t r_motionblur_minblur = {CVAR_SAVE, "r_motionblur_minblur", "0.5", "factor of blur to apply at all times (always have this amount of blur no matter what the other factors are)"};
64 cvar_t r_motionblur_maxblur = {CVAR_SAVE, "r_motionblur_maxblur", "0.9", "maxmimum amount of blur"};
65 cvar_t r_motionblur_velocityfactor = {CVAR_SAVE, "r_motionblur_velocityfactor", "1", "factoring in of player velocity to the blur equation - the faster the player moves around the map, the more blur they get"};
66 cvar_t r_motionblur_velocityfactor_minspeed = {CVAR_SAVE, "r_motionblur_velocityfactor_minspeed", "400", "lower value of velocity when it starts to factor into blur equation"};
67 cvar_t r_motionblur_velocityfactor_maxspeed = {CVAR_SAVE, "r_motionblur_velocityfactor_maxspeed", "800", "upper value of velocity when it reaches the peak factor into blur equation"};
68 cvar_t r_motionblur_mousefactor = {CVAR_SAVE, "r_motionblur_mousefactor", "2", "factoring in of mouse acceleration to the blur equation - the faster the player turns their mouse, the more blur they get"};
69 cvar_t r_motionblur_mousefactor_minspeed = {CVAR_SAVE, "r_motionblur_mousefactor_minspeed", "0", "lower value of mouse acceleration when it starts to factor into blur equation"};
70 cvar_t r_motionblur_mousefactor_maxspeed = {CVAR_SAVE, "r_motionblur_mousefactor_maxspeed", "50", "upper value of mouse acceleration when it reaches the peak factor into blur equation"};
71
72 // TODO do we want a r_equalize_entities cvar that works on all ents, or would that be a cheat?
73 cvar_t r_equalize_entities_fullbright = {CVAR_SAVE, "r_equalize_entities_fullbright", "0", "render fullbright entities by equalizing their lightness, not by not rendering light (DEPRECATED)"};
74 cvar_t r_equalize_entities_minambient = {CVAR_SAVE, "r_equalize_entities_minambient", "0.5", "light equalizing: ensure at least this ambient/diffuse ratio (DEPRECATED)"};
75 cvar_t r_equalize_entities_by = {CVAR_SAVE, "r_equalize_entities_by", "0.7", "light equalizing: exponent of dynamics compression (0 = no compression, 1 = full compression) (DEPRECATED)"};
76 cvar_t r_equalize_entities_to = {CVAR_SAVE, "r_equalize_entities_to", "0.8", "light equalizing: target light level (DEPRECATED)"};
77
78 cvar_t r_depthfirst = {CVAR_SAVE, "r_depthfirst", "0", "renders a depth-only version of the scene before normal rendering begins to eliminate overdraw, values: 0 = off, 1 = world depth, 2 = world and model depth"};
79 cvar_t r_useinfinitefarclip = {CVAR_SAVE, "r_useinfinitefarclip", "1", "enables use of a special kind of projection matrix that has an extremely large farclip"};
80 cvar_t r_farclip_base = {0, "r_farclip_base", "65536", "farclip (furthest visible distance) for rendering when r_useinfinitefarclip is 0"};
81 cvar_t r_farclip_world = {0, "r_farclip_world", "2", "adds map size to farclip multiplied by this value"};
82 cvar_t r_nearclip = {0, "r_nearclip", "1", "distance from camera of nearclip plane" };
83 cvar_t r_deformvertexes = {0, "r_deformvertexes", "1", "allows use of deformvertexes in shader files (can be turned off to check performance impact)"};
84 cvar_t r_transparent = {0, "r_transparent", "1", "allows use of transparent surfaces (can be turned off to check performance impact)"};
85 cvar_t r_transparent_alphatocoverage = {0, "r_transparent_alphatocoverage", "1", "enables GL_ALPHA_TO_COVERAGE antialiasing technique on alphablend and alphatest surfaces when using vid_samples 2 or higher"};
86 cvar_t r_transparent_sortsurfacesbynearest = {0, "r_transparent_sortsurfacesbynearest", "1", "sort entity and world surfaces by nearest point on bounding box instead of using the center of the bounding box, usually reduces sorting artifacts"};
87 cvar_t r_transparent_useplanardistance = {0, "r_transparent_useplanardistance", "0", "sort transparent meshes by distance from view plane rather than spherical distance to the chosen point"};
88 cvar_t r_showoverdraw = {0, "r_showoverdraw", "0", "shows overlapping geometry"};
89 cvar_t r_showbboxes = {0, "r_showbboxes", "0", "shows bounding boxes of server entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
90 cvar_t r_showbboxes_client = { 0, "r_showbboxes_client", "0", "shows bounding boxes of clientside qc entities, value controls opacity scaling (1 = 10%,  10 = 100%)" };
91 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)"};
92 cvar_t r_showtris = {0, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"};
93 cvar_t r_shownormals = {0, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"};
94 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"};
95 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"};
96 cvar_t r_showcollisionbrushes = {0, "r_showcollisionbrushes", "0", "draws collision brushes in quake3 maps (mode 1), mode 2 disables rendering of world (trippy!)"};
97 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"};
98 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"};
99 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"};
100 cvar_t r_showspriteedges = {0, "r_showspriteedges", "0", "renders a debug outline to show the polygon shape of each sprite frame rendered (may be 2 or more in case of interpolated animations), for debugging rendering bugs with specific view types"};
101 cvar_t r_showparticleedges = {0, "r_showparticleedges", "0", "renders a debug outline to show the polygon shape of each particle, for debugging rendering bugs with specific view types"};
102 cvar_t r_drawportals = {0, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"};
103 cvar_t r_drawentities = {0, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"};
104 cvar_t r_draw2d = {0, "r_draw2d","1", "draw 2D stuff (dangerous to turn off)"};
105 cvar_t r_drawworld = {0, "r_drawworld","1", "draw world (most static stuff)"};
106 cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1", "draw your weapon model"};
107 cvar_t r_drawexteriormodel = {0, "r_drawexteriormodel","1", "draw your player model (e.g. in chase cam, reflections)"};
108 cvar_t r_cullentities_trace = {0, "r_cullentities_trace", "1", "probabistically cull invisible entities"};
109 cvar_t r_cullentities_trace_entityocclusion = { 0, "r_cullentities_trace_entityocclusion", "1", "check for occluding entities such as doors, not just world hull" };
110 cvar_t r_cullentities_trace_samples = {0, "r_cullentities_trace_samples", "2", "number of samples to test for entity culling (in addition to center sample)"};
111 cvar_t r_cullentities_trace_tempentitysamples = {0, "r_cullentities_trace_tempentitysamples", "-1", "number of samples to test for entity culling of temp entities (including all CSQC entities), -1 disables trace culling on these entities to prevent flicker (pvs still applies)"};
112 cvar_t r_cullentities_trace_enlarge = {0, "r_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
113 cvar_t r_cullentities_trace_expand = {0, "r_cullentities_trace_expand", "0", "box expanded by this many units for entity culling"};
114 cvar_t r_cullentities_trace_pad = {0, "r_cullentities_trace_pad", "8", "accept traces that hit within this many units of the box"};
115 cvar_t r_cullentities_trace_delay = {0, "r_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
116 cvar_t r_cullentities_trace_eyejitter = {0, "r_cullentities_trace_eyejitter", "16", "randomly offset rays from the eye by this much to reduce the odds of flickering"};
117 cvar_t r_sortentities = {0, "r_sortentities", "0", "sort entities before drawing (might be faster)"};
118 cvar_t r_speeds = {0, "r_speeds","0", "displays rendering statistics and per-subsystem timings"};
119 cvar_t r_fullbright = {0, "r_fullbright","0", "makes map very bright and renders faster"};
120
121 cvar_t r_fakelight = {0, "r_fakelight","0", "render 'fake' lighting instead of real lightmaps (DEPRECATED)"};
122 cvar_t r_fakelight_intensity = {0, "r_fakelight_intensity","0.75", "fakelight intensity modifier (DEPRECATED)"};
123 #define FAKELIGHT_ENABLED (r_fakelight.integer >= 2 || (r_fakelight.integer && r_refdef.scene.worldmodel && !r_refdef.scene.worldmodel->lit))
124
125 cvar_t r_fullbright_directed = {0, "r_fullbright_directed", "0", "render fullbright things (unlit worldmodel and EF_FULLBRIGHT entities, but not fullbright shaders) using a constant light direction instead to add more depth while keeping uniform brightness"};
126 cvar_t r_fullbright_directed_ambient = {0, "r_fullbright_directed_ambient", "0.5", "ambient light multiplier for directed fullbright"};
127 cvar_t r_fullbright_directed_diffuse = {0, "r_fullbright_directed_diffuse", "0.75", "diffuse light multiplier for directed fullbright"};
128 cvar_t r_fullbright_directed_pitch = {0, "r_fullbright_directed_pitch", "20", "constant pitch direction ('height') of the fake light source to use for fullbright"};
129 cvar_t r_fullbright_directed_pitch_relative = {0, "r_fullbright_directed_pitch_relative", "0", "whether r_fullbright_directed_pitch is interpreted as absolute (0) or relative (1) pitch"};
130
131 cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1", "opacity of water polygons"};
132 cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1", "enables dynamic lights (rocket glow and such)"};
133 cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1", "enables glowing pixels in quake textures (changes need r_restart to take effect)"};
134 cvar_t r_shadows = {CVAR_SAVE, "r_shadows", "0", "casts fake stencil shadows from models onto the world (rtlights are unaffected by this); when set to 2, always cast the shadows in the direction set by r_shadows_throwdirection, otherwise use the model lighting."};
135 cvar_t r_shadows_darken = {CVAR_SAVE, "r_shadows_darken", "0.5", "how much shadowed areas will be darkened"};
136 cvar_t r_shadows_throwdistance = {CVAR_SAVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"};
137 cvar_t r_shadows_throwdirection = {CVAR_SAVE, "r_shadows_throwdirection", "0 0 -1", "override throwing direction for r_shadows 2"};
138 cvar_t r_shadows_drawafterrtlighting = {CVAR_SAVE, "r_shadows_drawafterrtlighting", "0", "draw fake shadows AFTER realtime lightning is drawn. May be useful for simulating fast sunlight on large outdoor maps with only one noshadow rtlight. The price is less realistic appearance of dynamic light shadows."};
139 cvar_t r_shadows_castfrombmodels = {CVAR_SAVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"};
140 cvar_t r_shadows_focus = {CVAR_SAVE, "r_shadows_focus", "0 0 0", "offset the shadowed area focus"};
141 cvar_t r_shadows_shadowmapscale = {CVAR_SAVE, "r_shadows_shadowmapscale", "0.25", "higher values increase shadowmap quality at a cost of area covered (multiply global shadowmap precision) for fake shadows. Needs shadowmapping ON."};
142 cvar_t r_shadows_shadowmapbias = {CVAR_SAVE, "r_shadows_shadowmapbias", "-1", "sets shadowmap bias for fake shadows. -1 sets the value of r_shadow_shadowmapping_bias. Needs shadowmapping ON."};
143 cvar_t r_q1bsp_skymasking = {0, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
144 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"};
145 cvar_t r_polygonoffset_submodel_offset = {0, "r_polygonoffset_submodel_offset", "14", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
146 cvar_t r_polygonoffset_decals_factor = {0, "r_polygonoffset_decals_factor", "0", "biases depth values of decals to prevent z-fighting artifacts"};
147 cvar_t r_polygonoffset_decals_offset = {0, "r_polygonoffset_decals_offset", "-14", "biases depth values of decals to prevent z-fighting artifacts"};
148 cvar_t r_fog_exp2 = {0, "r_fog_exp2", "0", "uses GL_EXP2 fog (as in Nehahra) rather than realistic GL_EXP fog"};
149 cvar_t r_fog_clear = {0, "r_fog_clear", "1", "clears renderbuffer with fog color before render starts"};
150 cvar_t r_drawfog = {CVAR_SAVE, "r_drawfog", "1", "allows one to disable fog rendering"};
151 cvar_t r_transparentdepthmasking = {CVAR_SAVE, "r_transparentdepthmasking", "0", "enables depth writes on transparent meshes whose materially is normally opaque, this prevents seeing the inside of a transparent mesh"};
152 cvar_t r_transparent_sortmindist = {CVAR_SAVE, "r_transparent_sortmindist", "0", "lower distance limit for transparent sorting"};
153 cvar_t r_transparent_sortmaxdist = {CVAR_SAVE, "r_transparent_sortmaxdist", "32768", "upper distance limit for transparent sorting"};
154 cvar_t r_transparent_sortarraysize = {CVAR_SAVE, "r_transparent_sortarraysize", "4096", "number of distance-sorting layers"};
155 cvar_t r_celshading = {CVAR_SAVE, "r_celshading", "0", "cartoon-style light shading (OpenGL 2.x only)"}; // FIXME remove OpenGL 2.x only once implemented for DX9
156 cvar_t r_celoutlines = {CVAR_SAVE, "r_celoutlines", "0", "cartoon-style outlines (requires r_shadow_deferred; OpenGL 2.x only)"}; // FIXME remove OpenGL 2.x only once implemented for DX9
157
158 cvar_t gl_fogenable = {0, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"};
159 cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"};
160 cvar_t gl_fogred = {0, "gl_fogred","0.3", "nehahra fog color red value (for Nehahra compatibility only)"};
161 cvar_t gl_foggreen = {0, "gl_foggreen","0.3", "nehahra fog color green value (for Nehahra compatibility only)"};
162 cvar_t gl_fogblue = {0, "gl_fogblue","0.3", "nehahra fog color blue value (for Nehahra compatibility only)"};
163 cvar_t gl_fogstart = {0, "gl_fogstart", "0", "nehahra fog start distance (for Nehahra compatibility only)"};
164 cvar_t gl_fogend = {0, "gl_fogend","0", "nehahra fog end distance (for Nehahra compatibility only)"};
165 cvar_t gl_skyclip = {0, "gl_skyclip", "4608", "nehahra farclip distance - the real fog end (for Nehahra compatibility only)"};
166
167 cvar_t r_texture_dds_load = {CVAR_SAVE, "r_texture_dds_load", "0", "load compressed dds/filename.dds texture instead of filename.tga, if the file exists (requires driver support)"};
168 cvar_t r_texture_dds_save = {CVAR_SAVE, "r_texture_dds_save", "0", "save compressed dds/filename.dds texture when filename.tga is loaded, so that it can be loaded instead next time"};
169
170 cvar_t r_textureunits = {0, "r_textureunits", "32", "number of texture units to use in GL 1.1 and GL 1.3 rendering paths"};
171 static cvar_t gl_combine = {CVAR_READONLY, "gl_combine", "1", "indicates whether the OpenGL 1.3 rendering path is active"};
172 static cvar_t r_glsl = {CVAR_READONLY, "r_glsl", "1", "indicates whether the OpenGL 2.0 rendering path is active"};
173
174 cvar_t r_usedepthtextures = {CVAR_SAVE, "r_usedepthtextures", "1", "use depth texture instead of depth renderbuffer where possible, uses less video memory but may render slower (or faster) depending on hardware"};
175 cvar_t r_viewfbo = {CVAR_SAVE, "r_viewfbo", "0", "enables use of an 8bit (1) or 16bit (2) or 32bit (3) per component float framebuffer render, which may be at a different resolution than the video mode"};
176 cvar_t r_rendertarget_debug = {0, "r_rendertarget_debug", "-1", "replaces the view with the contents of the specified render target (by number - note that these can fluctuate depending on scene)"};
177 cvar_t r_viewscale = {CVAR_SAVE, "r_viewscale", "1", "scaling factor for resolution of the fbo rendering method, must be > 0, can be above 1 for a costly antialiasing behavior, typical values are 0.5 for 1/4th as many pixels rendered, or 1 for normal rendering"};
178 cvar_t r_viewscale_fpsscaling = {CVAR_SAVE, "r_viewscale_fpsscaling", "0", "change resolution based on framerate"};
179 cvar_t r_viewscale_fpsscaling_min = {CVAR_SAVE, "r_viewscale_fpsscaling_min", "0.0625", "worst acceptable quality"};
180 cvar_t r_viewscale_fpsscaling_multiply = {CVAR_SAVE, "r_viewscale_fpsscaling_multiply", "5", "adjust quality up or down by the frametime difference from 1.0/target, multiplied by this factor"};
181 cvar_t r_viewscale_fpsscaling_stepsize = {CVAR_SAVE, "r_viewscale_fpsscaling_stepsize", "0.01", "smallest adjustment to hit the target framerate (this value prevents minute oscillations)"};
182 cvar_t r_viewscale_fpsscaling_stepmax = {CVAR_SAVE, "r_viewscale_fpsscaling_stepmax", "1.00", "largest adjustment to hit the target framerate (this value prevents wild overshooting of the estimate)"};
183 cvar_t r_viewscale_fpsscaling_target = {CVAR_SAVE, "r_viewscale_fpsscaling_target", "70", "desired framerate"};
184
185 cvar_t r_glsl_skeletal = {CVAR_SAVE, "r_glsl_skeletal", "1", "render skeletal models faster using a gpu-skinning technique"};
186 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)"};
187 cvar_t r_glsl_offsetmapping = {CVAR_SAVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
188 cvar_t r_glsl_offsetmapping_steps = {CVAR_SAVE, "r_glsl_offsetmapping_steps", "2", "offset mapping steps (note: too high values may be not supported by your GPU)"};
189 cvar_t r_glsl_offsetmapping_reliefmapping = {CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
190 cvar_t r_glsl_offsetmapping_reliefmapping_steps = {CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping_steps", "10", "relief mapping steps (note: too high values may be not supported by your GPU)"};
191 cvar_t r_glsl_offsetmapping_reliefmapping_refinesteps = {CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping_refinesteps", "5", "relief mapping refine steps (these are a binary search executed as the last step as given by r_glsl_offsetmapping_reliefmapping_steps)"};
192 cvar_t r_glsl_offsetmapping_scale = {CVAR_SAVE, "r_glsl_offsetmapping_scale", "0.04", "how deep the offset mapping effect is"};
193 cvar_t r_glsl_offsetmapping_lod = {CVAR_SAVE, "r_glsl_offsetmapping_lod", "0", "apply distance-based level-of-detail correction to number of offsetmappig steps, effectively making it render faster on large open-area maps"};
194 cvar_t r_glsl_offsetmapping_lod_distance = {CVAR_SAVE, "r_glsl_offsetmapping_lod_distance", "32", "first LOD level distance, second level (-50% steps) is 2x of this, third (33%) - 3x etc."};
195 cvar_t r_glsl_postprocess = {CVAR_SAVE, "r_glsl_postprocess", "0", "use a GLSL postprocessing shader"};
196 cvar_t r_glsl_postprocess_uservec1 = {CVAR_SAVE, "r_glsl_postprocess_uservec1", "0 0 0 0", "a 4-component vector to pass as uservec1 to the postprocessing shader (only useful if default.glsl has been customized)"};
197 cvar_t r_glsl_postprocess_uservec2 = {CVAR_SAVE, "r_glsl_postprocess_uservec2", "0 0 0 0", "a 4-component vector to pass as uservec2 to the postprocessing shader (only useful if default.glsl has been customized)"};
198 cvar_t r_glsl_postprocess_uservec3 = {CVAR_SAVE, "r_glsl_postprocess_uservec3", "0 0 0 0", "a 4-component vector to pass as uservec3 to the postprocessing shader (only useful if default.glsl has been customized)"};
199 cvar_t r_glsl_postprocess_uservec4 = {CVAR_SAVE, "r_glsl_postprocess_uservec4", "0 0 0 0", "a 4-component vector to pass as uservec4 to the postprocessing shader (only useful if default.glsl has been customized)"};
200 cvar_t r_glsl_postprocess_uservec1_enable = {CVAR_SAVE, "r_glsl_postprocess_uservec1_enable", "1", "enables postprocessing uservec1 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
201 cvar_t r_glsl_postprocess_uservec2_enable = {CVAR_SAVE, "r_glsl_postprocess_uservec2_enable", "1", "enables postprocessing uservec2 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
202 cvar_t r_glsl_postprocess_uservec3_enable = {CVAR_SAVE, "r_glsl_postprocess_uservec3_enable", "1", "enables postprocessing uservec3 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
203 cvar_t r_glsl_postprocess_uservec4_enable = {CVAR_SAVE, "r_glsl_postprocess_uservec4_enable", "1", "enables postprocessing uservec4 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
204
205 cvar_t r_water = {CVAR_SAVE, "r_water", "0", "whether to use reflections and refraction on water surfaces (note: r_wateralpha must be set below 1)"};
206 cvar_t r_water_cameraentitiesonly = {CVAR_SAVE, "r_water_cameraentitiesonly", "0", "whether to only show QC-defined reflections/refractions (typically used for camera- or portal-like effects)"};
207 cvar_t r_water_clippingplanebias = {CVAR_SAVE, "r_water_clippingplanebias", "1", "a rather technical setting which avoids black pixels around water edges"};
208 cvar_t r_water_resolutionmultiplier = {CVAR_SAVE, "r_water_resolutionmultiplier", "0.5", "multiplier for screen resolution when rendering refracted/reflected scenes, 1 is full quality, lower values are faster"};
209 cvar_t r_water_refractdistort = {CVAR_SAVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
210 cvar_t r_water_reflectdistort = {CVAR_SAVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"};
211 cvar_t r_water_scissormode = {0, "r_water_scissormode", "3", "scissor (1) or cull (2) or both (3) water renders"};
212 cvar_t r_water_lowquality = {0, "r_water_lowquality", "0", "special option to accelerate water rendering, 1 disables shadows and particles, 2 disables all dynamic lights"};
213 cvar_t r_water_hideplayer = {CVAR_SAVE, "r_water_hideplayer", "0", "if set to 1 then player will be hidden in refraction views, if set to 2 then player will also be hidden in reflection views, player is always visible in camera views"};
214
215 cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "0", "enables animation smoothing on sprites"};
216 cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
217 cvar_t r_lerplightstyles = {CVAR_SAVE, "r_lerplightstyles", "0", "enable animation smoothing on flickering lights"};
218 cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
219
220 cvar_t r_bloom = {CVAR_SAVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"};
221 cvar_t r_bloom_colorscale = {CVAR_SAVE, "r_bloom_colorscale", "1", "how bright the glow is"};
222
223 cvar_t r_bloom_brighten = {CVAR_SAVE, "r_bloom_brighten", "2", "how bright the glow is, after subtract/power"};
224 cvar_t r_bloom_blur = {CVAR_SAVE, "r_bloom_blur", "4", "how large the glow is"};
225 cvar_t r_bloom_resolution = {CVAR_SAVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"};
226 cvar_t r_bloom_colorexponent = {CVAR_SAVE, "r_bloom_colorexponent", "1", "how exaggerated the glow is"};
227 cvar_t r_bloom_colorsubtract = {CVAR_SAVE, "r_bloom_colorsubtract", "0.125", "reduces bloom colors by a certain amount"};
228 cvar_t r_bloom_scenebrightness = {CVAR_SAVE, "r_bloom_scenebrightness", "1", "global rendering brightness when bloom is enabled"};
229
230 cvar_t r_hdr_scenebrightness = {CVAR_SAVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
231 cvar_t r_hdr_glowintensity = {CVAR_SAVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
232 cvar_t r_hdr_irisadaptation = {CVAR_SAVE, "r_hdr_irisadaptation", "0", "adjust scene brightness according to light intensity at player location"};
233 cvar_t r_hdr_irisadaptation_multiplier = {CVAR_SAVE, "r_hdr_irisadaptation_multiplier", "2", "brightness at which value will be 1.0"};
234 cvar_t r_hdr_irisadaptation_minvalue = {CVAR_SAVE, "r_hdr_irisadaptation_minvalue", "0.5", "minimum value that can result from multiplier / brightness"};
235 cvar_t r_hdr_irisadaptation_maxvalue = {CVAR_SAVE, "r_hdr_irisadaptation_maxvalue", "4", "maximum value that can result from multiplier / brightness"};
236 cvar_t r_hdr_irisadaptation_value = {0, "r_hdr_irisadaptation_value", "1", "current value as scenebrightness multiplier, changes continuously when irisadaptation is active"};
237 cvar_t r_hdr_irisadaptation_fade_up = {CVAR_SAVE, "r_hdr_irisadaptation_fade_up", "0.1", "fade rate at which value adjusts to darkness"};
238 cvar_t r_hdr_irisadaptation_fade_down = {CVAR_SAVE, "r_hdr_irisadaptation_fade_down", "0.5", "fade rate at which value adjusts to brightness"};
239 cvar_t r_hdr_irisadaptation_radius = {CVAR_SAVE, "r_hdr_irisadaptation_radius", "15", "lighting within this many units of the eye is averaged"};
240
241 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"};
242
243 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"};
244
245 cvar_t gl_lightmaps = {0, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers), a value of 2 keeps normalmap shading"};
246
247 cvar_t r_test = {0, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
248
249 cvar_t r_batch_multidraw = {CVAR_SAVE, "r_batch_multidraw", "1", "issue multiple glDrawElements calls when rendering a batch of surfaces with the same texture (otherwise the index data is copied to make it one draw)"};
250 cvar_t r_batch_multidraw_mintriangles = {CVAR_SAVE, "r_batch_multidraw_mintriangles", "0", "minimum number of triangles to activate multidraw path (copying small groups of triangles may be faster)"};
251 cvar_t r_batch_debugdynamicvertexpath = {CVAR_SAVE, "r_batch_debugdynamicvertexpath", "0", "force the dynamic batching code path for debugging purposes"};
252 cvar_t r_batch_dynamicbuffer = {CVAR_SAVE, "r_batch_dynamicbuffer", "0", "use vertex/index buffers for drawing dynamic and copytriangles batches"};
253
254 cvar_t r_glsl_saturation = {CVAR_SAVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"};
255 cvar_t r_glsl_saturation_redcompensate = {CVAR_SAVE, "r_glsl_saturation_redcompensate", "0", "a 'vampire sight' addition to desaturation effect, does compensation for red color, r_glsl_restart is required"};
256
257 cvar_t r_glsl_vertextextureblend_usebothalphas = {CVAR_SAVE, "r_glsl_vertextextureblend_usebothalphas", "0", "use both alpha layers on vertex blended surfaces, each alpha layer sets amount of 'blend leak' on another layer, requires mod_q3shader_force_terrain_alphaflag on."};
258
259 cvar_t r_framedatasize = {CVAR_SAVE, "r_framedatasize", "0.5", "size of renderer data cache used during one frame (for skeletal animation caching, light processing, etc)"};
260 cvar_t r_buffermegs[R_BUFFERDATA_COUNT] =
261 {
262         {CVAR_SAVE, "r_buffermegs_vertex", "4", "vertex buffer size for one frame"},
263         {CVAR_SAVE, "r_buffermegs_index16", "1", "index buffer size for one frame (16bit indices)"},
264         {CVAR_SAVE, "r_buffermegs_index32", "1", "index buffer size for one frame (32bit indices)"},
265         {CVAR_SAVE, "r_buffermegs_uniform", "0.25", "uniform buffer size for one frame"},
266 };
267
268 extern cvar_t v_glslgamma_2d;
269
270 extern qboolean v_flipped_state;
271
272 r_framebufferstate_t r_fb;
273
274 /// shadow volume bsp struct with automatically growing nodes buffer
275 svbsp_t r_svbsp;
276
277 int r_uniformbufferalignment = 32; // dynamically updated to match GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
278
279 rtexture_t *r_texture_blanknormalmap;
280 rtexture_t *r_texture_white;
281 rtexture_t *r_texture_grey128;
282 rtexture_t *r_texture_black;
283 rtexture_t *r_texture_notexture;
284 rtexture_t *r_texture_whitecube;
285 rtexture_t *r_texture_normalizationcube;
286 rtexture_t *r_texture_fogattenuation;
287 rtexture_t *r_texture_fogheighttexture;
288 rtexture_t *r_texture_gammaramps;
289 unsigned int r_texture_gammaramps_serial;
290 //rtexture_t *r_texture_fogintensity;
291 rtexture_t *r_texture_reflectcube;
292
293 // TODO: hash lookups?
294 typedef struct cubemapinfo_s
295 {
296         char basename[64];
297         rtexture_t *texture;
298 }
299 cubemapinfo_t;
300
301 int r_texture_numcubemaps;
302 cubemapinfo_t *r_texture_cubemaps[MAX_CUBEMAPS];
303
304 unsigned int r_queries[MAX_OCCLUSION_QUERIES];
305 unsigned int r_numqueries;
306 unsigned int r_maxqueries;
307
308 typedef struct r_qwskincache_s
309 {
310         char name[MAX_QPATH];
311         skinframe_t *skinframe;
312 }
313 r_qwskincache_t;
314
315 static r_qwskincache_t *r_qwskincache;
316 static int r_qwskincache_size;
317
318 /// vertex coordinates for a quad that covers the screen exactly
319 extern const float r_screenvertex3f[12];
320 const float r_screenvertex3f[12] =
321 {
322         0, 0, 0,
323         1, 0, 0,
324         1, 1, 0,
325         0, 1, 0
326 };
327
328 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
329 {
330         int i;
331         for (i = 0;i < verts;i++)
332         {
333                 out[0] = in[0] * r;
334                 out[1] = in[1] * g;
335                 out[2] = in[2] * b;
336                 out[3] = in[3];
337                 in += 4;
338                 out += 4;
339         }
340 }
341
342 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
343 {
344         int i;
345         for (i = 0;i < verts;i++)
346         {
347                 out[0] = r;
348                 out[1] = g;
349                 out[2] = b;
350                 out[3] = a;
351                 out += 4;
352         }
353 }
354
355 // FIXME: move this to client?
356 void FOG_clear(void)
357 {
358         if (gamemode == GAME_NEHAHRA)
359         {
360                 Cvar_Set("gl_fogenable", "0");
361                 Cvar_Set("gl_fogdensity", "0.2");
362                 Cvar_Set("gl_fogred", "0.3");
363                 Cvar_Set("gl_foggreen", "0.3");
364                 Cvar_Set("gl_fogblue", "0.3");
365         }
366         r_refdef.fog_density = 0;
367         r_refdef.fog_red = 0;
368         r_refdef.fog_green = 0;
369         r_refdef.fog_blue = 0;
370         r_refdef.fog_alpha = 1;
371         r_refdef.fog_start = 0;
372         r_refdef.fog_end = 16384;
373         r_refdef.fog_height = 1<<30;
374         r_refdef.fog_fadedepth = 128;
375         memset(r_refdef.fog_height_texturename, 0, sizeof(r_refdef.fog_height_texturename));
376 }
377
378 static void R_BuildBlankTextures(void)
379 {
380         unsigned char data[4];
381         data[2] = 128; // normal X
382         data[1] = 128; // normal Y
383         data[0] = 255; // normal Z
384         data[3] = 255; // height
385         r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
386         data[0] = 255;
387         data[1] = 255;
388         data[2] = 255;
389         data[3] = 255;
390         r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
391         data[0] = 128;
392         data[1] = 128;
393         data[2] = 128;
394         data[3] = 255;
395         r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
396         data[0] = 0;
397         data[1] = 0;
398         data[2] = 0;
399         data[3] = 255;
400         r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
401 }
402
403 static void R_BuildNoTexture(void)
404 {
405         int x, y;
406         unsigned char pix[16][16][4];
407         // this makes a light grey/dark grey checkerboard texture
408         for (y = 0;y < 16;y++)
409         {
410                 for (x = 0;x < 16;x++)
411                 {
412                         if ((y < 8) ^ (x < 8))
413                         {
414                                 pix[y][x][0] = 128;
415                                 pix[y][x][1] = 128;
416                                 pix[y][x][2] = 128;
417                                 pix[y][x][3] = 255;
418                         }
419                         else
420                         {
421                                 pix[y][x][0] = 64;
422                                 pix[y][x][1] = 64;
423                                 pix[y][x][2] = 64;
424                                 pix[y][x][3] = 255;
425                         }
426                 }
427         }
428         r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_PERSISTENT, -1, NULL);
429 }
430
431 static void R_BuildWhiteCube(void)
432 {
433         unsigned char data[6*1*1*4];
434         memset(data, 255, sizeof(data));
435         r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
436 }
437
438 static void R_BuildNormalizationCube(void)
439 {
440         int x, y, side;
441         vec3_t v;
442         vec_t s, t, intensity;
443 #define NORMSIZE 64
444         unsigned char *data;
445         data = (unsigned char *)Mem_Alloc(tempmempool, 6*NORMSIZE*NORMSIZE*4);
446         for (side = 0;side < 6;side++)
447         {
448                 for (y = 0;y < NORMSIZE;y++)
449                 {
450                         for (x = 0;x < NORMSIZE;x++)
451                         {
452                                 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
453                                 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
454                                 switch(side)
455                                 {
456                                 default:
457                                 case 0:
458                                         v[0] = 1;
459                                         v[1] = -t;
460                                         v[2] = -s;
461                                         break;
462                                 case 1:
463                                         v[0] = -1;
464                                         v[1] = -t;
465                                         v[2] = s;
466                                         break;
467                                 case 2:
468                                         v[0] = s;
469                                         v[1] = 1;
470                                         v[2] = t;
471                                         break;
472                                 case 3:
473                                         v[0] = s;
474                                         v[1] = -1;
475                                         v[2] = -t;
476                                         break;
477                                 case 4:
478                                         v[0] = s;
479                                         v[1] = -t;
480                                         v[2] = 1;
481                                         break;
482                                 case 5:
483                                         v[0] = -s;
484                                         v[1] = -t;
485                                         v[2] = -1;
486                                         break;
487                                 }
488                                 intensity = 127.0f / sqrt(DotProduct(v, v));
489                                 data[((side*64+y)*64+x)*4+2] = (unsigned char)(128.0f + intensity * v[0]);
490                                 data[((side*64+y)*64+x)*4+1] = (unsigned char)(128.0f + intensity * v[1]);
491                                 data[((side*64+y)*64+x)*4+0] = (unsigned char)(128.0f + intensity * v[2]);
492                                 data[((side*64+y)*64+x)*4+3] = 255;
493                         }
494                 }
495         }
496         r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
497         Mem_Free(data);
498 }
499
500 static void R_BuildFogTexture(void)
501 {
502         int x, b;
503 #define FOGWIDTH 256
504         unsigned char data1[FOGWIDTH][4];
505         //unsigned char data2[FOGWIDTH][4];
506         double d, r, alpha;
507
508         r_refdef.fogmasktable_start = r_refdef.fog_start;
509         r_refdef.fogmasktable_alpha = r_refdef.fog_alpha;
510         r_refdef.fogmasktable_range = r_refdef.fogrange;
511         r_refdef.fogmasktable_density = r_refdef.fog_density;
512
513         r = r_refdef.fogmasktable_range / FOGMASKTABLEWIDTH;
514         for (x = 0;x < FOGMASKTABLEWIDTH;x++)
515         {
516                 d = (x * r - r_refdef.fogmasktable_start);
517                 if(developer_extra.integer)
518                         Con_DPrintf("%f ", d);
519                 d = max(0, d);
520                 if (r_fog_exp2.integer)
521                         alpha = exp(-r_refdef.fogmasktable_density * r_refdef.fogmasktable_density * 0.0001 * d * d);
522                 else
523                         alpha = exp(-r_refdef.fogmasktable_density * 0.004 * d);
524                 if(developer_extra.integer)
525                         Con_DPrintf(" : %f ", alpha);
526                 alpha = 1 - (1 - alpha) * r_refdef.fogmasktable_alpha;
527                 if(developer_extra.integer)
528                         Con_DPrintf(" = %f\n", alpha);
529                 r_refdef.fogmasktable[x] = bound(0, alpha, 1);
530         }
531
532         for (x = 0;x < FOGWIDTH;x++)
533         {
534                 b = (int)(r_refdef.fogmasktable[x * (FOGMASKTABLEWIDTH - 1) / (FOGWIDTH - 1)] * 255);
535                 data1[x][0] = b;
536                 data1[x][1] = b;
537                 data1[x][2] = b;
538                 data1[x][3] = 255;
539                 //data2[x][0] = 255 - b;
540                 //data2[x][1] = 255 - b;
541                 //data2[x][2] = 255 - b;
542                 //data2[x][3] = 255;
543         }
544         if (r_texture_fogattenuation)
545         {
546                 R_UpdateTexture(r_texture_fogattenuation, &data1[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
547                 //R_UpdateTexture(r_texture_fogattenuation, &data2[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
548         }
549         else
550         {
551                 r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
552                 //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
553         }
554 }
555
556 static void R_BuildFogHeightTexture(void)
557 {
558         unsigned char *inpixels;
559         int size;
560         int x;
561         int y;
562         int j;
563         float c[4];
564         float f;
565         inpixels = NULL;
566         strlcpy(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename, sizeof(r_refdef.fogheighttexturename));
567         if (r_refdef.fogheighttexturename[0])
568                 inpixels = loadimagepixelsbgra(r_refdef.fogheighttexturename, true, false, false, NULL);
569         if (!inpixels)
570         {
571                 r_refdef.fog_height_tablesize = 0;
572                 if (r_texture_fogheighttexture)
573                         R_FreeTexture(r_texture_fogheighttexture);
574                 r_texture_fogheighttexture = NULL;
575                 if (r_refdef.fog_height_table2d)
576                         Mem_Free(r_refdef.fog_height_table2d);
577                 r_refdef.fog_height_table2d = NULL;
578                 if (r_refdef.fog_height_table1d)
579                         Mem_Free(r_refdef.fog_height_table1d);
580                 r_refdef.fog_height_table1d = NULL;
581                 return;
582         }
583         size = image_width;
584         r_refdef.fog_height_tablesize = size;
585         r_refdef.fog_height_table1d = (unsigned char *)Mem_Alloc(r_main_mempool, size * 4);
586         r_refdef.fog_height_table2d = (unsigned char *)Mem_Alloc(r_main_mempool, size * size * 4);
587         memcpy(r_refdef.fog_height_table1d, inpixels, size * 4);
588         Mem_Free(inpixels);
589         // LordHavoc: now the magic - what is that table2d for?  it is a cooked
590         // average fog color table accounting for every fog layer between a point
591         // and the camera.  (Note: attenuation is handled separately!)
592         for (y = 0;y < size;y++)
593         {
594                 for (x = 0;x < size;x++)
595                 {
596                         Vector4Clear(c);
597                         f = 0;
598                         if (x < y)
599                         {
600                                 for (j = x;j <= y;j++)
601                                 {
602                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
603                                         f++;
604                                 }
605                         }
606                         else
607                         {
608                                 for (j = x;j >= y;j--)
609                                 {
610                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
611                                         f++;
612                                 }
613                         }
614                         f = 1.0f / f;
615                         r_refdef.fog_height_table2d[(y*size+x)*4+0] = (unsigned char)(c[0] * f);
616                         r_refdef.fog_height_table2d[(y*size+x)*4+1] = (unsigned char)(c[1] * f);
617                         r_refdef.fog_height_table2d[(y*size+x)*4+2] = (unsigned char)(c[2] * f);
618                         r_refdef.fog_height_table2d[(y*size+x)*4+3] = (unsigned char)(c[3] * f);
619                 }
620         }
621         r_texture_fogheighttexture = R_LoadTexture2D(r_main_texturepool, "fogheighttable", size, size, r_refdef.fog_height_table2d, TEXTYPE_BGRA, TEXF_ALPHA | TEXF_CLAMP, -1, NULL);
622 }
623
624 //=======================================================================================================================================================
625
626 static const char *builtinshaderstrings[] =
627 {
628 #include "shader_glsl.h"
629 0
630 };
631
632 //=======================================================================================================================================================
633
634 typedef struct shaderpermutationinfo_s
635 {
636         const char *pretext;
637         const char *name;
638 }
639 shaderpermutationinfo_t;
640
641 typedef struct shadermodeinfo_s
642 {
643         const char *sourcebasename;
644         const char *extension;
645         const char **builtinshaderstrings;
646         const char *pretext;
647         const char *name;
648         char *filename;
649         char *builtinstring;
650         int builtincrc;
651 }
652 shadermodeinfo_t;
653
654 // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
655 shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
656 {
657         {"#define USEDIFFUSE\n", " diffuse"},
658         {"#define USEVERTEXTEXTUREBLEND\n", " vertextextureblend"},
659         {"#define USEVIEWTINT\n", " viewtint"},
660         {"#define USECOLORMAPPING\n", " colormapping"},
661         {"#define USESATURATION\n", " saturation"},
662         {"#define USEFOGINSIDE\n", " foginside"},
663         {"#define USEFOGOUTSIDE\n", " fogoutside"},
664         {"#define USEFOGHEIGHTTEXTURE\n", " fogheighttexture"},
665         {"#define USEFOGALPHAHACK\n", " fogalphahack"},
666         {"#define USEGAMMARAMPS\n", " gammaramps"},
667         {"#define USECUBEFILTER\n", " cubefilter"},
668         {"#define USEGLOW\n", " glow"},
669         {"#define USEBLOOM\n", " bloom"},
670         {"#define USESPECULAR\n", " specular"},
671         {"#define USEPOSTPROCESSING\n", " postprocessing"},
672         {"#define USEREFLECTION\n", " reflection"},
673         {"#define USEOFFSETMAPPING\n", " offsetmapping"},
674         {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
675         {"#define USESHADOWMAP2D\n", " shadowmap2d"},
676         {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"}, // TODO make this a static parm
677         {"#define USESHADOWMAPORTHO\n", " shadowmaportho"},
678         {"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"},
679         {"#define USEALPHAKILL\n", " alphakill"},
680         {"#define USEREFLECTCUBE\n", " reflectcube"},
681         {"#define USENORMALMAPSCROLLBLEND\n", " normalmapscrollblend"},
682         {"#define USEBOUNCEGRID\n", " bouncegrid"},
683         {"#define USEBOUNCEGRIDDIRECTIONAL\n", " bouncegriddirectional"}, // TODO make this a static parm
684         {"#define USETRIPPY\n", " trippy"},
685         {"#define USEDEPTHRGB\n", " depthrgb"},
686         {"#define USEALPHAGENVERTEX\n", " alphagenvertex"},
687         {"#define USESKELETAL\n", " skeletal"},
688         {"#define USEOCCLUDE\n", " occlude"}
689 };
690
691 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
692 shadermodeinfo_t shadermodeinfo[SHADERLANGUAGE_COUNT][SHADERMODE_COUNT] =
693 {
694         // SHADERLANGUAGE_GLSL
695         {
696                 {"combined", "glsl", builtinshaderstrings, "#define MODE_GENERIC\n", " generic"},
697                 {"combined", "glsl", builtinshaderstrings, "#define MODE_POSTPROCESS\n", " postprocess"},
698                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
699                 {"combined", "glsl", builtinshaderstrings, "#define MODE_FLATCOLOR\n", " flatcolor"},
700                 {"combined", "glsl", builtinshaderstrings, "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
701                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTMAP\n", " lightmap"},
702                 {"combined", "glsl", builtinshaderstrings, "#define MODE_FAKELIGHT\n", " fakelight"},
703                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
704                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
705                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
706                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
707                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
708                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTSOURCE\n", " lightsource"},
709                 {"combined", "glsl", builtinshaderstrings, "#define MODE_REFRACTION\n", " refraction"},
710                 {"combined", "glsl", builtinshaderstrings, "#define MODE_WATER\n", " water"},
711                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
712                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
713         },
714 };
715
716 struct r_glsl_permutation_s;
717 typedef struct r_glsl_permutation_s
718 {
719         /// hash lookup data
720         struct r_glsl_permutation_s *hashnext;
721         unsigned int mode;
722         dpuint64 permutation;
723
724         /// indicates if we have tried compiling this permutation already
725         qboolean compiled;
726         /// 0 if compilation failed
727         int program;
728         // texture units assigned to each detected uniform
729         int tex_Texture_First;
730         int tex_Texture_Second;
731         int tex_Texture_GammaRamps;
732         int tex_Texture_Normal;
733         int tex_Texture_Color;
734         int tex_Texture_Gloss;
735         int tex_Texture_Glow;
736         int tex_Texture_SecondaryNormal;
737         int tex_Texture_SecondaryColor;
738         int tex_Texture_SecondaryGloss;
739         int tex_Texture_SecondaryGlow;
740         int tex_Texture_Pants;
741         int tex_Texture_Shirt;
742         int tex_Texture_FogHeightTexture;
743         int tex_Texture_FogMask;
744         int tex_Texture_Lightmap;
745         int tex_Texture_Deluxemap;
746         int tex_Texture_Attenuation;
747         int tex_Texture_Cube;
748         int tex_Texture_Refraction;
749         int tex_Texture_Reflection;
750         int tex_Texture_ShadowMap2D;
751         int tex_Texture_CubeProjection;
752         int tex_Texture_ScreenNormalMap;
753         int tex_Texture_ScreenDiffuse;
754         int tex_Texture_ScreenSpecular;
755         int tex_Texture_ReflectMask;
756         int tex_Texture_ReflectCube;
757         int tex_Texture_BounceGrid;
758         /// locations of detected uniforms in program object, or -1 if not found
759         int loc_Texture_First;
760         int loc_Texture_Second;
761         int loc_Texture_GammaRamps;
762         int loc_Texture_Normal;
763         int loc_Texture_Color;
764         int loc_Texture_Gloss;
765         int loc_Texture_Glow;
766         int loc_Texture_SecondaryNormal;
767         int loc_Texture_SecondaryColor;
768         int loc_Texture_SecondaryGloss;
769         int loc_Texture_SecondaryGlow;
770         int loc_Texture_Pants;
771         int loc_Texture_Shirt;
772         int loc_Texture_FogHeightTexture;
773         int loc_Texture_FogMask;
774         int loc_Texture_Lightmap;
775         int loc_Texture_Deluxemap;
776         int loc_Texture_Attenuation;
777         int loc_Texture_Cube;
778         int loc_Texture_Refraction;
779         int loc_Texture_Reflection;
780         int loc_Texture_ShadowMap2D;
781         int loc_Texture_CubeProjection;
782         int loc_Texture_ScreenNormalMap;
783         int loc_Texture_ScreenDiffuse;
784         int loc_Texture_ScreenSpecular;
785         int loc_Texture_ReflectMask;
786         int loc_Texture_ReflectCube;
787         int loc_Texture_BounceGrid;
788         int loc_Alpha;
789         int loc_BloomBlur_Parameters;
790         int loc_ClientTime;
791         int loc_Color_Ambient;
792         int loc_Color_Diffuse;
793         int loc_Color_Specular;
794         int loc_Color_Glow;
795         int loc_Color_Pants;
796         int loc_Color_Shirt;
797         int loc_DeferredColor_Ambient;
798         int loc_DeferredColor_Diffuse;
799         int loc_DeferredColor_Specular;
800         int loc_DeferredMod_Diffuse;
801         int loc_DeferredMod_Specular;
802         int loc_DistortScaleRefractReflect;
803         int loc_EyePosition;
804         int loc_FogColor;
805         int loc_FogHeightFade;
806         int loc_FogPlane;
807         int loc_FogPlaneViewDist;
808         int loc_FogRangeRecip;
809         int loc_LightColor;
810         int loc_LightDir;
811         int loc_LightPosition;
812         int loc_OffsetMapping_ScaleSteps;
813         int loc_OffsetMapping_LodDistance;
814         int loc_OffsetMapping_Bias;
815         int loc_PixelSize;
816         int loc_ReflectColor;
817         int loc_ReflectFactor;
818         int loc_ReflectOffset;
819         int loc_RefractColor;
820         int loc_Saturation;
821         int loc_ScreenCenterRefractReflect;
822         int loc_ScreenScaleRefractReflect;
823         int loc_ScreenToDepth;
824         int loc_ShadowMap_Parameters;
825         int loc_ShadowMap_TextureScale;
826         int loc_SpecularPower;
827         int loc_Skeletal_Transform12;
828         int loc_UserVec1;
829         int loc_UserVec2;
830         int loc_UserVec3;
831         int loc_UserVec4;
832         int loc_ViewTintColor;
833         int loc_ViewToLight;
834         int loc_ModelToLight;
835         int loc_TexMatrix;
836         int loc_BackgroundTexMatrix;
837         int loc_ModelViewProjectionMatrix;
838         int loc_ModelViewMatrix;
839         int loc_PixelToScreenTexCoord;
840         int loc_ModelToReflectCube;
841         int loc_ShadowMapMatrix;
842         int loc_BloomColorSubtract;
843         int loc_NormalmapScrollBlend;
844         int loc_BounceGridMatrix;
845         int loc_BounceGridIntensity;
846         /// uniform block bindings
847         int ubibind_Skeletal_Transform12_UniformBlock;
848         /// uniform block indices
849         int ubiloc_Skeletal_Transform12_UniformBlock;
850 }
851 r_glsl_permutation_t;
852
853 #define SHADERPERMUTATION_HASHSIZE 256
854
855
856 // non-degradable "lightweight" shader parameters to keep the permutations simpler
857 // these can NOT degrade! only use for simple stuff
858 enum
859 {
860         SHADERSTATICPARM_SATURATION_REDCOMPENSATE = 0, ///< red compensation filter for saturation
861         SHADERSTATICPARM_EXACTSPECULARMATH = 1, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
862         SHADERSTATICPARM_POSTPROCESS_USERVEC1 = 2, ///< postprocess uservec1 is enabled
863         SHADERSTATICPARM_POSTPROCESS_USERVEC2 = 3, ///< postprocess uservec2 is enabled
864         SHADERSTATICPARM_POSTPROCESS_USERVEC3 = 4, ///< postprocess uservec3 is enabled
865         SHADERSTATICPARM_POSTPROCESS_USERVEC4 = 5,  ///< postprocess uservec4 is enabled
866         SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS = 6, // use both alpha layers while blending materials, allows more advanced microblending
867         SHADERSTATICPARM_OFFSETMAPPING_USELOD = 7,  ///< LOD for offsetmapping
868         SHADERSTATICPARM_SHADOWMAPPCF_1 = 8, ///< PCF 1
869         SHADERSTATICPARM_SHADOWMAPPCF_2 = 9, ///< PCF 2
870         SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler
871         SHADERSTATICPARM_CELSHADING = 11, ///< celshading (alternative diffuse and specular math)
872         SHADERSTATICPARM_CELOUTLINES = 12, ///< celoutline (depth buffer analysis to produce outlines)
873         SHADERSTATICPARM_FXAA = 13 ///< fast approximate anti aliasing
874 };
875 #define SHADERSTATICPARMS_COUNT 14
876
877 static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT];
878 static int shaderstaticparms_count = 0;
879
880 static unsigned int r_compileshader_staticparms[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5] = {0};
881 #define R_COMPILESHADER_STATICPARM_ENABLE(p) r_compileshader_staticparms[(p) >> 5] |= (1 << ((p) & 0x1F))
882
883 extern qboolean r_shadow_shadowmapsampler;
884 extern int r_shadow_shadowmappcf;
885 qboolean R_CompileShader_CheckStaticParms(void)
886 {
887         static int r_compileshader_staticparms_save[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5];
888         memcpy(r_compileshader_staticparms_save, r_compileshader_staticparms, sizeof(r_compileshader_staticparms));
889         memset(r_compileshader_staticparms, 0, sizeof(r_compileshader_staticparms));
890
891         // detect all
892         if (r_glsl_saturation_redcompensate.integer)
893                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SATURATION_REDCOMPENSATE);
894         if (r_glsl_vertextextureblend_usebothalphas.integer)
895                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS);
896         if (r_shadow_glossexact.integer)
897                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_EXACTSPECULARMATH);
898         if (r_glsl_postprocess.integer)
899         {
900                 if (r_glsl_postprocess_uservec1_enable.integer)
901                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC1);
902                 if (r_glsl_postprocess_uservec2_enable.integer)
903                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC2);
904                 if (r_glsl_postprocess_uservec3_enable.integer)
905                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC3);
906                 if (r_glsl_postprocess_uservec4_enable.integer)
907                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC4);
908         }
909         if (r_fxaa.integer)
910                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_FXAA);
911         if (r_glsl_offsetmapping_lod.integer && r_glsl_offsetmapping_lod_distance.integer > 0)
912                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_OFFSETMAPPING_USELOD);
913
914         if (r_shadow_shadowmapsampler)
915                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWSAMPLER);
916         if (r_shadow_shadowmappcf > 1)
917                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_2);
918         else if (r_shadow_shadowmappcf)
919                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_1);
920         if (r_celshading.integer)
921                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELSHADING);
922         if (r_celoutlines.integer)
923                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELOUTLINES);
924
925         return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0;
926 }
927
928 #define R_COMPILESHADER_STATICPARM_EMIT(p, n) \
929         if(r_compileshader_staticparms[(p) >> 5] & (1 << ((p) & 0x1F))) \
930                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "#define " n "\n"; \
931         else \
932                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "\n"
933 static void R_CompileShader_AddStaticParms(unsigned int mode, dpuint64 permutation)
934 {
935         shaderstaticparms_count = 0;
936
937         // emit all
938         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SATURATION_REDCOMPENSATE, "SATURATION_REDCOMPENSATE");
939         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_EXACTSPECULARMATH, "USEEXACTSPECULARMATH");
940         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC1, "USERVEC1");
941         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC2, "USERVEC2");
942         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC3, "USERVEC3");
943         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC4, "USERVEC4");
944         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS, "USEBOTHALPHAS");
945         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_OFFSETMAPPING_USELOD, "USEOFFSETMAPPING_LOD");
946         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_1, "USESHADOWMAPPCF 1");
947         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_2, "USESHADOWMAPPCF 2");
948         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWSAMPLER, "USESHADOWSAMPLER");
949         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELSHADING, "USECELSHADING");
950         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELOUTLINES, "USECELOUTLINES");
951         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_FXAA, "USEFXAA");
952 }
953
954 /// information about each possible shader permutation
955 r_glsl_permutation_t *r_glsl_permutationhash[SHADERMODE_COUNT][SHADERPERMUTATION_HASHSIZE];
956 /// currently selected permutation
957 r_glsl_permutation_t *r_glsl_permutation;
958 /// storage for permutations linked in the hash table
959 memexpandablearray_t r_glsl_permutationarray;
960
961 static r_glsl_permutation_t *R_GLSL_FindPermutation(unsigned int mode, dpuint64 permutation)
962 {
963         //unsigned int hashdepth = 0;
964         unsigned int hashindex = (permutation * 0x1021) & (SHADERPERMUTATION_HASHSIZE - 1);
965         r_glsl_permutation_t *p;
966         for (p = r_glsl_permutationhash[mode][hashindex];p;p = p->hashnext)
967         {
968                 if (p->mode == mode && p->permutation == permutation)
969                 {
970                         //if (hashdepth > 10)
971                         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
972                         return p;
973                 }
974                 //hashdepth++;
975         }
976         p = (r_glsl_permutation_t*)Mem_ExpandableArray_AllocRecord(&r_glsl_permutationarray);
977         p->mode = mode;
978         p->permutation = permutation;
979         p->hashnext = r_glsl_permutationhash[mode][hashindex];
980         r_glsl_permutationhash[mode][hashindex] = p;
981         //if (hashdepth > 10)
982         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
983         return p;
984 }
985
986 static char *R_ShaderStrCat(const char **strings)
987 {
988         char *string, *s;
989         const char **p = strings;
990         const char *t;
991         size_t len = 0;
992         for (p = strings;(t = *p);p++)
993                 len += strlen(t);
994         len++;
995         s = string = (char *)Mem_Alloc(r_main_mempool, len);
996         len = 0;
997         for (p = strings;(t = *p);p++)
998         {
999                 len = strlen(t);
1000                 memcpy(s, t, len);
1001                 s += len;
1002         }
1003         *s = 0;
1004         return string;
1005 }
1006
1007 static char *R_ShaderStrCat(const char **strings);
1008 static void R_InitShaderModeInfo(void)
1009 {
1010         int i, language;
1011         shadermodeinfo_t *modeinfo;
1012         // we have a bunch of things to compute that weren't calculated at engine compile time - all filenames should have a crc of the builtin strings to prevent accidental overrides (any customization must be updated to match engine)
1013         for (language = 0; language < SHADERLANGUAGE_COUNT; language++)
1014         {
1015                 for (i = 0; i < SHADERMODE_COUNT; i++)
1016                 {
1017                         char filename[MAX_QPATH];
1018                         modeinfo = &shadermodeinfo[language][i];
1019                         modeinfo->builtinstring = R_ShaderStrCat(modeinfo->builtinshaderstrings);
1020                         modeinfo->builtincrc = CRC_Block((const unsigned char *)modeinfo->builtinstring, strlen(modeinfo->builtinstring));
1021                         dpsnprintf(filename, sizeof(filename), "%s/%s_crc%i.%s", modeinfo->extension, modeinfo->sourcebasename, modeinfo->builtincrc, modeinfo->extension);
1022                         modeinfo->filename = Mem_strdup(r_main_mempool, filename);
1023                 }
1024         }
1025 }
1026
1027 static char *ShaderModeInfo_GetShaderText(shadermodeinfo_t *modeinfo, qboolean printfromdisknotice, qboolean builtinonly)
1028 {
1029         char *shaderstring;
1030         // if the mode has no filename we have to return the builtin string
1031         if (builtinonly || !modeinfo->filename)
1032                 return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1033         // note that FS_LoadFile appends a 0 byte to make it a valid string
1034         shaderstring = (char *)FS_LoadFile(modeinfo->filename, r_main_mempool, false, NULL);
1035         if (shaderstring)
1036         {
1037                 if (printfromdisknotice)
1038                         Con_DPrintf("Loading shaders from file %s...\n", modeinfo->filename);
1039                 return shaderstring;
1040         }
1041         // fall back to builtinstring
1042         return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1043 }
1044
1045 static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, dpuint64 permutation)
1046 {
1047         int i;
1048         int ubibind;
1049         int sampler;
1050         shadermodeinfo_t *modeinfo = &shadermodeinfo[SHADERLANGUAGE_GLSL][mode];
1051         char *sourcestring;
1052         char permutationname[256];
1053         int vertstrings_count = 0;
1054         int geomstrings_count = 0;
1055         int fragstrings_count = 0;
1056         const char *vertstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1057         const char *geomstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1058         const char *fragstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1059
1060         if (p->compiled)
1061                 return;
1062         p->compiled = true;
1063         p->program = 0;
1064
1065         permutationname[0] = 0;
1066         sourcestring = ShaderModeInfo_GetShaderText(modeinfo, true, false);
1067
1068         strlcat(permutationname, modeinfo->filename, sizeof(permutationname));
1069
1070         // we need 140 for r_glsl_skeletal (GL_ARB_uniform_buffer_object)
1071         if(vid.support.glshaderversion >= 140)
1072         {
1073                 vertstrings_list[vertstrings_count++] = "#version 140\n";
1074                 geomstrings_list[geomstrings_count++] = "#version 140\n";
1075                 fragstrings_list[fragstrings_count++] = "#version 140\n";
1076                 vertstrings_list[vertstrings_count++] = "#define GLSL140\n";
1077                 geomstrings_list[geomstrings_count++] = "#define GLSL140\n";
1078                 fragstrings_list[fragstrings_count++] = "#define GLSL140\n";
1079         }
1080         // if we can do #version 130, we should (this improves quality of offset/reliefmapping thanks to textureGrad)
1081         else if(vid.support.glshaderversion >= 130)
1082         {
1083                 vertstrings_list[vertstrings_count++] = "#version 130\n";
1084                 geomstrings_list[geomstrings_count++] = "#version 130\n";
1085                 fragstrings_list[fragstrings_count++] = "#version 130\n";
1086                 vertstrings_list[vertstrings_count++] = "#define GLSL130\n";
1087                 geomstrings_list[geomstrings_count++] = "#define GLSL130\n";
1088                 fragstrings_list[fragstrings_count++] = "#define GLSL130\n";
1089         }
1090         // if we can do #version 120, we should (this adds the invariant keyword)
1091         else if(vid.support.glshaderversion >= 120)
1092         {
1093                 vertstrings_list[vertstrings_count++] = "#version 120\n";
1094                 geomstrings_list[geomstrings_count++] = "#version 120\n";
1095                 fragstrings_list[fragstrings_count++] = "#version 120\n";
1096                 vertstrings_list[vertstrings_count++] = "#define GLSL120\n";
1097                 geomstrings_list[geomstrings_count++] = "#define GLSL120\n";
1098                 fragstrings_list[fragstrings_count++] = "#define GLSL120\n";
1099         }
1100         // GLES also adds several things from GLSL120
1101         switch(vid.renderpath)
1102         {
1103         case RENDERPATH_GLES2:
1104                 vertstrings_list[vertstrings_count++] = "#define GLES\n";
1105                 geomstrings_list[geomstrings_count++] = "#define GLES\n";
1106                 fragstrings_list[fragstrings_count++] = "#define GLES\n";
1107                 break;
1108         default:
1109                 break;
1110         }
1111
1112         // the first pretext is which type of shader to compile as
1113         // (later these will all be bound together as a program object)
1114         vertstrings_list[vertstrings_count++] = "#define VERTEX_SHADER\n";
1115         geomstrings_list[geomstrings_count++] = "#define GEOMETRY_SHADER\n";
1116         fragstrings_list[fragstrings_count++] = "#define FRAGMENT_SHADER\n";
1117
1118         // the second pretext is the mode (for example a light source)
1119         vertstrings_list[vertstrings_count++] = modeinfo->pretext;
1120         geomstrings_list[geomstrings_count++] = modeinfo->pretext;
1121         fragstrings_list[fragstrings_count++] = modeinfo->pretext;
1122         strlcat(permutationname, modeinfo->name, sizeof(permutationname));
1123
1124         // now add all the permutation pretexts
1125         for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1126         {
1127                 if (permutation & (1ll<<i))
1128                 {
1129                         vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i].pretext;
1130                         geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i].pretext;
1131                         fragstrings_list[fragstrings_count++] = shaderpermutationinfo[i].pretext;
1132                         strlcat(permutationname, shaderpermutationinfo[i].name, sizeof(permutationname));
1133                 }
1134                 else
1135                 {
1136                         // keep line numbers correct
1137                         vertstrings_list[vertstrings_count++] = "\n";
1138                         geomstrings_list[geomstrings_count++] = "\n";
1139                         fragstrings_list[fragstrings_count++] = "\n";
1140                 }
1141         }
1142
1143         // add static parms
1144         R_CompileShader_AddStaticParms(mode, permutation);
1145         memcpy((char *)(vertstrings_list + vertstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1146         vertstrings_count += shaderstaticparms_count;
1147         memcpy((char *)(geomstrings_list + geomstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1148         geomstrings_count += shaderstaticparms_count;
1149         memcpy((char *)(fragstrings_list + fragstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1150         fragstrings_count += shaderstaticparms_count;
1151
1152         // now append the shader text itself
1153         vertstrings_list[vertstrings_count++] = sourcestring;
1154         geomstrings_list[geomstrings_count++] = sourcestring;
1155         fragstrings_list[fragstrings_count++] = sourcestring;
1156
1157         // compile the shader program
1158         if (vertstrings_count + geomstrings_count + fragstrings_count)
1159                 p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
1160         if (p->program)
1161         {
1162                 CHECKGLERROR
1163                 qglUseProgram(p->program);CHECKGLERROR
1164                 // look up all the uniform variable names we care about, so we don't
1165                 // have to look them up every time we set them
1166
1167 #if 0
1168                 // debugging aid
1169                 {
1170                         GLint activeuniformindex = 0;
1171                         GLint numactiveuniforms = 0;
1172                         char uniformname[128];
1173                         GLsizei uniformnamelength = 0;
1174                         GLint uniformsize = 0;
1175                         GLenum uniformtype = 0;
1176                         memset(uniformname, 0, sizeof(uniformname));
1177                         qglGetProgramiv(p->program, GL_ACTIVE_UNIFORMS, &numactiveuniforms);
1178                         Con_Printf("Shader has %i uniforms\n", numactiveuniforms);
1179                         for (activeuniformindex = 0;activeuniformindex < numactiveuniforms;activeuniformindex++)
1180                         {
1181                                 qglGetActiveUniform(p->program, activeuniformindex, sizeof(uniformname) - 1, &uniformnamelength, &uniformsize, &uniformtype, uniformname);
1182                                 Con_Printf("Uniform %i name \"%s\" size %i type %i\n", (int)activeuniformindex, uniformname, (int)uniformsize, (int)uniformtype);
1183                         }
1184                 }
1185 #endif
1186
1187                 p->loc_Texture_First              = qglGetUniformLocation(p->program, "Texture_First");
1188                 p->loc_Texture_Second             = qglGetUniformLocation(p->program, "Texture_Second");
1189                 p->loc_Texture_GammaRamps         = qglGetUniformLocation(p->program, "Texture_GammaRamps");
1190                 p->loc_Texture_Normal             = qglGetUniformLocation(p->program, "Texture_Normal");
1191                 p->loc_Texture_Color              = qglGetUniformLocation(p->program, "Texture_Color");
1192                 p->loc_Texture_Gloss              = qglGetUniformLocation(p->program, "Texture_Gloss");
1193                 p->loc_Texture_Glow               = qglGetUniformLocation(p->program, "Texture_Glow");
1194                 p->loc_Texture_SecondaryNormal    = qglGetUniformLocation(p->program, "Texture_SecondaryNormal");
1195                 p->loc_Texture_SecondaryColor     = qglGetUniformLocation(p->program, "Texture_SecondaryColor");
1196                 p->loc_Texture_SecondaryGloss     = qglGetUniformLocation(p->program, "Texture_SecondaryGloss");
1197                 p->loc_Texture_SecondaryGlow      = qglGetUniformLocation(p->program, "Texture_SecondaryGlow");
1198                 p->loc_Texture_Pants              = qglGetUniformLocation(p->program, "Texture_Pants");
1199                 p->loc_Texture_Shirt              = qglGetUniformLocation(p->program, "Texture_Shirt");
1200                 p->loc_Texture_FogHeightTexture   = qglGetUniformLocation(p->program, "Texture_FogHeightTexture");
1201                 p->loc_Texture_FogMask            = qglGetUniformLocation(p->program, "Texture_FogMask");
1202                 p->loc_Texture_Lightmap           = qglGetUniformLocation(p->program, "Texture_Lightmap");
1203                 p->loc_Texture_Deluxemap          = qglGetUniformLocation(p->program, "Texture_Deluxemap");
1204                 p->loc_Texture_Attenuation        = qglGetUniformLocation(p->program, "Texture_Attenuation");
1205                 p->loc_Texture_Cube               = qglGetUniformLocation(p->program, "Texture_Cube");
1206                 p->loc_Texture_Refraction         = qglGetUniformLocation(p->program, "Texture_Refraction");
1207                 p->loc_Texture_Reflection         = qglGetUniformLocation(p->program, "Texture_Reflection");
1208                 p->loc_Texture_ShadowMap2D        = qglGetUniformLocation(p->program, "Texture_ShadowMap2D");
1209                 p->loc_Texture_CubeProjection     = qglGetUniformLocation(p->program, "Texture_CubeProjection");
1210                 p->loc_Texture_ScreenNormalMap    = qglGetUniformLocation(p->program, "Texture_ScreenNormalMap");
1211                 p->loc_Texture_ScreenDiffuse      = qglGetUniformLocation(p->program, "Texture_ScreenDiffuse");
1212                 p->loc_Texture_ScreenSpecular     = qglGetUniformLocation(p->program, "Texture_ScreenSpecular");
1213                 p->loc_Texture_ReflectMask        = qglGetUniformLocation(p->program, "Texture_ReflectMask");
1214                 p->loc_Texture_ReflectCube        = qglGetUniformLocation(p->program, "Texture_ReflectCube");
1215                 p->loc_Texture_BounceGrid         = qglGetUniformLocation(p->program, "Texture_BounceGrid");
1216                 p->loc_Alpha                      = qglGetUniformLocation(p->program, "Alpha");
1217                 p->loc_BloomBlur_Parameters       = qglGetUniformLocation(p->program, "BloomBlur_Parameters");
1218                 p->loc_ClientTime                 = qglGetUniformLocation(p->program, "ClientTime");
1219                 p->loc_Color_Ambient              = qglGetUniformLocation(p->program, "Color_Ambient");
1220                 p->loc_Color_Diffuse              = qglGetUniformLocation(p->program, "Color_Diffuse");
1221                 p->loc_Color_Specular             = qglGetUniformLocation(p->program, "Color_Specular");
1222                 p->loc_Color_Glow                 = qglGetUniformLocation(p->program, "Color_Glow");
1223                 p->loc_Color_Pants                = qglGetUniformLocation(p->program, "Color_Pants");
1224                 p->loc_Color_Shirt                = qglGetUniformLocation(p->program, "Color_Shirt");
1225                 p->loc_DeferredColor_Ambient      = qglGetUniformLocation(p->program, "DeferredColor_Ambient");
1226                 p->loc_DeferredColor_Diffuse      = qglGetUniformLocation(p->program, "DeferredColor_Diffuse");
1227                 p->loc_DeferredColor_Specular     = qglGetUniformLocation(p->program, "DeferredColor_Specular");
1228                 p->loc_DeferredMod_Diffuse        = qglGetUniformLocation(p->program, "DeferredMod_Diffuse");
1229                 p->loc_DeferredMod_Specular       = qglGetUniformLocation(p->program, "DeferredMod_Specular");
1230                 p->loc_DistortScaleRefractReflect = qglGetUniformLocation(p->program, "DistortScaleRefractReflect");
1231                 p->loc_EyePosition                = qglGetUniformLocation(p->program, "EyePosition");
1232                 p->loc_FogColor                   = qglGetUniformLocation(p->program, "FogColor");
1233                 p->loc_FogHeightFade              = qglGetUniformLocation(p->program, "FogHeightFade");
1234                 p->loc_FogPlane                   = qglGetUniformLocation(p->program, "FogPlane");
1235                 p->loc_FogPlaneViewDist           = qglGetUniformLocation(p->program, "FogPlaneViewDist");
1236                 p->loc_FogRangeRecip              = qglGetUniformLocation(p->program, "FogRangeRecip");
1237                 p->loc_LightColor                 = qglGetUniformLocation(p->program, "LightColor");
1238                 p->loc_LightDir                   = qglGetUniformLocation(p->program, "LightDir");
1239                 p->loc_LightPosition              = qglGetUniformLocation(p->program, "LightPosition");
1240                 p->loc_OffsetMapping_ScaleSteps   = qglGetUniformLocation(p->program, "OffsetMapping_ScaleSteps");
1241                 p->loc_OffsetMapping_LodDistance  = qglGetUniformLocation(p->program, "OffsetMapping_LodDistance");
1242                 p->loc_OffsetMapping_Bias         = qglGetUniformLocation(p->program, "OffsetMapping_Bias");
1243                 p->loc_PixelSize                  = qglGetUniformLocation(p->program, "PixelSize");
1244                 p->loc_ReflectColor               = qglGetUniformLocation(p->program, "ReflectColor");
1245                 p->loc_ReflectFactor              = qglGetUniformLocation(p->program, "ReflectFactor");
1246                 p->loc_ReflectOffset              = qglGetUniformLocation(p->program, "ReflectOffset");
1247                 p->loc_RefractColor               = qglGetUniformLocation(p->program, "RefractColor");
1248                 p->loc_Saturation                 = qglGetUniformLocation(p->program, "Saturation");
1249                 p->loc_ScreenCenterRefractReflect = qglGetUniformLocation(p->program, "ScreenCenterRefractReflect");
1250                 p->loc_ScreenScaleRefractReflect  = qglGetUniformLocation(p->program, "ScreenScaleRefractReflect");
1251                 p->loc_ScreenToDepth              = qglGetUniformLocation(p->program, "ScreenToDepth");
1252                 p->loc_ShadowMap_Parameters       = qglGetUniformLocation(p->program, "ShadowMap_Parameters");
1253                 p->loc_ShadowMap_TextureScale     = qglGetUniformLocation(p->program, "ShadowMap_TextureScale");
1254                 p->loc_SpecularPower              = qglGetUniformLocation(p->program, "SpecularPower");
1255                 p->loc_UserVec1                   = qglGetUniformLocation(p->program, "UserVec1");
1256                 p->loc_UserVec2                   = qglGetUniformLocation(p->program, "UserVec2");
1257                 p->loc_UserVec3                   = qglGetUniformLocation(p->program, "UserVec3");
1258                 p->loc_UserVec4                   = qglGetUniformLocation(p->program, "UserVec4");
1259                 p->loc_ViewTintColor              = qglGetUniformLocation(p->program, "ViewTintColor");
1260                 p->loc_ViewToLight                = qglGetUniformLocation(p->program, "ViewToLight");
1261                 p->loc_ModelToLight               = qglGetUniformLocation(p->program, "ModelToLight");
1262                 p->loc_TexMatrix                  = qglGetUniformLocation(p->program, "TexMatrix");
1263                 p->loc_BackgroundTexMatrix        = qglGetUniformLocation(p->program, "BackgroundTexMatrix");
1264                 p->loc_ModelViewMatrix            = qglGetUniformLocation(p->program, "ModelViewMatrix");
1265                 p->loc_ModelViewProjectionMatrix  = qglGetUniformLocation(p->program, "ModelViewProjectionMatrix");
1266                 p->loc_PixelToScreenTexCoord      = qglGetUniformLocation(p->program, "PixelToScreenTexCoord");
1267                 p->loc_ModelToReflectCube         = qglGetUniformLocation(p->program, "ModelToReflectCube");
1268                 p->loc_ShadowMapMatrix            = qglGetUniformLocation(p->program, "ShadowMapMatrix");
1269                 p->loc_BloomColorSubtract         = qglGetUniformLocation(p->program, "BloomColorSubtract");
1270                 p->loc_NormalmapScrollBlend       = qglGetUniformLocation(p->program, "NormalmapScrollBlend");
1271                 p->loc_BounceGridMatrix           = qglGetUniformLocation(p->program, "BounceGridMatrix");
1272                 p->loc_BounceGridIntensity        = qglGetUniformLocation(p->program, "BounceGridIntensity");
1273                 // initialize the samplers to refer to the texture units we use
1274                 p->tex_Texture_First = -1;
1275                 p->tex_Texture_Second = -1;
1276                 p->tex_Texture_GammaRamps = -1;
1277                 p->tex_Texture_Normal = -1;
1278                 p->tex_Texture_Color = -1;
1279                 p->tex_Texture_Gloss = -1;
1280                 p->tex_Texture_Glow = -1;
1281                 p->tex_Texture_SecondaryNormal = -1;
1282                 p->tex_Texture_SecondaryColor = -1;
1283                 p->tex_Texture_SecondaryGloss = -1;
1284                 p->tex_Texture_SecondaryGlow = -1;
1285                 p->tex_Texture_Pants = -1;
1286                 p->tex_Texture_Shirt = -1;
1287                 p->tex_Texture_FogHeightTexture = -1;
1288                 p->tex_Texture_FogMask = -1;
1289                 p->tex_Texture_Lightmap = -1;
1290                 p->tex_Texture_Deluxemap = -1;
1291                 p->tex_Texture_Attenuation = -1;
1292                 p->tex_Texture_Cube = -1;
1293                 p->tex_Texture_Refraction = -1;
1294                 p->tex_Texture_Reflection = -1;
1295                 p->tex_Texture_ShadowMap2D = -1;
1296                 p->tex_Texture_CubeProjection = -1;
1297                 p->tex_Texture_ScreenNormalMap = -1;
1298                 p->tex_Texture_ScreenDiffuse = -1;
1299                 p->tex_Texture_ScreenSpecular = -1;
1300                 p->tex_Texture_ReflectMask = -1;
1301                 p->tex_Texture_ReflectCube = -1;
1302                 p->tex_Texture_BounceGrid = -1;
1303                 // bind the texture samplers in use
1304                 sampler = 0;
1305                 if (p->loc_Texture_First           >= 0) {p->tex_Texture_First            = sampler;qglUniform1i(p->loc_Texture_First           , sampler);sampler++;}
1306                 if (p->loc_Texture_Second          >= 0) {p->tex_Texture_Second           = sampler;qglUniform1i(p->loc_Texture_Second          , sampler);sampler++;}
1307                 if (p->loc_Texture_GammaRamps      >= 0) {p->tex_Texture_GammaRamps       = sampler;qglUniform1i(p->loc_Texture_GammaRamps      , sampler);sampler++;}
1308                 if (p->loc_Texture_Normal          >= 0) {p->tex_Texture_Normal           = sampler;qglUniform1i(p->loc_Texture_Normal          , sampler);sampler++;}
1309                 if (p->loc_Texture_Color           >= 0) {p->tex_Texture_Color            = sampler;qglUniform1i(p->loc_Texture_Color           , sampler);sampler++;}
1310                 if (p->loc_Texture_Gloss           >= 0) {p->tex_Texture_Gloss            = sampler;qglUniform1i(p->loc_Texture_Gloss           , sampler);sampler++;}
1311                 if (p->loc_Texture_Glow            >= 0) {p->tex_Texture_Glow             = sampler;qglUniform1i(p->loc_Texture_Glow            , sampler);sampler++;}
1312                 if (p->loc_Texture_SecondaryNormal >= 0) {p->tex_Texture_SecondaryNormal  = sampler;qglUniform1i(p->loc_Texture_SecondaryNormal , sampler);sampler++;}
1313                 if (p->loc_Texture_SecondaryColor  >= 0) {p->tex_Texture_SecondaryColor   = sampler;qglUniform1i(p->loc_Texture_SecondaryColor  , sampler);sampler++;}
1314                 if (p->loc_Texture_SecondaryGloss  >= 0) {p->tex_Texture_SecondaryGloss   = sampler;qglUniform1i(p->loc_Texture_SecondaryGloss  , sampler);sampler++;}
1315                 if (p->loc_Texture_SecondaryGlow   >= 0) {p->tex_Texture_SecondaryGlow    = sampler;qglUniform1i(p->loc_Texture_SecondaryGlow   , sampler);sampler++;}
1316                 if (p->loc_Texture_Pants           >= 0) {p->tex_Texture_Pants            = sampler;qglUniform1i(p->loc_Texture_Pants           , sampler);sampler++;}
1317                 if (p->loc_Texture_Shirt           >= 0) {p->tex_Texture_Shirt            = sampler;qglUniform1i(p->loc_Texture_Shirt           , sampler);sampler++;}
1318                 if (p->loc_Texture_FogHeightTexture>= 0) {p->tex_Texture_FogHeightTexture = sampler;qglUniform1i(p->loc_Texture_FogHeightTexture, sampler);sampler++;}
1319                 if (p->loc_Texture_FogMask         >= 0) {p->tex_Texture_FogMask          = sampler;qglUniform1i(p->loc_Texture_FogMask         , sampler);sampler++;}
1320                 if (p->loc_Texture_Lightmap        >= 0) {p->tex_Texture_Lightmap         = sampler;qglUniform1i(p->loc_Texture_Lightmap        , sampler);sampler++;}
1321                 if (p->loc_Texture_Deluxemap       >= 0) {p->tex_Texture_Deluxemap        = sampler;qglUniform1i(p->loc_Texture_Deluxemap       , sampler);sampler++;}
1322                 if (p->loc_Texture_Attenuation     >= 0) {p->tex_Texture_Attenuation      = sampler;qglUniform1i(p->loc_Texture_Attenuation     , sampler);sampler++;}
1323                 if (p->loc_Texture_Cube            >= 0) {p->tex_Texture_Cube             = sampler;qglUniform1i(p->loc_Texture_Cube            , sampler);sampler++;}
1324                 if (p->loc_Texture_Refraction      >= 0) {p->tex_Texture_Refraction       = sampler;qglUniform1i(p->loc_Texture_Refraction      , sampler);sampler++;}
1325                 if (p->loc_Texture_Reflection      >= 0) {p->tex_Texture_Reflection       = sampler;qglUniform1i(p->loc_Texture_Reflection      , sampler);sampler++;}
1326                 if (p->loc_Texture_ShadowMap2D     >= 0) {p->tex_Texture_ShadowMap2D      = sampler;qglUniform1i(p->loc_Texture_ShadowMap2D     , sampler);sampler++;}
1327                 if (p->loc_Texture_CubeProjection  >= 0) {p->tex_Texture_CubeProjection   = sampler;qglUniform1i(p->loc_Texture_CubeProjection  , sampler);sampler++;}
1328                 if (p->loc_Texture_ScreenNormalMap >= 0) {p->tex_Texture_ScreenNormalMap  = sampler;qglUniform1i(p->loc_Texture_ScreenNormalMap , sampler);sampler++;}
1329                 if (p->loc_Texture_ScreenDiffuse   >= 0) {p->tex_Texture_ScreenDiffuse    = sampler;qglUniform1i(p->loc_Texture_ScreenDiffuse   , sampler);sampler++;}
1330                 if (p->loc_Texture_ScreenSpecular  >= 0) {p->tex_Texture_ScreenSpecular   = sampler;qglUniform1i(p->loc_Texture_ScreenSpecular  , sampler);sampler++;}
1331                 if (p->loc_Texture_ReflectMask     >= 0) {p->tex_Texture_ReflectMask      = sampler;qglUniform1i(p->loc_Texture_ReflectMask     , sampler);sampler++;}
1332                 if (p->loc_Texture_ReflectCube     >= 0) {p->tex_Texture_ReflectCube      = sampler;qglUniform1i(p->loc_Texture_ReflectCube     , sampler);sampler++;}
1333                 if (p->loc_Texture_BounceGrid      >= 0) {p->tex_Texture_BounceGrid       = sampler;qglUniform1i(p->loc_Texture_BounceGrid      , sampler);sampler++;}
1334                 // get the uniform block indices so we can bind them
1335 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1336                 if (vid.support.arb_uniform_buffer_object)
1337                         p->ubiloc_Skeletal_Transform12_UniformBlock = qglGetUniformBlockIndex(p->program, "Skeletal_Transform12_UniformBlock");
1338                 else
1339 #endif
1340                         p->ubiloc_Skeletal_Transform12_UniformBlock = -1;
1341                 // clear the uniform block bindings
1342                 p->ubibind_Skeletal_Transform12_UniformBlock = -1;
1343                 // bind the uniform blocks in use
1344                 ubibind = 0;
1345 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1346                 if (p->ubiloc_Skeletal_Transform12_UniformBlock >= 0) {p->ubibind_Skeletal_Transform12_UniformBlock = ubibind;qglUniformBlockBinding(p->program, p->ubiloc_Skeletal_Transform12_UniformBlock, ubibind);ubibind++;}
1347 #endif
1348                 // we're done compiling and setting up the shader, at least until it is used
1349                 CHECKGLERROR
1350                 Con_DPrintf("^5GLSL shader %s compiled (%i textures).\n", permutationname, sampler);
1351         }
1352         else
1353                 Con_Printf("^1GLSL shader %s failed!  some features may not work properly.\n", permutationname);
1354
1355         // free the strings
1356         if (sourcestring)
1357                 Mem_Free(sourcestring);
1358 }
1359
1360 static void R_SetupShader_SetPermutationGLSL(unsigned int mode, dpuint64 permutation)
1361 {
1362         r_glsl_permutation_t *perm = R_GLSL_FindPermutation(mode, permutation);
1363         if (r_glsl_permutation != perm)
1364         {
1365                 r_glsl_permutation = perm;
1366                 if (!r_glsl_permutation->program)
1367                 {
1368                         if (!r_glsl_permutation->compiled)
1369                         {
1370                                 Con_DPrintf("Compiling shader mode %u permutation %u\n", mode, permutation);
1371                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1372                         }
1373                         if (!r_glsl_permutation->program)
1374                         {
1375                                 // remove features until we find a valid permutation
1376                                 int i;
1377                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1378                                 {
1379                                         // reduce i more quickly whenever it would not remove any bits
1380                                         dpuint64 j = 1ll<<(SHADERPERMUTATION_COUNT-1-i);
1381                                         if (!(permutation & j))
1382                                                 continue;
1383                                         permutation -= j;
1384                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1385                                         if (!r_glsl_permutation->compiled)
1386                                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1387                                         if (r_glsl_permutation->program)
1388                                                 break;
1389                                 }
1390                                 if (i >= SHADERPERMUTATION_COUNT)
1391                                 {
1392                                         //Con_Printf("Could not find a working OpenGL 2.0 shader for permutation %s %s\n", shadermodeinfo[mode].filename, shadermodeinfo[mode].pretext);
1393                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1394                                         qglUseProgram(0);CHECKGLERROR
1395                                         return; // no bit left to clear, entire mode is broken
1396                                 }
1397                         }
1398                 }
1399                 CHECKGLERROR
1400                 qglUseProgram(r_glsl_permutation->program);CHECKGLERROR
1401         }
1402         if (r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
1403         if (r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
1404         if (r_glsl_permutation->loc_ClientTime >= 0) qglUniform1f(r_glsl_permutation->loc_ClientTime, cl.time);
1405         CHECKGLERROR
1406 }
1407
1408 void R_GLSL_Restart_f(void)
1409 {
1410         unsigned int i, limit;
1411         switch(vid.renderpath)
1412         {
1413         case RENDERPATH_GL20:
1414         case RENDERPATH_GLES2:
1415                 {
1416                         r_glsl_permutation_t *p;
1417                         r_glsl_permutation = NULL;
1418                         limit = (unsigned int)Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
1419                         for (i = 0;i < limit;i++)
1420                         {
1421                                 if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i)))
1422                                 {
1423                                         GL_Backend_FreeProgram(p->program);
1424                                         Mem_ExpandableArray_FreeRecord(&r_glsl_permutationarray, (void*)p);
1425                                 }
1426                         }
1427                         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
1428                 }
1429                 break;
1430         }
1431 }
1432
1433 static void R_GLSL_DumpShader_f(void)
1434 {
1435         int i, language, mode, dupe;
1436         char *text;
1437         shadermodeinfo_t *modeinfo;
1438         qfile_t *file;
1439
1440         for (language = 0;language < SHADERLANGUAGE_COUNT;language++)
1441         {
1442                 modeinfo = shadermodeinfo[language];
1443                 for (mode = 0;mode < SHADERMODE_COUNT;mode++)
1444                 {
1445                         // don't dump the same file multiple times (most or all shaders come from the same file)
1446                         for (dupe = mode - 1;dupe >= 0;dupe--)
1447                                 if (!strcmp(modeinfo[mode].filename, modeinfo[dupe].filename))
1448                                         break;
1449                         if (dupe >= 0)
1450                                 continue;
1451                         text = modeinfo[mode].builtinstring;
1452                         if (!text)
1453                                 continue;
1454                         file = FS_OpenRealFile(modeinfo[mode].filename, "w", false);
1455                         if (file)
1456                         {
1457                                 FS_Print(file, "/* The engine may define the following macros:\n");
1458                                 FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
1459                                 for (i = 0;i < SHADERMODE_COUNT;i++)
1460                                         FS_Print(file, modeinfo[i].pretext);
1461                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1462                                         FS_Print(file, shaderpermutationinfo[i].pretext);
1463                                 FS_Print(file, "*/\n");
1464                                 FS_Print(file, text);
1465                                 FS_Close(file);
1466                                 Con_Printf("%s written\n", modeinfo[mode].filename);
1467                         }
1468                         else
1469                                 Con_Printf("failed to write to %s\n", modeinfo[mode].filename);
1470                 }
1471         }
1472 }
1473
1474 void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemode, int rgbscale, qboolean usegamma, qboolean notrippy, qboolean suppresstexalpha)
1475 {
1476         dpuint64 permutation = 0;
1477         if (r_trippy.integer && !notrippy)
1478                 permutation |= SHADERPERMUTATION_TRIPPY;
1479         permutation |= SHADERPERMUTATION_VIEWTINT;
1480         if (first)
1481                 permutation |= SHADERPERMUTATION_DIFFUSE;
1482         if (second)
1483                 permutation |= SHADERPERMUTATION_SPECULAR;
1484         if (texturemode == GL_MODULATE)
1485                 permutation |= SHADERPERMUTATION_COLORMAPPING;
1486         else if (texturemode == GL_ADD)
1487                 permutation |= SHADERPERMUTATION_GLOW;
1488         else if (texturemode == GL_DECAL)
1489                 permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1490         if (usegamma && v_glslgamma_2d.integer && !vid.sRGB2D && r_texture_gammaramps && !vid_gammatables_trivial)
1491                 permutation |= SHADERPERMUTATION_GAMMARAMPS;
1492         if (suppresstexalpha)
1493                 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1494         if (!second)
1495                 texturemode = GL_MODULATE;
1496         if (vid.allowalphatocoverage)
1497                 GL_AlphaToCoverage(false);
1498         switch (vid.renderpath)
1499         {
1500         case RENDERPATH_GL20:
1501         case RENDERPATH_GLES2:
1502                 R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, permutation);
1503                 if (r_glsl_permutation->tex_Texture_First >= 0)
1504                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First , first );
1505                 if (r_glsl_permutation->tex_Texture_Second >= 0)
1506                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second, second);
1507                 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0)
1508                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps);
1509                 break;
1510         }
1511 }
1512
1513 void R_SetupShader_Generic_NoTexture(qboolean usegamma, qboolean notrippy)
1514 {
1515         R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, usegamma, notrippy, false);
1516 }
1517
1518 void R_SetupShader_DepthOrShadow(qboolean notrippy, qboolean depthrgb, qboolean skeletal)
1519 {
1520         dpuint64 permutation = 0;
1521         if (r_trippy.integer && !notrippy)
1522                 permutation |= SHADERPERMUTATION_TRIPPY;
1523         if (depthrgb)
1524                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1525         if (skeletal)
1526                 permutation |= SHADERPERMUTATION_SKELETAL;
1527
1528         if (vid.allowalphatocoverage)
1529                 GL_AlphaToCoverage(false);
1530         switch (vid.renderpath)
1531         {
1532         case RENDERPATH_GL20:
1533         case RENDERPATH_GLES2:
1534                 R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation);
1535 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1536                 if (r_glsl_permutation->ubiloc_Skeletal_Transform12_UniformBlock >= 0 && rsurface.batchskeletaltransform3x4buffer) qglBindBufferRange(GL_UNIFORM_BUFFER, r_glsl_permutation->ubibind_Skeletal_Transform12_UniformBlock, rsurface.batchskeletaltransform3x4buffer->bufferobject, rsurface.batchskeletaltransform3x4offset, rsurface.batchskeletaltransform3x4size);
1537 #endif
1538                 break;
1539         }
1540 }
1541
1542 #define BLENDFUNC_ALLOWS_COLORMOD      1
1543 #define BLENDFUNC_ALLOWS_FOG           2
1544 #define BLENDFUNC_ALLOWS_FOG_HACK0     4
1545 #define BLENDFUNC_ALLOWS_FOG_HACKALPHA 8
1546 #define BLENDFUNC_ALLOWS_ANYFOG        (BLENDFUNC_ALLOWS_FOG | BLENDFUNC_ALLOWS_FOG_HACK0 | BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1547 static int R_BlendFuncFlags(int src, int dst)
1548 {
1549         int r = 0;
1550
1551         // a blendfunc allows colormod if:
1552         // a) it can never keep the destination pixel invariant, or
1553         // b) it can keep the destination pixel invariant, and still can do so if colormodded
1554         // this is to prevent unintended side effects from colormod
1555
1556         // a blendfunc allows fog if:
1557         // blend(fog(src), fog(dst)) == fog(blend(src, dst))
1558         // this is to prevent unintended side effects from fog
1559
1560         // these checks are the output of fogeval.pl
1561
1562         r |= BLENDFUNC_ALLOWS_COLORMOD;
1563         if(src == GL_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1564         if(src == GL_DST_ALPHA && dst == GL_ONE_MINUS_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1565         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1566         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1567         if(src == GL_DST_COLOR && dst == GL_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1568         if(src == GL_DST_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1569         if(src == GL_DST_COLOR && dst == GL_ZERO) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1570         if(src == GL_ONE && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1571         if(src == GL_ONE && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG_HACKALPHA;
1572         if(src == GL_ONE && dst == GL_ZERO) r |= BLENDFUNC_ALLOWS_FOG;
1573         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1574         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1575         if(src == GL_ONE_MINUS_DST_COLOR && dst == GL_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1576         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1577         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1578         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1579         if(src == GL_ONE_MINUS_SRC_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1580         if(src == GL_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1581         if(src == GL_SRC_ALPHA && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1582         if(src == GL_ZERO && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG;
1583         if(src == GL_ZERO && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1584
1585         return r;
1586 }
1587
1588 void R_SetupShader_Surface(const float rtlightambient[3], const float rtlightdiffuse[3], const float rtlightspecular[3], rsurfacepass_t rsurfacepass, int texturenumsurfaces, const msurface_t **texturesurfacelist, void *surfacewaterplane, qboolean notrippy)
1589 {
1590         // select a permutation of the lighting shader appropriate to this
1591         // combination of texture, entity, light source, and fogging, only use the
1592         // minimum features necessary to avoid wasting rendering time in the
1593         // fragment shader on features that are not being used
1594         dpuint64 permutation = 0;
1595         unsigned int mode = 0;
1596         int blendfuncflags;
1597         texture_t *t = rsurface.texture;
1598         float m16f[16];
1599         matrix4x4_t tempmatrix;
1600         r_waterstate_waterplane_t *waterplane = (r_waterstate_waterplane_t *)surfacewaterplane;
1601         if (r_trippy.integer && !notrippy)
1602                 permutation |= SHADERPERMUTATION_TRIPPY;
1603         if (t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1604                 permutation |= SHADERPERMUTATION_ALPHAKILL;
1605         if (t->currentmaterialflags & MATERIALFLAG_OCCLUDE)
1606                 permutation |= SHADERPERMUTATION_OCCLUDE;
1607         if (t->r_water_waterscroll[0] && t->r_water_waterscroll[1])
1608                 permutation |= SHADERPERMUTATION_NORMALMAPSCROLLBLEND; // todo: make generic
1609         if (rsurfacepass == RSURFPASS_BACKGROUND)
1610         {
1611                 // distorted background
1612                 if (t->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1613                 {
1614                         mode = SHADERMODE_WATER;
1615                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1616                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1617                         if((r_wateralpha.value < 1) && (t->currentmaterialflags & MATERIALFLAG_WATERALPHA))
1618                         {
1619                                 // this is the right thing to do for wateralpha
1620                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1621                                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1622                         }
1623                         else
1624                         {
1625                                 // this is the right thing to do for entity alpha
1626                                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1627                                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1628                         }
1629                 }
1630                 else if (t->currentmaterialflags & MATERIALFLAG_REFRACTION)
1631                 {
1632                         mode = SHADERMODE_REFRACTION;
1633                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1634                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1635                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1636                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1637                 }
1638                 else
1639                 {
1640                         mode = SHADERMODE_GENERIC;
1641                         permutation |= SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_ALPHAKILL;
1642                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1643                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1644                 }
1645                 if (vid.allowalphatocoverage)
1646                         GL_AlphaToCoverage(false);
1647         }
1648         else if (rsurfacepass == RSURFPASS_DEFERREDGEOMETRY)
1649         {
1650                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1651                 {
1652                         switch(t->offsetmapping)
1653                         {
1654                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1655                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1656                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1657                         case OFFSETMAPPING_OFF: break;
1658                         }
1659                 }
1660                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1661                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1662                 // normalmap (deferred prepass), may use alpha test on diffuse
1663                 mode = SHADERMODE_DEFERREDGEOMETRY;
1664                 GL_BlendFunc(GL_ONE, GL_ZERO);
1665                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1666                 if (vid.allowalphatocoverage)
1667                         GL_AlphaToCoverage(false);
1668         }
1669         else if (rsurfacepass == RSURFPASS_RTLIGHT)
1670         {
1671                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1672                 {
1673                         switch(t->offsetmapping)
1674                         {
1675                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1676                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1677                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1678                         case OFFSETMAPPING_OFF: break;
1679                         }
1680                 }
1681                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1682                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1683                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1684                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1685                 // light source
1686                 mode = SHADERMODE_LIGHTSOURCE;
1687                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1688                         permutation |= SHADERPERMUTATION_CUBEFILTER;
1689                 if (VectorLength2(rtlightdiffuse) > 0)
1690                         permutation |= SHADERPERMUTATION_DIFFUSE;
1691                 if (VectorLength2(rtlightspecular) > 0)
1692                         permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1693                 if (r_refdef.fogenabled)
1694                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1695                 if (t->colormapping)
1696                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1697                 if (r_shadow_usingshadowmap2d)
1698                 {
1699                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1700                         if(r_shadow_shadowmapvsdct)
1701                                 permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
1702
1703                         if (r_shadow_shadowmap2ddepthbuffer)
1704                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1705                 }
1706                 if (t->reflectmasktexture)
1707                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1708                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1709                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE);
1710                 if (vid.allowalphatocoverage)
1711                         GL_AlphaToCoverage(false);
1712         }
1713         else if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
1714         {
1715                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1716                 {
1717                         switch(t->offsetmapping)
1718                         {
1719                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1720                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1721                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1722                         case OFFSETMAPPING_OFF: break;
1723                         }
1724                 }
1725                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1726                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1727                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1728                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1729                 // directional model lighting
1730                 mode = SHADERMODE_LIGHTDIRECTION;
1731                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1732                         permutation |= SHADERPERMUTATION_GLOW;
1733                 if (VectorLength2(t->render_modellight_diffuse))
1734                         permutation |= SHADERPERMUTATION_DIFFUSE;
1735                 if (VectorLength2(t->render_modellight_specular) > 0)
1736                         permutation |= SHADERPERMUTATION_SPECULAR;
1737                 if (r_refdef.fogenabled)
1738                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1739                 if (t->colormapping)
1740                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1741                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1742                 {
1743                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1744                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1745
1746                         if (r_shadow_shadowmap2ddepthbuffer)
1747                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1748                 }
1749                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1750                         permutation |= SHADERPERMUTATION_REFLECTION;
1751                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1752                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1753                 if (t->reflectmasktexture)
1754                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1755                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld)
1756                 {
1757                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1758                         if (r_shadow_bouncegrid_state.directional)
1759                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1760                 }
1761                 GL_BlendFunc(t->currentlayers[0].blendfunc1, t->currentlayers[0].blendfunc2);
1762                 blendfuncflags = R_BlendFuncFlags(t->currentlayers[0].blendfunc1, t->currentlayers[0].blendfunc2);
1763                 // when using alphatocoverage, we don't need alphakill
1764                 if (vid.allowalphatocoverage)
1765                 {
1766                         if (r_transparent_alphatocoverage.integer)
1767                         {
1768                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1769                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1770                         }
1771                         else
1772                                 GL_AlphaToCoverage(false);
1773                 }
1774         }
1775         else
1776         {
1777                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1778                 {
1779                         switch(t->offsetmapping)
1780                         {
1781                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1782                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1783                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1784                         case OFFSETMAPPING_OFF: break;
1785                         }
1786                 }
1787                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1788                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1789                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1790                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1791                 // lightmapped wall
1792                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1793                         permutation |= SHADERPERMUTATION_GLOW;
1794                 if (r_refdef.fogenabled)
1795                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1796                 if (t->colormapping)
1797                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1798                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1799                 {
1800                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1801                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1802
1803                         if (r_shadow_shadowmap2ddepthbuffer)
1804                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1805                 }
1806                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1807                         permutation |= SHADERPERMUTATION_REFLECTION;
1808                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1809                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1810                 if (t->reflectmasktexture)
1811                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1812                 if (FAKELIGHT_ENABLED)
1813                 {
1814                         // fake lightmapping (q1bsp, q3bsp, fullbright map)
1815                         mode = SHADERMODE_FAKELIGHT;
1816                         permutation |= SHADERPERMUTATION_DIFFUSE;
1817                         if (VectorLength2(t->render_lightmap_specular) > 0)
1818                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1819                 }
1820                 else if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping)
1821                 {
1822                         // deluxemapping (light direction texture)
1823                         if (rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping && r_refdef.scene.worldmodel->brushq3.deluxemapping_modelspace)
1824                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE;
1825                         else
1826                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1827                         permutation |= SHADERPERMUTATION_DIFFUSE;
1828                         if (VectorLength2(t->render_lightmap_specular) > 0)
1829                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1830                 }
1831                 else if (r_glsl_deluxemapping.integer >= 2)
1832                 {
1833                         // fake deluxemapping (uniform light direction in tangentspace)
1834                         if (rsurface.uselightmaptexture)
1835                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP;
1836                         else
1837                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR;
1838                         permutation |= SHADERPERMUTATION_DIFFUSE;
1839                         if (VectorLength2(t->render_lightmap_specular) > 0)
1840                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1841                 }
1842                 else if (rsurface.uselightmaptexture)
1843                 {
1844                         // ordinary lightmapping (q1bsp, q3bsp)
1845                         mode = SHADERMODE_LIGHTMAP;
1846                 }
1847                 else
1848                 {
1849                         // ordinary vertex coloring (q3bsp)
1850                         mode = SHADERMODE_VERTEXCOLOR;
1851                 }
1852                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld)
1853                 {
1854                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1855                         if (r_shadow_bouncegrid_state.directional)
1856                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1857                 }
1858                 GL_BlendFunc(t->currentlayers[0].blendfunc1, t->currentlayers[0].blendfunc2);
1859                 blendfuncflags = R_BlendFuncFlags(t->currentlayers[0].blendfunc1, t->currentlayers[0].blendfunc2);
1860                 // when using alphatocoverage, we don't need alphakill
1861                 if (vid.allowalphatocoverage)
1862                 {
1863                         if (r_transparent_alphatocoverage.integer)
1864                         {
1865                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1866                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1867                         }
1868                         else
1869                                 GL_AlphaToCoverage(false);
1870                 }
1871         }
1872         if(!(blendfuncflags & BLENDFUNC_ALLOWS_ANYFOG))
1873                 permutation &= ~(SHADERPERMUTATION_FOGHEIGHTTEXTURE | SHADERPERMUTATION_FOGOUTSIDE | SHADERPERMUTATION_FOGINSIDE);
1874         if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1875                 permutation |= SHADERPERMUTATION_FOGALPHAHACK;
1876         switch(vid.renderpath)
1877         {
1878         case RENDERPATH_GL20:
1879         case RENDERPATH_GLES2:
1880                 if (!vid.useinterleavedarrays)
1881                 {
1882                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | (rsurface.modellightmapcolor4f ? BATCHNEED_ARRAY_VERTEXCOLOR : 0) | BATCHNEED_ARRAY_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_ARRAY_LIGHTMAP : 0) | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
1883                         R_Mesh_VertexPointer(     3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
1884                         R_Mesh_ColorPointer(      4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset);
1885                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
1886                         R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchsvector3f, rsurface.batchsvector3f_vertexbuffer, rsurface.batchsvector3f_bufferoffset);
1887                         R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset);
1888                         R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset);
1889                         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset);
1890                         R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
1891                         R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, rsurface.batchskeletalindex4ub_vertexbuffer, rsurface.batchskeletalindex4ub_bufferoffset);
1892                         R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, rsurface.batchskeletalweight4ub_vertexbuffer, rsurface.batchskeletalweight4ub_bufferoffset);
1893                 }
1894                 else
1895                 {
1896                         RSurf_PrepareVerticesForBatch(BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | (rsurface.modellightmapcolor4f ? BATCHNEED_VERTEXMESH_VERTEXCOLOR : 0) | BATCHNEED_VERTEXMESH_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_VERTEXMESH_LIGHTMAP : 0) | (rsurface.entityskeletaltransform3x4 ? BATCHNEED_VERTEXMESH_SKELETAL : 0) | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
1897                         R_Mesh_PrepareVertices_Mesh(rsurface.batchnumvertices, rsurface.batchvertexmesh, rsurface.batchvertexmesh_vertexbuffer, rsurface.batchvertexmesh_bufferoffset);
1898                 }
1899                 // this has to be after RSurf_PrepareVerticesForBatch
1900                 if (rsurface.batchskeletaltransform3x4buffer)
1901                         permutation |= SHADERPERMUTATION_SKELETAL;
1902                 R_SetupShader_SetPermutationGLSL(mode, permutation);
1903 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1904                 if (r_glsl_permutation->ubiloc_Skeletal_Transform12_UniformBlock >= 0 && rsurface.batchskeletaltransform3x4buffer) qglBindBufferRange(GL_UNIFORM_BUFFER, r_glsl_permutation->ubibind_Skeletal_Transform12_UniformBlock, rsurface.batchskeletaltransform3x4buffer->bufferobject, rsurface.batchskeletaltransform3x4offset, rsurface.batchskeletaltransform3x4size);
1905 #endif
1906                 if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);}
1907                 if (mode == SHADERMODE_LIGHTSOURCE)
1908                 {
1909                         if (r_glsl_permutation->loc_ModelToLight >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToLight, 1, false, m16f);}
1910                         if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
1911                         if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1912                         if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, rtlightambient[0], rtlightambient[1], rtlightambient[2]);
1913                         if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, rtlightdiffuse[0], rtlightdiffuse[1], rtlightdiffuse[2]);
1914                         if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, rtlightspecular[0], rtlightspecular[1], rtlightspecular[2]);
1915         
1916                         // additive passes are only darkened by fog, not tinted
1917                         if (r_glsl_permutation->loc_FogColor >= 0)
1918                                 qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1919                         if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1f(r_glsl_permutation->loc_SpecularPower, t->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
1920                 }
1921                 else
1922                 {
1923                         if (mode == SHADERMODE_FLATCOLOR)
1924                         {
1925                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_modellight_ambient[0], t->render_modellight_ambient[1], t->render_modellight_ambient[2]);
1926                         }
1927                         else if (mode == SHADERMODE_LIGHTDIRECTION)
1928                         {
1929                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_modellight_ambient[0], t->render_modellight_ambient[1], t->render_modellight_ambient[2]);
1930                                 if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, t->render_modellight_diffuse[0], t->render_modellight_diffuse[1], t->render_modellight_diffuse[2]);
1931                                 if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, t->render_modellight_specular[0], t->render_modellight_specular[1], t->render_modellight_specular[2]);
1932                                 if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Diffuse, t->render_rtlight_diffuse[0], t->render_rtlight_diffuse[1], t->render_rtlight_diffuse[2]);
1933                                 if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, t->render_rtlight_specular[0], t->render_rtlight_specular[1], t->render_rtlight_specular[2]);
1934                                 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1935                                 if (r_glsl_permutation->loc_LightDir >= 0) qglUniform3f(r_glsl_permutation->loc_LightDir, t->render_modellight_lightdir[0], t->render_modellight_lightdir[1], t->render_modellight_lightdir[2]);
1936                         }
1937                         else
1938                         {
1939                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_lightmap_ambient[0], t->render_lightmap_ambient[1], t->render_lightmap_ambient[2]);
1940                                 if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, t->render_lightmap_diffuse[0], t->render_lightmap_diffuse[1], t->render_lightmap_diffuse[2]);
1941                                 if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, t->render_lightmap_specular[0], t->render_lightmap_specular[1], t->render_lightmap_specular[2]);
1942                                 if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Diffuse, t->render_rtlight_diffuse[0], t->render_rtlight_diffuse[1], t->render_rtlight_diffuse[2]);
1943                                 if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, t->render_rtlight_specular[0], t->render_rtlight_specular[1], t->render_rtlight_specular[2]);
1944                         }
1945                         // additive passes are only darkened by fog, not tinted
1946                         if (r_glsl_permutation->loc_FogColor >= 0)
1947                         {
1948                                 if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0)
1949                                         qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1950                                 else
1951                                         qglUniform3f(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1952                         }
1953                         if (r_glsl_permutation->loc_DistortScaleRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_DistortScaleRefractReflect, r_water_refractdistort.value * t->refractfactor, r_water_refractdistort.value * t->refractfactor, r_water_reflectdistort.value * t->reflectfactor, r_water_reflectdistort.value * t->reflectfactor);
1954                         if (r_glsl_permutation->loc_ScreenScaleRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_ScreenScaleRefractReflect, r_fb.water.screenscale[0], r_fb.water.screenscale[1], r_fb.water.screenscale[0], r_fb.water.screenscale[1]);
1955                         if (r_glsl_permutation->loc_ScreenCenterRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_ScreenCenterRefractReflect, r_fb.water.screencenter[0], r_fb.water.screencenter[1], r_fb.water.screencenter[0], r_fb.water.screencenter[1]);
1956                         if (r_glsl_permutation->loc_RefractColor >= 0) qglUniform4f(r_glsl_permutation->loc_RefractColor, t->refractcolor4f[0], t->refractcolor4f[1], t->refractcolor4f[2], t->refractcolor4f[3] * t->currentalpha);
1957                         if (r_glsl_permutation->loc_ReflectColor >= 0) qglUniform4f(r_glsl_permutation->loc_ReflectColor, t->reflectcolor4f[0], t->reflectcolor4f[1], t->reflectcolor4f[2], t->reflectcolor4f[3] * t->currentalpha);
1958                         if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectFactor, t->reflectmax - t->reflectmin);
1959                         if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectOffset, t->reflectmin);
1960                         if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1f(r_glsl_permutation->loc_SpecularPower, t->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
1961                         if (r_glsl_permutation->loc_NormalmapScrollBlend >= 0) qglUniform2f(r_glsl_permutation->loc_NormalmapScrollBlend, t->r_water_waterscroll[0], t->r_water_waterscroll[1]);
1962                 }
1963                 if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currenttexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
1964                 if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
1965                 if (r_glsl_permutation->loc_ShadowMapMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ShadowMapMatrix, 1, false, m16f);}
1966                 if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
1967                 {
1968                         if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_modelshadowmap_texturescale[0], r_shadow_modelshadowmap_texturescale[1], r_shadow_modelshadowmap_texturescale[2], r_shadow_modelshadowmap_texturescale[3]);
1969                         if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_modelshadowmap_parameters[0], r_shadow_modelshadowmap_parameters[1], r_shadow_modelshadowmap_parameters[2], r_shadow_modelshadowmap_parameters[3]);
1970                 }
1971                 else
1972                 {
1973                         if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
1974                         if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
1975                 }
1976
1977                 if (r_glsl_permutation->loc_Color_Glow >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Glow, t->render_glowmod[0], t->render_glowmod[1], t->render_glowmod[2]);
1978                 if (r_glsl_permutation->loc_Alpha >= 0) qglUniform1f(r_glsl_permutation->loc_Alpha, t->currentalpha * ((t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay) ? t->r_water_wateralpha : 1));
1979                 if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3f(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
1980                 if (r_glsl_permutation->loc_Color_Pants >= 0)
1981                 {
1982                         if (t->pantstexture)
1983                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, t->render_colormap_pants[0], t->render_colormap_pants[1], t->render_colormap_pants[2]);
1984                         else
1985                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
1986                 }
1987                 if (r_glsl_permutation->loc_Color_Shirt >= 0)
1988                 {
1989                         if (t->shirttexture)
1990                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, t->render_colormap_shirt[0], t->render_colormap_shirt[1], t->render_colormap_shirt[2]);
1991                         else
1992                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
1993                 }
1994                 if (r_glsl_permutation->loc_FogPlane >= 0) qglUniform4f(r_glsl_permutation->loc_FogPlane, rsurface.fogplane[0], rsurface.fogplane[1], rsurface.fogplane[2], rsurface.fogplane[3]);
1995                 if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1f(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist);
1996                 if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1f(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
1997                 if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1f(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
1998                 if (r_glsl_permutation->loc_OffsetMapping_ScaleSteps >= 0) qglUniform4f(r_glsl_permutation->loc_OffsetMapping_ScaleSteps,
1999                                 r_glsl_offsetmapping_scale.value*t->offsetscale,
2000                                 max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2001                                 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2002                                 max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer)
2003                         );
2004                 if (r_glsl_permutation->loc_OffsetMapping_LodDistance >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer * r_refdef.view.quality);
2005                 if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, t->offsetbias);
2006                 if (r_glsl_permutation->loc_ScreenToDepth >= 0) qglUniform2f(r_glsl_permutation->loc_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
2007                 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
2008                 if (r_glsl_permutation->loc_BounceGridMatrix >= 0) {Matrix4x4_Concat(&tempmatrix, &r_shadow_bouncegrid_state.matrix, &rsurface.matrix);Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BounceGridMatrix, 1, false, m16f);}
2009                 if (r_glsl_permutation->loc_BounceGridIntensity >= 0) qglUniform1f(r_glsl_permutation->loc_BounceGridIntensity, r_shadow_bouncegrid_state.intensity*r_refdef.view.colorscale);
2010
2011                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First            , r_texture_white                                     );
2012                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second           , r_texture_white                                     );
2013                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps       , r_texture_gammaramps                                );
2014                 if (r_glsl_permutation->tex_Texture_Normal          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Normal           , t->nmaptexture                       );
2015                 if (r_glsl_permutation->tex_Texture_Color           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Color            , t->basetexture                       );
2016                 if (r_glsl_permutation->tex_Texture_Gloss           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Gloss            , t->glosstexture                      );
2017                 if (r_glsl_permutation->tex_Texture_Glow            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Glow             , t->glowtexture                       );
2018                 if (r_glsl_permutation->tex_Texture_SecondaryNormal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryNormal  , t->backgroundnmaptexture             );
2019                 if (r_glsl_permutation->tex_Texture_SecondaryColor  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryColor   , t->backgroundbasetexture             );
2020                 if (r_glsl_permutation->tex_Texture_SecondaryGloss  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGloss   , t->backgroundglosstexture            );
2021                 if (r_glsl_permutation->tex_Texture_SecondaryGlow   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGlow    , t->backgroundglowtexture             );
2022                 if (r_glsl_permutation->tex_Texture_Pants           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Pants            , t->pantstexture                      );
2023                 if (r_glsl_permutation->tex_Texture_Shirt           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Shirt            , t->shirttexture                      );
2024                 if (r_glsl_permutation->tex_Texture_ReflectMask     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectMask      , t->reflectmasktexture                );
2025                 if (r_glsl_permutation->tex_Texture_ReflectCube     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectCube      , t->reflectcubetexture ? t->reflectcubetexture : r_texture_whitecube);
2026                 if (r_glsl_permutation->tex_Texture_FogHeightTexture>= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogHeightTexture , r_texture_fogheighttexture                          );
2027                 if (r_glsl_permutation->tex_Texture_FogMask         >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogMask          , r_texture_fogattenuation                            );
2028                 if (r_glsl_permutation->tex_Texture_Lightmap        >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Lightmap         , rsurface.lightmaptexture ? rsurface.lightmaptexture : r_texture_white);
2029                 if (r_glsl_permutation->tex_Texture_Deluxemap       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Deluxemap        , rsurface.deluxemaptexture ? rsurface.deluxemaptexture : r_texture_blanknormalmap);
2030                 if (r_glsl_permutation->tex_Texture_Attenuation     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation      , r_shadow_attenuationgradienttexture                 );
2031                 if (rsurfacepass == RSURFPASS_BACKGROUND)
2032                 {
2033                         if (r_glsl_permutation->tex_Texture_Refraction  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Refraction        , waterplane->rt_refraction ? waterplane->rt_refraction->colortexture[0] : r_texture_black);
2034                         if (r_glsl_permutation->tex_Texture_First       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First             , waterplane->rt_camera ? waterplane->rt_camera->colortexture[0] : r_texture_black);
2035                         if (r_glsl_permutation->tex_Texture_Reflection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Reflection        , waterplane->rt_reflection ? waterplane->rt_reflection->colortexture[0] : r_texture_black);
2036                 }
2037                 else
2038                 {
2039                         if (r_glsl_permutation->tex_Texture_Reflection >= 0 && waterplane) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Reflection        , waterplane->rt_reflection ? waterplane->rt_reflection->colortexture[0] : r_texture_black);
2040                 }
2041                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap   , r_shadow_prepassgeometrynormalmaptexture            );
2042                 if (r_glsl_permutation->tex_Texture_ScreenDiffuse   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDiffuse     , r_shadow_prepasslightingdiffusetexture              );
2043                 if (r_glsl_permutation->tex_Texture_ScreenSpecular  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenSpecular    , r_shadow_prepasslightingspeculartexture             );
2044                 if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)))
2045                 {
2046                         if (r_glsl_permutation->tex_Texture_ShadowMap2D     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D, r_shadow_shadowmap2ddepthtexture                           );
2047                         if (rsurface.rtlight)
2048                         {
2049                                 if (r_glsl_permutation->tex_Texture_Cube            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube              , rsurface.rtlight->currentcubemap                    );
2050                                 if (r_glsl_permutation->tex_Texture_CubeProjection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection    , r_shadow_shadowmapvsdcttexture                      );
2051                         }
2052                 }
2053                 if (r_glsl_permutation->tex_Texture_BounceGrid  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_BounceGrid, r_shadow_bouncegrid_state.texture);
2054                 CHECKGLERROR
2055                 break;
2056         }
2057 }
2058
2059 void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
2060 {
2061         // select a permutation of the lighting shader appropriate to this
2062         // combination of texture, entity, light source, and fogging, only use the
2063         // minimum features necessary to avoid wasting rendering time in the
2064         // fragment shader on features that are not being used
2065         dpuint64 permutation = 0;
2066         unsigned int mode = 0;
2067         const float *lightcolorbase = rtlight->currentcolor;
2068         float ambientscale = rtlight->ambientscale;
2069         float diffusescale = rtlight->diffusescale;
2070         float specularscale = rtlight->specularscale;
2071         // this is the location of the light in view space
2072         vec3_t viewlightorigin;
2073         // this transforms from view space (camera) to light space (cubemap)
2074         matrix4x4_t viewtolight;
2075         matrix4x4_t lighttoview;
2076         float viewtolight16f[16];
2077         // light source
2078         mode = SHADERMODE_DEFERREDLIGHTSOURCE;
2079         if (rtlight->currentcubemap != r_texture_whitecube)
2080                 permutation |= SHADERPERMUTATION_CUBEFILTER;
2081         if (diffusescale > 0)
2082                 permutation |= SHADERPERMUTATION_DIFFUSE;
2083         if (specularscale > 0 && r_shadow_gloss.integer > 0)
2084                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
2085         if (r_shadow_usingshadowmap2d)
2086         {
2087                 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
2088                 if (r_shadow_shadowmapvsdct)
2089                         permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
2090
2091                 if (r_shadow_shadowmap2ddepthbuffer)
2092                         permutation |= SHADERPERMUTATION_DEPTHRGB;
2093         }
2094         if (vid.allowalphatocoverage)
2095                 GL_AlphaToCoverage(false);
2096         Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rtlight->shadoworigin, viewlightorigin);
2097         Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rtlight->matrix_lighttoworld);
2098         Matrix4x4_Invert_Full(&viewtolight, &lighttoview);
2099         Matrix4x4_ToArrayFloatGL(&viewtolight, viewtolight16f);
2100         switch(vid.renderpath)
2101         {
2102         case RENDERPATH_GL20:
2103         case RENDERPATH_GLES2:
2104                 R_SetupShader_SetPermutationGLSL(mode, permutation);
2105                 if (r_glsl_permutation->loc_LightPosition             >= 0) qglUniform3f(       r_glsl_permutation->loc_LightPosition            , viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]);
2106                 if (r_glsl_permutation->loc_ViewToLight               >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ViewToLight              , 1, false, viewtolight16f);
2107                 if (r_glsl_permutation->loc_DeferredColor_Ambient     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Ambient    , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
2108                 if (r_glsl_permutation->loc_DeferredColor_Diffuse     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Diffuse    , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
2109                 if (r_glsl_permutation->loc_DeferredColor_Specular    >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Specular   , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
2110                 if (r_glsl_permutation->loc_ShadowMap_TextureScale    >= 0) qglUniform4f(       r_glsl_permutation->loc_ShadowMap_TextureScale   , r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
2111                 if (r_glsl_permutation->loc_ShadowMap_Parameters      >= 0) qglUniform4f(       r_glsl_permutation->loc_ShadowMap_Parameters     , r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
2112                 if (r_glsl_permutation->loc_SpecularPower             >= 0) qglUniform1f(       r_glsl_permutation->loc_SpecularPower            , (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
2113                 if (r_glsl_permutation->loc_ScreenToDepth             >= 0) qglUniform2f(       r_glsl_permutation->loc_ScreenToDepth            , r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
2114                 if (r_glsl_permutation->loc_PixelToScreenTexCoord     >= 0) qglUniform2f(       r_glsl_permutation->loc_PixelToScreenTexCoord    , 1.0f/vid.width, 1.0f/vid.height);
2115
2116                 if (r_glsl_permutation->tex_Texture_Attenuation       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation        , r_shadow_attenuationgradienttexture                 );
2117                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap    , r_shadow_prepassgeometrynormalmaptexture            );
2118                 if (r_glsl_permutation->tex_Texture_Cube              >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube               , rsurface.rtlight->currentcubemap                    );
2119                 if (r_glsl_permutation->tex_Texture_ShadowMap2D       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D        , r_shadow_shadowmap2ddepthtexture                    );
2120                 if (r_glsl_permutation->tex_Texture_CubeProjection    >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection     , r_shadow_shadowmapvsdcttexture                      );
2121                 break;
2122         }
2123 }
2124
2125 #define SKINFRAME_HASH 1024
2126
2127 typedef struct
2128 {
2129         unsigned int loadsequence; // incremented each level change
2130         memexpandablearray_t array;
2131         skinframe_t *hash[SKINFRAME_HASH];
2132 }
2133 r_skinframe_t;
2134 r_skinframe_t r_skinframe;
2135
2136 void R_SkinFrame_PrepareForPurge(void)
2137 {
2138         r_skinframe.loadsequence++;
2139         // wrap it without hitting zero
2140         if (r_skinframe.loadsequence >= 200)
2141                 r_skinframe.loadsequence = 1;
2142 }
2143
2144 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
2145 {
2146         if (!skinframe)
2147                 return;
2148         // mark the skinframe as used for the purging code
2149         skinframe->loadsequence = r_skinframe.loadsequence;
2150 }
2151
2152 void R_SkinFrame_PurgeSkinFrame(skinframe_t *s)
2153 {
2154         if (s == NULL)
2155                 return;
2156         if (s->merged == s->base)
2157                 s->merged = NULL;
2158         R_PurgeTexture(s->stain); s->stain = NULL;
2159         R_PurgeTexture(s->merged); s->merged = NULL;
2160         R_PurgeTexture(s->base); s->base = NULL;
2161         R_PurgeTexture(s->pants); s->pants = NULL;
2162         R_PurgeTexture(s->shirt); s->shirt = NULL;
2163         R_PurgeTexture(s->nmap); s->nmap = NULL;
2164         R_PurgeTexture(s->gloss); s->gloss = NULL;
2165         R_PurgeTexture(s->glow); s->glow = NULL;
2166         R_PurgeTexture(s->fog); s->fog = NULL;
2167         R_PurgeTexture(s->reflect); s->reflect = NULL;
2168         s->loadsequence = 0;
2169 }
2170
2171 void R_SkinFrame_Purge(void)
2172 {
2173         int i;
2174         skinframe_t *s;
2175         for (i = 0;i < SKINFRAME_HASH;i++)
2176         {
2177                 for (s = r_skinframe.hash[i];s;s = s->next)
2178                 {
2179                         if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
2180                                 R_SkinFrame_PurgeSkinFrame(s);
2181                 }
2182         }
2183 }
2184
2185 skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name ) {
2186         skinframe_t *item;
2187         char basename[MAX_QPATH];
2188
2189         Image_StripImageExtension(name, basename, sizeof(basename));
2190
2191         if( last == NULL ) {
2192                 int hashindex;
2193                 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2194                 item = r_skinframe.hash[hashindex];
2195         } else {
2196                 item = last->next;
2197         }
2198
2199         // linearly search through the hash bucket
2200         for( ; item ; item = item->next ) {
2201                 if( !strcmp( item->basename, basename ) ) {
2202                         return item;
2203                 }
2204         }
2205         return NULL;
2206 }
2207
2208 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qboolean add)
2209 {
2210         skinframe_t *item;
2211         int hashindex;
2212         char basename[MAX_QPATH];
2213
2214         Image_StripImageExtension(name, basename, sizeof(basename));
2215
2216         hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2217         for (item = r_skinframe.hash[hashindex];item;item = item->next)
2218                 if (!strcmp(item->basename, basename) && (comparecrc < 0 || (item->textureflags == textureflags && item->comparewidth == comparewidth && item->compareheight == compareheight && item->comparecrc == comparecrc)))
2219                         break;
2220
2221         if (!item)
2222         {
2223                 if (!add)
2224                         return NULL;
2225                 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
2226                 memset(item, 0, sizeof(*item));
2227                 strlcpy(item->basename, basename, sizeof(item->basename));
2228                 item->textureflags = textureflags & ~TEXF_FORCE_RELOAD;
2229                 item->comparewidth = comparewidth;
2230                 item->compareheight = compareheight;
2231                 item->comparecrc = comparecrc;
2232                 item->next = r_skinframe.hash[hashindex];
2233                 r_skinframe.hash[hashindex] = item;
2234         }
2235         else if (textureflags & TEXF_FORCE_RELOAD)
2236         {
2237                 if (!add)
2238                         return NULL;
2239                 R_SkinFrame_PurgeSkinFrame(item);
2240         }
2241
2242         R_SkinFrame_MarkUsed(item);
2243         return item;
2244 }
2245
2246 #define R_SKINFRAME_LOAD_AVERAGE_COLORS(cnt, getpixel) \
2247         { \
2248                 unsigned long long avgcolor[5], wsum; \
2249                 int pix, comp, w; \
2250                 avgcolor[0] = 0; \
2251                 avgcolor[1] = 0; \
2252                 avgcolor[2] = 0; \
2253                 avgcolor[3] = 0; \
2254                 avgcolor[4] = 0; \
2255                 wsum = 0; \
2256                 for(pix = 0; pix < cnt; ++pix) \
2257                 { \
2258                         w = 0; \
2259                         for(comp = 0; comp < 3; ++comp) \
2260                                 w += getpixel; \
2261                         if(w) /* ignore perfectly black pixels because that is better for model skins */ \
2262                         { \
2263                                 ++wsum; \
2264                                 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2265                                 w = getpixel; \
2266                                 for(comp = 0; comp < 3; ++comp) \
2267                                         avgcolor[comp] += getpixel * w; \
2268                                 avgcolor[3] += w; \
2269                         } \
2270                         /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2271                         avgcolor[4] += getpixel; \
2272                 } \
2273                 if(avgcolor[3] == 0) /* no pixels seen? even worse */ \
2274                         avgcolor[3] = 1; \
2275                 skinframe->avgcolor[0] = avgcolor[2] / (255.0 * avgcolor[3]); \
2276                 skinframe->avgcolor[1] = avgcolor[1] / (255.0 * avgcolor[3]); \
2277                 skinframe->avgcolor[2] = avgcolor[0] / (255.0 * avgcolor[3]); \
2278                 skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \
2279         }
2280
2281 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2282 {
2283         skinframe_t *skinframe;
2284
2285         if (cls.state == ca_dedicated)
2286                 return NULL;
2287
2288         // return an existing skinframe if already loaded
2289         // if loading of the first image fails, don't make a new skinframe as it
2290         // would cause all future lookups of this to be missing
2291         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, -1, false);
2292         if (skinframe && skinframe->base)
2293                 return skinframe;
2294
2295         return R_SkinFrame_LoadExternal_SkinFrame(skinframe, name, textureflags, complain, fallbacknotexture);
2296 }
2297
2298 extern cvar_t gl_picmip;
2299 skinframe_t *R_SkinFrame_LoadExternal_SkinFrame(skinframe_t *skinframe, const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2300 {
2301         int j;
2302         unsigned char *pixels;
2303         unsigned char *bumppixels;
2304         unsigned char *basepixels = NULL;
2305         int basepixels_width = 0;
2306         int basepixels_height = 0;
2307         rtexture_t *ddsbase = NULL;
2308         qboolean ddshasalpha = false;
2309         float ddsavgcolor[4];
2310         char basename[MAX_QPATH];
2311         int miplevel = R_PicmipForFlags(textureflags);
2312         int savemiplevel = miplevel;
2313         int mymiplevel;
2314         char vabuf[1024];
2315
2316         if (cls.state == ca_dedicated)
2317                 return NULL;
2318
2319         Image_StripImageExtension(name, basename, sizeof(basename));
2320
2321         // check for DDS texture file first
2322         if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false)))
2323         {
2324                 basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel);
2325                 if (basepixels == NULL && fallbacknotexture)
2326                         basepixels = Image_GenerateNoTexture();
2327                 if (basepixels == NULL)
2328                         return NULL;
2329         }
2330
2331         // FIXME handle miplevel
2332
2333         if (developer_loading.integer)
2334                 Con_Printf("loading skin \"%s\"\n", name);
2335
2336         // we've got some pixels to store, so really allocate this new texture now
2337         if (!skinframe)
2338                 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
2339         textureflags &= ~TEXF_FORCE_RELOAD;
2340         skinframe->stain = NULL;
2341         skinframe->merged = NULL;
2342         skinframe->base = NULL;
2343         skinframe->pants = NULL;
2344         skinframe->shirt = NULL;
2345         skinframe->nmap = NULL;
2346         skinframe->gloss = NULL;
2347         skinframe->glow = NULL;
2348         skinframe->fog = NULL;
2349         skinframe->reflect = NULL;
2350         skinframe->hasalpha = false;
2351         // we could store the q2animname here too
2352
2353         if (ddsbase)
2354         {
2355                 skinframe->base = ddsbase;
2356                 skinframe->hasalpha = ddshasalpha;
2357                 VectorCopy(ddsavgcolor, skinframe->avgcolor);
2358                 if (r_loadfog && skinframe->hasalpha)
2359                         skinframe->fog = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), false, textureflags | TEXF_ALPHA, NULL, NULL, miplevel, true);
2360                 //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2361         }
2362         else
2363         {
2364                 basepixels_width = image_width;
2365                 basepixels_height = image_height;
2366                 skinframe->base = R_LoadTexture2D (r_main_texturepool, skinframe->basename, basepixels_width, basepixels_height, basepixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), miplevel, NULL);
2367                 if (textureflags & TEXF_ALPHA)
2368                 {
2369                         for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
2370                         {
2371                                 if (basepixels[j] < 255)
2372                                 {
2373                                         skinframe->hasalpha = true;
2374                                         break;
2375                                 }
2376                         }
2377                         if (r_loadfog && skinframe->hasalpha)
2378                         {
2379                                 // has transparent pixels
2380                                 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2381                                 for (j = 0;j < image_width * image_height * 4;j += 4)
2382                                 {
2383                                         pixels[j+0] = 255;
2384                                         pixels[j+1] = 255;
2385                                         pixels[j+2] = 255;
2386                                         pixels[j+3] = basepixels[j+3];
2387                                 }
2388                                 skinframe->fog = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_mask", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), miplevel, NULL);
2389                                 Mem_Free(pixels);
2390                         }
2391                 }
2392                 R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
2393 #ifndef USE_GLES2
2394                 //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2395                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->base)
2396                         R_SaveTextureDDSFile(skinframe->base, va(vabuf, sizeof(vabuf), "dds/%s.dds", skinframe->basename), r_texture_dds_save.integer < 2, skinframe->hasalpha);
2397                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->fog)
2398                         R_SaveTextureDDSFile(skinframe->fog, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2399 #endif
2400         }
2401
2402         if (r_loaddds)
2403         {
2404                 mymiplevel = savemiplevel;
2405                 if (r_loadnormalmap)
2406                         skinframe->nmap = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), false, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), NULL, NULL, mymiplevel, true);
2407                 skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2408                 if (r_loadgloss)
2409                         skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2410                 skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2411                 skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2412                 skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2413         }
2414
2415         // _norm is the name used by tenebrae and has been adopted as standard
2416         if (r_loadnormalmap && skinframe->nmap == NULL)
2417         {
2418                 mymiplevel = savemiplevel;
2419                 if ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2420                 {
2421                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2422                         Mem_Free(pixels);
2423                         pixels = NULL;
2424                 }
2425                 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_bump", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2426                 {
2427                         pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2428                         Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
2429                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2430                         Mem_Free(pixels);
2431                         Mem_Free(bumppixels);
2432                 }
2433                 else if (r_shadow_bumpscale_basetexture.value > 0)
2434                 {
2435                         pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
2436                         Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
2437                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), basepixels_width, basepixels_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2438                         Mem_Free(pixels);
2439                 }
2440 #ifndef USE_GLES2
2441                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->nmap)
2442                         R_SaveTextureDDSFile(skinframe->nmap, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2443 #endif
2444         }
2445
2446         // _luma is supported only for tenebrae compatibility
2447         // _glow is the preferred name
2448         mymiplevel = savemiplevel;
2449         if (skinframe->glow == NULL && ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_glow",  skinframe->basename), false, false, false, &mymiplevel)) || (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_luma", skinframe->basename), false, false, false, &mymiplevel))))
2450         {
2451                 skinframe->glow = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_glow.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2452 #ifndef USE_GLES2
2453                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->glow)
2454                         R_SaveTextureDDSFile(skinframe->glow, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2455 #endif
2456                 Mem_Free(pixels);pixels = NULL;
2457         }
2458
2459         mymiplevel = savemiplevel;
2460         if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), false, false, false, &mymiplevel)))
2461         {
2462                 skinframe->gloss = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (gl_texturecompression_gloss.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2463 #ifndef USE_GLES2
2464                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->gloss)
2465                         R_SaveTextureDDSFile(skinframe->gloss, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2466 #endif
2467                 Mem_Free(pixels);
2468                 pixels = NULL;
2469         }
2470
2471         mymiplevel = savemiplevel;
2472         if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), false, false, false, &mymiplevel)))
2473         {
2474                 skinframe->pants = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2475 #ifndef USE_GLES2
2476                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->pants)
2477                         R_SaveTextureDDSFile(skinframe->pants, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2478 #endif
2479                 Mem_Free(pixels);
2480                 pixels = NULL;
2481         }
2482
2483         mymiplevel = savemiplevel;
2484         if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), false, false, false, &mymiplevel)))
2485         {
2486                 skinframe->shirt = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2487 #ifndef USE_GLES2
2488                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->shirt)
2489                         R_SaveTextureDDSFile(skinframe->shirt, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2490 #endif
2491                 Mem_Free(pixels);
2492                 pixels = NULL;
2493         }
2494
2495         mymiplevel = savemiplevel;
2496         if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), false, false, false, &mymiplevel)))
2497         {
2498                 skinframe->reflect = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_reflectmask.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2499 #ifndef USE_GLES2
2500                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->reflect)
2501                         R_SaveTextureDDSFile(skinframe->reflect, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2502 #endif
2503                 Mem_Free(pixels);
2504                 pixels = NULL;
2505         }
2506
2507         if (basepixels)
2508                 Mem_Free(basepixels);
2509
2510         return skinframe;
2511 }
2512
2513 // this is only used by .spr32 sprites, HL .spr files, HL .bsp files
2514 skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height, qboolean sRGB)
2515 {
2516         int i;
2517         skinframe_t *skinframe;
2518         char vabuf[1024];
2519
2520         if (cls.state == ca_dedicated)
2521                 return NULL;
2522
2523         // if already loaded just return it, otherwise make a new skinframe
2524         skinframe = R_SkinFrame_Find(name, textureflags, width, height, (!(textureflags & TEXF_FORCE_RELOAD) && skindata) ? CRC_Block(skindata, width*height*4) : -1, true);
2525         if (skinframe->base)
2526                 return skinframe;
2527         textureflags &= ~TEXF_FORCE_RELOAD;
2528
2529         skinframe->stain = NULL;
2530         skinframe->merged = NULL;
2531         skinframe->base = NULL;
2532         skinframe->pants = NULL;
2533         skinframe->shirt = NULL;
2534         skinframe->nmap = NULL;
2535         skinframe->gloss = NULL;
2536         skinframe->glow = NULL;
2537         skinframe->fog = NULL;
2538         skinframe->reflect = NULL;
2539         skinframe->hasalpha = false;
2540
2541         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2542         if (!skindata)
2543                 return NULL;
2544
2545         if (developer_loading.integer)
2546                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2547
2548         if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0)
2549         {
2550                 unsigned char *a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2551                 unsigned char *b = a + width * height * 4;
2552                 Image_HeightmapToNormalmap_BGRA(skindata, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2553                 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), width, height, b, TEXTYPE_BGRA, (textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL);
2554                 Mem_Free(a);
2555         }
2556         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL);
2557         if (textureflags & TEXF_ALPHA)
2558         {
2559                 for (i = 3;i < width * height * 4;i += 4)
2560                 {
2561                         if (skindata[i] < 255)
2562                         {
2563                                 skinframe->hasalpha = true;
2564                                 break;
2565                         }
2566                 }
2567                 if (r_loadfog && skinframe->hasalpha)
2568                 {
2569                         unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
2570                         memcpy(fogpixels, skindata, width * height * 4);
2571                         for (i = 0;i < width * height * 4;i += 4)
2572                                 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
2573                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, textureflags, -1, NULL);
2574                         Mem_Free(fogpixels);
2575                 }
2576         }
2577
2578         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]);
2579         //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2580
2581         return skinframe;
2582 }
2583
2584 skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height)
2585 {
2586         int i;
2587         int featuresmask;
2588         skinframe_t *skinframe;
2589
2590         if (cls.state == ca_dedicated)
2591                 return NULL;
2592
2593         // if already loaded just return it, otherwise make a new skinframe
2594         skinframe = R_SkinFrame_Find(name, textureflags, width, height, (!(textureflags & TEXF_FORCE_RELOAD) && skindata) ? CRC_Block(skindata, width*height) : -1, true);
2595         if (skinframe->base)
2596                 return skinframe;
2597         //textureflags &= ~TEXF_FORCE_RELOAD;
2598
2599         skinframe->stain = NULL;
2600         skinframe->merged = NULL;
2601         skinframe->base = NULL;
2602         skinframe->pants = NULL;
2603         skinframe->shirt = NULL;
2604         skinframe->nmap = NULL;
2605         skinframe->gloss = NULL;
2606         skinframe->glow = NULL;
2607         skinframe->fog = NULL;
2608         skinframe->reflect = NULL;
2609         skinframe->hasalpha = false;
2610
2611         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2612         if (!skindata)
2613                 return NULL;
2614
2615         if (developer_loading.integer)
2616                 Con_Printf("loading quake skin \"%s\"\n", name);
2617
2618         // we actually don't upload anything until the first use, because mdl skins frequently go unused, and are almost never used in both modes (colormapped and non-colormapped)
2619         skinframe->qpixels = (unsigned char *)Mem_Alloc(r_main_mempool, width*height); // FIXME LEAK
2620         memcpy(skinframe->qpixels, skindata, width*height);
2621         skinframe->qwidth = width;
2622         skinframe->qheight = height;
2623
2624         featuresmask = 0;
2625         for (i = 0;i < width * height;i++)
2626                 featuresmask |= palette_featureflags[skindata[i]];
2627
2628         skinframe->hasalpha = false;
2629         // fence textures
2630         if (name[0] == '{')
2631                 skinframe->hasalpha = true;
2632         skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT));
2633         skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0;
2634         skinframe->qgeneratemerged = true;
2635         skinframe->qgeneratebase = skinframe->qhascolormapping;
2636         skinframe->qgenerateglow = loadglowtexture && (featuresmask & PALETTEFEATURE_GLOW);
2637
2638         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette_bgra_complete)[skindata[pix]*4 + comp]);
2639         //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2640
2641         return skinframe;
2642 }
2643
2644 static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qboolean colormapped)
2645 {
2646         int width;
2647         int height;
2648         unsigned char *skindata;
2649         char vabuf[1024];
2650
2651         if (!skinframe->qpixels)
2652                 return;
2653
2654         if (!skinframe->qhascolormapping)
2655                 colormapped = false;
2656
2657         if (colormapped)
2658         {
2659                 if (!skinframe->qgeneratebase)
2660                         return;
2661         }
2662         else
2663         {
2664                 if (!skinframe->qgeneratemerged)
2665                         return;
2666         }
2667
2668         width = skinframe->qwidth;
2669         height = skinframe->qheight;
2670         skindata = skinframe->qpixels;
2671
2672         if (skinframe->qgeneratenmap)
2673         {
2674                 unsigned char *a, *b;
2675                 skinframe->qgeneratenmap = false;
2676                 a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2677                 b = a + width * height * 4;
2678                 // use either a custom palette or the quake palette
2679                 Image_Copy8bitBGRA(skindata, a, width * height, palette_bgra_complete);
2680                 Image_HeightmapToNormalmap_BGRA(a, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2681                 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), width, height, b, TEXTYPE_BGRA, (skinframe->textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL);
2682                 Mem_Free(a);
2683         }
2684
2685         if (skinframe->qgenerateglow)
2686         {
2687                 skinframe->qgenerateglow = false;
2688                 if (skinframe->hasalpha) // fence textures
2689                         skinframe->glow = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags | TEXF_ALPHA, -1, palette_bgra_onlyfullbrights_transparent); // glow
2690                 else
2691                         skinframe->glow = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_onlyfullbrights); // glow
2692         }
2693
2694         if (colormapped)
2695         {
2696                 skinframe->qgeneratebase = false;
2697                 skinframe->base  = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nospecial", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, skinframe->glow ? palette_bgra_nocolormapnofullbrights : palette_bgra_nocolormap);
2698                 skinframe->pants = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_pantsaswhite);
2699                 skinframe->shirt = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_shirtaswhite);
2700         }
2701         else
2702         {
2703                 skinframe->qgeneratemerged = false;
2704                 if (skinframe->hasalpha) // fence textures
2705                         skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags | TEXF_ALPHA, -1, skinframe->glow ? palette_bgra_nofullbrights_transparent : palette_bgra_transparent);
2706                 else
2707                         skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, skinframe->glow ? palette_bgra_nofullbrights : palette_bgra_complete);
2708         }
2709
2710         if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase)
2711         {
2712                 Mem_Free(skinframe->qpixels);
2713                 skinframe->qpixels = NULL;
2714         }
2715 }
2716
2717 skinframe_t *R_SkinFrame_LoadInternal8bit(const char *name, int textureflags, const unsigned char *skindata, int width, int height, const unsigned int *palette, const unsigned int *alphapalette)
2718 {
2719         int i;
2720         skinframe_t *skinframe;
2721         char vabuf[1024];
2722
2723         if (cls.state == ca_dedicated)
2724                 return NULL;
2725
2726         // if already loaded just return it, otherwise make a new skinframe
2727         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2728         if (skinframe->base)
2729                 return skinframe;
2730         textureflags &= ~TEXF_FORCE_RELOAD;
2731
2732         skinframe->stain = NULL;
2733         skinframe->merged = NULL;
2734         skinframe->base = NULL;
2735         skinframe->pants = NULL;
2736         skinframe->shirt = NULL;
2737         skinframe->nmap = NULL;
2738         skinframe->gloss = NULL;
2739         skinframe->glow = NULL;
2740         skinframe->fog = NULL;
2741         skinframe->reflect = NULL;
2742         skinframe->hasalpha = false;
2743
2744         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2745         if (!skindata)
2746                 return NULL;
2747
2748         if (developer_loading.integer)
2749                 Con_Printf("loading embedded 8bit image \"%s\"\n", name);
2750
2751         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, palette);
2752         if ((textureflags & TEXF_ALPHA) && alphapalette)
2753         {
2754                 for (i = 0;i < width * height;i++)
2755                 {
2756                         if (((unsigned char *)palette)[skindata[i]*4+3] < 255)
2757                         {
2758                                 skinframe->hasalpha = true;
2759                                 break;
2760                         }
2761                 }
2762                 if (r_loadfog && skinframe->hasalpha)
2763                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, alphapalette);
2764         }
2765
2766         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
2767         //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2768
2769         return skinframe;
2770 }
2771
2772 skinframe_t *R_SkinFrame_LoadMissing(void)
2773 {
2774         skinframe_t *skinframe;
2775
2776         if (cls.state == ca_dedicated)
2777                 return NULL;
2778
2779         skinframe = R_SkinFrame_Find("missing", TEXF_FORCENEAREST, 0, 0, 0, true);
2780         skinframe->stain = NULL;
2781         skinframe->merged = NULL;
2782         skinframe->base = NULL;
2783         skinframe->pants = NULL;
2784         skinframe->shirt = NULL;
2785         skinframe->nmap = NULL;
2786         skinframe->gloss = NULL;
2787         skinframe->glow = NULL;
2788         skinframe->fog = NULL;
2789         skinframe->reflect = NULL;
2790         skinframe->hasalpha = false;
2791
2792         skinframe->avgcolor[0] = rand() / RAND_MAX;
2793         skinframe->avgcolor[1] = rand() / RAND_MAX;
2794         skinframe->avgcolor[2] = rand() / RAND_MAX;
2795         skinframe->avgcolor[3] = 1;
2796
2797         return skinframe;
2798 }
2799
2800 skinframe_t *R_SkinFrame_LoadNoTexture(void)
2801 {
2802         int x, y;
2803         static unsigned char pix[16][16][4];
2804
2805         if (cls.state == ca_dedicated)
2806                 return NULL;
2807
2808         // this makes a light grey/dark grey checkerboard texture
2809         if (!pix[0][0][3])
2810         {
2811                 for (y = 0; y < 16; y++)
2812                 {
2813                         for (x = 0; x < 16; x++)
2814                         {
2815                                 if ((y < 8) ^ (x < 8))
2816                                 {
2817                                         pix[y][x][0] = 128;
2818                                         pix[y][x][1] = 128;
2819                                         pix[y][x][2] = 128;
2820                                         pix[y][x][3] = 255;
2821                                 }
2822                                 else
2823                                 {
2824                                         pix[y][x][0] = 64;
2825                                         pix[y][x][1] = 64;
2826                                         pix[y][x][2] = 64;
2827                                         pix[y][x][3] = 255;
2828                                 }
2829                         }
2830                 }
2831         }
2832
2833         return R_SkinFrame_LoadInternalBGRA("notexture", TEXF_FORCENEAREST, pix[0][0], 16, 16, false);
2834 }
2835
2836 skinframe_t *R_SkinFrame_LoadInternalUsingTexture(const char *name, int textureflags, rtexture_t *tex, int width, int height, qboolean sRGB)
2837 {
2838         skinframe_t *skinframe;
2839         if (cls.state == ca_dedicated)
2840                 return NULL;
2841         // if already loaded just return it, otherwise make a new skinframe
2842         skinframe = R_SkinFrame_Find(name, textureflags, width, height, (textureflags & TEXF_FORCE_RELOAD) ? -1 : 0, true);
2843         if (skinframe->base)
2844                 return skinframe;
2845         textureflags &= ~TEXF_FORCE_RELOAD;
2846         skinframe->stain = NULL;
2847         skinframe->merged = NULL;
2848         skinframe->base = NULL;
2849         skinframe->pants = NULL;
2850         skinframe->shirt = NULL;
2851         skinframe->nmap = NULL;
2852         skinframe->gloss = NULL;
2853         skinframe->glow = NULL;
2854         skinframe->fog = NULL;
2855         skinframe->reflect = NULL;
2856         skinframe->hasalpha = (textureflags & TEXF_ALPHA) != 0;
2857         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2858         if (!tex)
2859                 return NULL;
2860         if (developer_loading.integer)
2861                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2862         skinframe->base = skinframe->merged = tex;
2863         Vector4Set(skinframe->avgcolor, 1, 1, 1, 1); // bogus placeholder
2864         return skinframe;
2865 }
2866
2867 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2868 typedef struct suffixinfo_s
2869 {
2870         const char *suffix;
2871         qboolean flipx, flipy, flipdiagonal;
2872 }
2873 suffixinfo_t;
2874 static suffixinfo_t suffix[3][6] =
2875 {
2876         {
2877                 {"px",   false, false, false},
2878                 {"nx",   false, false, false},
2879                 {"py",   false, false, false},
2880                 {"ny",   false, false, false},
2881                 {"pz",   false, false, false},
2882                 {"nz",   false, false, false}
2883         },
2884         {
2885                 {"posx", false, false, false},
2886                 {"negx", false, false, false},
2887                 {"posy", false, false, false},
2888                 {"negy", false, false, false},
2889                 {"posz", false, false, false},
2890                 {"negz", false, false, false}
2891         },
2892         {
2893                 {"rt",    true, false,  true},
2894                 {"lf",   false,  true,  true},
2895                 {"ft",    true,  true, false},
2896                 {"bk",   false, false, false},
2897                 {"up",    true, false,  true},
2898                 {"dn",    true, false,  true}
2899         }
2900 };
2901
2902 static int componentorder[4] = {0, 1, 2, 3};
2903
2904 static rtexture_t *R_LoadCubemap(const char *basename)
2905 {
2906         int i, j, cubemapsize;
2907         unsigned char *cubemappixels, *image_buffer;
2908         rtexture_t *cubemaptexture;
2909         char name[256];
2910         // must start 0 so the first loadimagepixels has no requested width/height
2911         cubemapsize = 0;
2912         cubemappixels = NULL;
2913         cubemaptexture = NULL;
2914         // keep trying different suffix groups (posx, px, rt) until one loads
2915         for (j = 0;j < 3 && !cubemappixels;j++)
2916         {
2917                 // load the 6 images in the suffix group
2918                 for (i = 0;i < 6;i++)
2919                 {
2920                         // generate an image name based on the base and and suffix
2921                         dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2922                         // load it
2923                         if ((image_buffer = loadimagepixelsbgra(name, false, false, false, NULL)))
2924                         {
2925                                 // an image loaded, make sure width and height are equal
2926                                 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
2927                                 {
2928                                         // if this is the first image to load successfully, allocate the cubemap memory
2929                                         if (!cubemappixels && image_width >= 1)
2930                                         {
2931                                                 cubemapsize = image_width;
2932                                                 // note this clears to black, so unavailable sides are black
2933                                                 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2934                                         }
2935                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2936                                         if (cubemappixels)
2937                                                 Image_CopyMux(cubemappixels+i*cubemapsize*cubemapsize*4, image_buffer, cubemapsize, cubemapsize, suffix[j][i].flipx, suffix[j][i].flipy, suffix[j][i].flipdiagonal, 4, 4, componentorder);
2938                                 }
2939                                 else
2940                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2941                                 // free the image
2942                                 Mem_Free(image_buffer);
2943                         }
2944                 }
2945         }
2946         // if a cubemap loaded, upload it
2947         if (cubemappixels)
2948         {
2949                 if (developer_loading.integer)
2950                         Con_Printf("loading cubemap \"%s\"\n", basename);
2951
2952                 cubemaptexture = R_LoadTextureCubeMap(r_main_texturepool, basename, cubemapsize, cubemappixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, (gl_texturecompression_lightcubemaps.integer && gl_texturecompression.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
2953                 Mem_Free(cubemappixels);
2954         }
2955         else
2956         {
2957                 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
2958                 if (developer_loading.integer)
2959                 {
2960                         Con_Printf("(tried tried images ");
2961                         for (j = 0;j < 3;j++)
2962                                 for (i = 0;i < 6;i++)
2963                                         Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2964                         Con_Print(" and was unable to find any of them).\n");
2965                 }
2966         }
2967         return cubemaptexture;
2968 }
2969
2970 rtexture_t *R_GetCubemap(const char *basename)
2971 {
2972         int i;
2973         for (i = 0;i < r_texture_numcubemaps;i++)
2974                 if (r_texture_cubemaps[i] != NULL)
2975                         if (!strcasecmp(r_texture_cubemaps[i]->basename, basename))
2976                                 return r_texture_cubemaps[i]->texture ? r_texture_cubemaps[i]->texture : r_texture_whitecube;
2977         if (i >= MAX_CUBEMAPS || !r_main_mempool)
2978                 return r_texture_whitecube;
2979         r_texture_numcubemaps++;
2980         r_texture_cubemaps[i] = (cubemapinfo_t *)Mem_Alloc(r_main_mempool, sizeof(cubemapinfo_t));
2981         strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename));
2982         r_texture_cubemaps[i]->texture = R_LoadCubemap(r_texture_cubemaps[i]->basename);
2983         return r_texture_cubemaps[i]->texture;
2984 }
2985
2986 static void R_Main_FreeViewCache(void)
2987 {
2988         if (r_refdef.viewcache.entityvisible)
2989                 Mem_Free(r_refdef.viewcache.entityvisible);
2990         if (r_refdef.viewcache.world_pvsbits)
2991                 Mem_Free(r_refdef.viewcache.world_pvsbits);
2992         if (r_refdef.viewcache.world_leafvisible)
2993                 Mem_Free(r_refdef.viewcache.world_leafvisible);
2994         if (r_refdef.viewcache.world_surfacevisible)
2995                 Mem_Free(r_refdef.viewcache.world_surfacevisible);
2996         memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache));
2997 }
2998
2999 static void R_Main_ResizeViewCache(void)
3000 {
3001         int numentities = r_refdef.scene.numentities;
3002         int numclusters = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusters : 1;
3003         int numclusterbytes = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusterbytes : 1;
3004         int numleafs = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_leafs : 1;
3005         int numsurfaces = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->num_surfaces : 1;
3006         if (r_refdef.viewcache.maxentities < numentities)
3007         {
3008                 r_refdef.viewcache.maxentities = numentities;
3009                 if (r_refdef.viewcache.entityvisible)
3010                         Mem_Free(r_refdef.viewcache.entityvisible);
3011                 r_refdef.viewcache.entityvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.maxentities);
3012         }
3013         if (r_refdef.viewcache.world_numclusters != numclusters)
3014         {
3015                 r_refdef.viewcache.world_numclusters = numclusters;
3016                 r_refdef.viewcache.world_numclusterbytes = numclusterbytes;
3017                 if (r_refdef.viewcache.world_pvsbits)
3018                         Mem_Free(r_refdef.viewcache.world_pvsbits);
3019                 r_refdef.viewcache.world_pvsbits = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numclusterbytes);
3020         }
3021         if (r_refdef.viewcache.world_numleafs != numleafs)
3022         {
3023                 r_refdef.viewcache.world_numleafs = numleafs;
3024                 if (r_refdef.viewcache.world_leafvisible)
3025                         Mem_Free(r_refdef.viewcache.world_leafvisible);
3026                 r_refdef.viewcache.world_leafvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numleafs);
3027         }
3028         if (r_refdef.viewcache.world_numsurfaces != numsurfaces)
3029         {
3030                 r_refdef.viewcache.world_numsurfaces = numsurfaces;
3031                 if (r_refdef.viewcache.world_surfacevisible)
3032                         Mem_Free(r_refdef.viewcache.world_surfacevisible);
3033                 r_refdef.viewcache.world_surfacevisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numsurfaces);
3034         }
3035 }
3036
3037 extern rtexture_t *loadingscreentexture;
3038 static void gl_main_start(void)
3039 {
3040         loadingscreentexture = NULL;
3041         r_texture_blanknormalmap = NULL;
3042         r_texture_white = NULL;
3043         r_texture_grey128 = NULL;
3044         r_texture_black = NULL;
3045         r_texture_whitecube = NULL;
3046         r_texture_normalizationcube = NULL;
3047         r_texture_fogattenuation = NULL;
3048         r_texture_fogheighttexture = NULL;
3049         r_texture_gammaramps = NULL;
3050         r_texture_numcubemaps = 0;
3051         r_uniformbufferalignment = 32;
3052
3053         r_loaddds = r_texture_dds_load.integer != 0;
3054         r_savedds = vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer;
3055
3056         switch(vid.renderpath)
3057         {
3058         case RENDERPATH_GL20:
3059         case RENDERPATH_GLES2:
3060                 Cvar_SetValueQuick(&r_textureunits, vid.texunits);
3061                 Cvar_SetValueQuick(&gl_combine, 1);
3062                 Cvar_SetValueQuick(&r_glsl, 1);
3063                 r_loadnormalmap = true;
3064                 r_loadgloss = true;
3065                 r_loadfog = false;
3066 #ifdef GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
3067                 if (vid.support.arb_uniform_buffer_object)
3068                         qglGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &r_uniformbufferalignment);
3069 #endif
3070                         break;
3071         }
3072
3073         R_AnimCache_Free();
3074         R_FrameData_Reset();
3075         R_BufferData_Reset();
3076
3077         r_numqueries = 0;
3078         r_maxqueries = 0;
3079         memset(r_queries, 0, sizeof(r_queries));
3080
3081         r_qwskincache = NULL;
3082         r_qwskincache_size = 0;
3083
3084         // due to caching of texture_t references, the collision cache must be reset
3085         Collision_Cache_Reset(true);
3086
3087         // set up r_skinframe loading system for textures
3088         memset(&r_skinframe, 0, sizeof(r_skinframe));
3089         r_skinframe.loadsequence = 1;
3090         Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
3091
3092         r_main_texturepool = R_AllocTexturePool();
3093         R_BuildBlankTextures();
3094         R_BuildNoTexture();
3095         if (vid.support.arb_texture_cube_map)
3096         {
3097                 R_BuildWhiteCube();
3098                 R_BuildNormalizationCube();
3099         }
3100         r_texture_fogattenuation = NULL;
3101         r_texture_fogheighttexture = NULL;
3102         r_texture_gammaramps = NULL;
3103         //r_texture_fogintensity = NULL;
3104         memset(&r_fb, 0, sizeof(r_fb));
3105         Mem_ExpandableArray_NewArray(&r_fb.rendertargets, r_main_mempool, sizeof(r_rendertarget_t), 128);
3106         r_glsl_permutation = NULL;
3107         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3108         Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256);
3109         memset(&r_svbsp, 0, sizeof (r_svbsp));
3110
3111         memset(r_texture_cubemaps, 0, sizeof(r_texture_cubemaps));
3112         r_texture_numcubemaps = 0;
3113
3114         r_refdef.fogmasktable_density = 0;
3115
3116 #ifdef __ANDROID__
3117         // For Steelstorm Android
3118         // FIXME CACHE the program and reload
3119         // FIXME see possible combinations for SS:BR android
3120         Con_DPrintf("Compiling most used shaders for SS:BR android... START\n");
3121         R_SetupShader_SetPermutationGLSL(0, 12);
3122         R_SetupShader_SetPermutationGLSL(0, 13);
3123         R_SetupShader_SetPermutationGLSL(0, 8388621);
3124         R_SetupShader_SetPermutationGLSL(3, 0);
3125         R_SetupShader_SetPermutationGLSL(3, 2048);
3126         R_SetupShader_SetPermutationGLSL(5, 0);
3127         R_SetupShader_SetPermutationGLSL(5, 2);
3128         R_SetupShader_SetPermutationGLSL(5, 2048);
3129         R_SetupShader_SetPermutationGLSL(5, 8388608);
3130         R_SetupShader_SetPermutationGLSL(11, 1);
3131         R_SetupShader_SetPermutationGLSL(11, 2049);
3132         R_SetupShader_SetPermutationGLSL(11, 8193);
3133         R_SetupShader_SetPermutationGLSL(11, 10241);
3134         Con_DPrintf("Compiling most used shaders for SS:BR android... END\n");
3135 #endif
3136 }
3137
3138 static void gl_main_shutdown(void)
3139 {
3140         R_RenderTarget_FreeUnused(true);
3141         Mem_ExpandableArray_FreeArray(&r_fb.rendertargets);
3142         R_AnimCache_Free();
3143         R_FrameData_Reset();
3144         R_BufferData_Reset();
3145
3146         R_Main_FreeViewCache();
3147
3148         switch(vid.renderpath)
3149         {
3150         case RENDERPATH_GL20:
3151         case RENDERPATH_GLES2:
3152 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
3153                 if (r_maxqueries)
3154                         qglDeleteQueriesARB(r_maxqueries, r_queries);
3155 #endif
3156                 break;
3157         }
3158
3159         r_numqueries = 0;
3160         r_maxqueries = 0;
3161         memset(r_queries, 0, sizeof(r_queries));
3162
3163         r_qwskincache = NULL;
3164         r_qwskincache_size = 0;
3165
3166         // clear out the r_skinframe state
3167         Mem_ExpandableArray_FreeArray(&r_skinframe.array);
3168         memset(&r_skinframe, 0, sizeof(r_skinframe));
3169
3170         if (r_svbsp.nodes)
3171                 Mem_Free(r_svbsp.nodes);
3172         memset(&r_svbsp, 0, sizeof (r_svbsp));
3173         R_FreeTexturePool(&r_main_texturepool);
3174         loadingscreentexture = NULL;
3175         r_texture_blanknormalmap = NULL;
3176         r_texture_white = NULL;
3177         r_texture_grey128 = NULL;
3178         r_texture_black = NULL;
3179         r_texture_whitecube = NULL;
3180         r_texture_normalizationcube = NULL;
3181         r_texture_fogattenuation = NULL;
3182         r_texture_fogheighttexture = NULL;
3183         r_texture_gammaramps = NULL;
3184         r_texture_numcubemaps = 0;
3185         //r_texture_fogintensity = NULL;
3186         memset(&r_fb, 0, sizeof(r_fb));
3187         R_GLSL_Restart_f();
3188
3189         r_glsl_permutation = NULL;
3190         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3191         Mem_ExpandableArray_FreeArray(&r_glsl_permutationarray);
3192 }
3193
3194 static void gl_main_newmap(void)
3195 {
3196         // FIXME: move this code to client
3197         char *entities, entname[MAX_QPATH];
3198         if (r_qwskincache)
3199                 Mem_Free(r_qwskincache);
3200         r_qwskincache = NULL;
3201         r_qwskincache_size = 0;
3202         if (cl.worldmodel)
3203         {
3204                 dpsnprintf(entname, sizeof(entname), "%s.ent", cl.worldnamenoextension);
3205                 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
3206                 {
3207                         CL_ParseEntityLump(entities);
3208                         Mem_Free(entities);
3209                         return;
3210                 }
3211                 if (cl.worldmodel->brush.entities)
3212                         CL_ParseEntityLump(cl.worldmodel->brush.entities);
3213         }
3214         R_Main_FreeViewCache();
3215
3216         R_FrameData_Reset();
3217         R_BufferData_Reset();
3218 }
3219
3220 void GL_Main_Init(void)
3221 {
3222         int i;
3223         r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
3224         R_InitShaderModeInfo();
3225
3226         Cmd_AddCommand("r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
3227         Cmd_AddCommand("r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
3228         // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
3229         if (gamemode == GAME_NEHAHRA)
3230         {
3231                 Cvar_RegisterVariable (&gl_fogenable);
3232                 Cvar_RegisterVariable (&gl_fogdensity);
3233                 Cvar_RegisterVariable (&gl_fogred);
3234                 Cvar_RegisterVariable (&gl_foggreen);
3235                 Cvar_RegisterVariable (&gl_fogblue);
3236                 Cvar_RegisterVariable (&gl_fogstart);
3237                 Cvar_RegisterVariable (&gl_fogend);
3238                 Cvar_RegisterVariable (&gl_skyclip);
3239         }
3240         Cvar_RegisterVariable(&r_motionblur);
3241         Cvar_RegisterVariable(&r_damageblur);
3242         Cvar_RegisterVariable(&r_motionblur_averaging);
3243         Cvar_RegisterVariable(&r_motionblur_randomize);
3244         Cvar_RegisterVariable(&r_motionblur_minblur);
3245         Cvar_RegisterVariable(&r_motionblur_maxblur);
3246         Cvar_RegisterVariable(&r_motionblur_velocityfactor);
3247         Cvar_RegisterVariable(&r_motionblur_velocityfactor_minspeed);
3248         Cvar_RegisterVariable(&r_motionblur_velocityfactor_maxspeed);
3249         Cvar_RegisterVariable(&r_motionblur_mousefactor);
3250         Cvar_RegisterVariable(&r_motionblur_mousefactor_minspeed);
3251         Cvar_RegisterVariable(&r_motionblur_mousefactor_maxspeed);
3252         Cvar_RegisterVariable(&r_equalize_entities_fullbright);
3253         Cvar_RegisterVariable(&r_equalize_entities_minambient);
3254         Cvar_RegisterVariable(&r_equalize_entities_by);
3255         Cvar_RegisterVariable(&r_equalize_entities_to);
3256         Cvar_RegisterVariable(&r_depthfirst);
3257         Cvar_RegisterVariable(&r_useinfinitefarclip);
3258         Cvar_RegisterVariable(&r_farclip_base);
3259         Cvar_RegisterVariable(&r_farclip_world);
3260         Cvar_RegisterVariable(&r_nearclip);
3261         Cvar_RegisterVariable(&r_deformvertexes);
3262         Cvar_RegisterVariable(&r_transparent);
3263         Cvar_RegisterVariable(&r_transparent_alphatocoverage);
3264         Cvar_RegisterVariable(&r_transparent_sortsurfacesbynearest);
3265         Cvar_RegisterVariable(&r_transparent_useplanardistance);
3266         Cvar_RegisterVariable(&r_showoverdraw);
3267         Cvar_RegisterVariable(&r_showbboxes);
3268         Cvar_RegisterVariable(&r_showbboxes_client);
3269         Cvar_RegisterVariable(&r_showsurfaces);
3270         Cvar_RegisterVariable(&r_showtris);
3271         Cvar_RegisterVariable(&r_shownormals);
3272         Cvar_RegisterVariable(&r_showlighting);
3273         Cvar_RegisterVariable(&r_showshadowvolumes);
3274         Cvar_RegisterVariable(&r_showcollisionbrushes);
3275         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
3276         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
3277         Cvar_RegisterVariable(&r_showdisabledepthtest);
3278         Cvar_RegisterVariable(&r_showspriteedges);
3279         Cvar_RegisterVariable(&r_showparticleedges);
3280         Cvar_RegisterVariable(&r_drawportals);
3281         Cvar_RegisterVariable(&r_drawentities);
3282         Cvar_RegisterVariable(&r_draw2d);
3283         Cvar_RegisterVariable(&r_drawworld);
3284         Cvar_RegisterVariable(&r_cullentities_trace);
3285         Cvar_RegisterVariable(&r_cullentities_trace_entityocclusion);
3286         Cvar_RegisterVariable(&r_cullentities_trace_samples);
3287         Cvar_RegisterVariable(&r_cullentities_trace_tempentitysamples);
3288         Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
3289         Cvar_RegisterVariable(&r_cullentities_trace_expand);
3290         Cvar_RegisterVariable(&r_cullentities_trace_pad);
3291         Cvar_RegisterVariable(&r_cullentities_trace_delay);
3292         Cvar_RegisterVariable(&r_cullentities_trace_eyejitter);
3293         Cvar_RegisterVariable(&r_sortentities);
3294         Cvar_RegisterVariable(&r_drawviewmodel);
3295         Cvar_RegisterVariable(&r_drawexteriormodel);
3296         Cvar_RegisterVariable(&r_speeds);
3297         Cvar_RegisterVariable(&r_fullbrights);
3298         Cvar_RegisterVariable(&r_wateralpha);
3299         Cvar_RegisterVariable(&r_dynamic);
3300         Cvar_RegisterVariable(&r_fakelight);
3301         Cvar_RegisterVariable(&r_fakelight_intensity);
3302         Cvar_RegisterVariable(&r_fullbright_directed);
3303         Cvar_RegisterVariable(&r_fullbright_directed_ambient);
3304         Cvar_RegisterVariable(&r_fullbright_directed_diffuse);
3305         Cvar_RegisterVariable(&r_fullbright_directed_pitch);
3306         Cvar_RegisterVariable(&r_fullbright_directed_pitch_relative);
3307         Cvar_RegisterVariable(&r_fullbright);
3308         Cvar_RegisterVariable(&r_shadows);
3309         Cvar_RegisterVariable(&r_shadows_darken);
3310         Cvar_RegisterVariable(&r_shadows_drawafterrtlighting);
3311         Cvar_RegisterVariable(&r_shadows_castfrombmodels);
3312         Cvar_RegisterVariable(&r_shadows_throwdistance);
3313         Cvar_RegisterVariable(&r_shadows_throwdirection);
3314         Cvar_RegisterVariable(&r_shadows_focus);
3315         Cvar_RegisterVariable(&r_shadows_shadowmapscale);
3316         Cvar_RegisterVariable(&r_shadows_shadowmapbias);
3317         Cvar_RegisterVariable(&r_q1bsp_skymasking);
3318         Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
3319         Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
3320         Cvar_RegisterVariable(&r_polygonoffset_decals_factor);
3321         Cvar_RegisterVariable(&r_polygonoffset_decals_offset);
3322         Cvar_RegisterVariable(&r_fog_exp2);
3323         Cvar_RegisterVariable(&r_fog_clear);
3324         Cvar_RegisterVariable(&r_drawfog);
3325         Cvar_RegisterVariable(&r_transparentdepthmasking);
3326         Cvar_RegisterVariable(&r_transparent_sortmindist);
3327         Cvar_RegisterVariable(&r_transparent_sortmaxdist);
3328         Cvar_RegisterVariable(&r_transparent_sortarraysize);
3329         Cvar_RegisterVariable(&r_texture_dds_load);
3330         Cvar_RegisterVariable(&r_texture_dds_save);
3331         Cvar_RegisterVariable(&r_textureunits);
3332         Cvar_RegisterVariable(&gl_combine);
3333         Cvar_RegisterVariable(&r_usedepthtextures);
3334         Cvar_RegisterVariable(&r_viewfbo);
3335         Cvar_RegisterVariable(&r_rendertarget_debug);
3336         Cvar_RegisterVariable(&r_viewscale);
3337         Cvar_RegisterVariable(&r_viewscale_fpsscaling);
3338         Cvar_RegisterVariable(&r_viewscale_fpsscaling_min);
3339         Cvar_RegisterVariable(&r_viewscale_fpsscaling_multiply);
3340         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepsize);
3341         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepmax);
3342         Cvar_RegisterVariable(&r_viewscale_fpsscaling_target);
3343         Cvar_RegisterVariable(&r_glsl);
3344         Cvar_RegisterVariable(&r_glsl_deluxemapping);
3345         Cvar_RegisterVariable(&r_glsl_offsetmapping);
3346         Cvar_RegisterVariable(&r_glsl_offsetmapping_steps);
3347         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
3348         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_steps);
3349         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_refinesteps);
3350         Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
3351         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod);
3352         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod_distance);
3353         Cvar_RegisterVariable(&r_glsl_postprocess);
3354         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1);
3355         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2);
3356         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3);
3357         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4);
3358         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1_enable);
3359         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2_enable);
3360         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3_enable);
3361         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable);
3362         Cvar_RegisterVariable(&r_celshading);
3363         Cvar_RegisterVariable(&r_celoutlines);
3364
3365         Cvar_RegisterVariable(&r_water);
3366         Cvar_RegisterVariable(&r_water_cameraentitiesonly);
3367         Cvar_RegisterVariable(&r_water_resolutionmultiplier);
3368         Cvar_RegisterVariable(&r_water_clippingplanebias);
3369         Cvar_RegisterVariable(&r_water_refractdistort);
3370         Cvar_RegisterVariable(&r_water_reflectdistort);
3371         Cvar_RegisterVariable(&r_water_scissormode);
3372         Cvar_RegisterVariable(&r_water_lowquality);
3373         Cvar_RegisterVariable(&r_water_hideplayer);
3374
3375         Cvar_RegisterVariable(&r_lerpsprites);
3376         Cvar_RegisterVariable(&r_lerpmodels);
3377         Cvar_RegisterVariable(&r_lerplightstyles);
3378         Cvar_RegisterVariable(&r_waterscroll);
3379         Cvar_RegisterVariable(&r_bloom);
3380         Cvar_RegisterVariable(&r_bloom_colorscale);
3381         Cvar_RegisterVariable(&r_bloom_brighten);
3382         Cvar_RegisterVariable(&r_bloom_blur);
3383         Cvar_RegisterVariable(&r_bloom_resolution);
3384         Cvar_RegisterVariable(&r_bloom_colorexponent);
3385         Cvar_RegisterVariable(&r_bloom_colorsubtract);
3386         Cvar_RegisterVariable(&r_bloom_scenebrightness);
3387         Cvar_RegisterVariable(&r_hdr_scenebrightness);
3388         Cvar_RegisterVariable(&r_hdr_glowintensity);
3389         Cvar_RegisterVariable(&r_hdr_irisadaptation);
3390         Cvar_RegisterVariable(&r_hdr_irisadaptation_multiplier);
3391         Cvar_RegisterVariable(&r_hdr_irisadaptation_minvalue);
3392         Cvar_RegisterVariable(&r_hdr_irisadaptation_maxvalue);
3393         Cvar_RegisterVariable(&r_hdr_irisadaptation_value);
3394         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_up);
3395         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_down);
3396         Cvar_RegisterVariable(&r_hdr_irisadaptation_radius);
3397         Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
3398         Cvar_RegisterVariable(&developer_texturelogging);
3399         Cvar_RegisterVariable(&gl_lightmaps);
3400         Cvar_RegisterVariable(&r_test);
3401         Cvar_RegisterVariable(&r_batch_multidraw);
3402         Cvar_RegisterVariable(&r_batch_multidraw_mintriangles);
3403         Cvar_RegisterVariable(&r_batch_debugdynamicvertexpath);
3404         Cvar_RegisterVariable(&r_glsl_skeletal);
3405         Cvar_RegisterVariable(&r_glsl_saturation);
3406         Cvar_RegisterVariable(&r_glsl_saturation_redcompensate);
3407         Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas);
3408         Cvar_RegisterVariable(&r_framedatasize);
3409         for (i = 0;i < R_BUFFERDATA_COUNT;i++)
3410                 Cvar_RegisterVariable(&r_buffermegs[i]);
3411         Cvar_RegisterVariable(&r_batch_dynamicbuffer);
3412         if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
3413                 Cvar_SetValue("r_fullbrights", 0);
3414 #ifdef DP_MOBILETOUCH
3415         // GLES devices have terrible depth precision in general, so...
3416         Cvar_SetValueQuick(&r_nearclip, 4);
3417         Cvar_SetValueQuick(&r_farclip_base, 4096);
3418         Cvar_SetValueQuick(&r_farclip_world, 0);
3419         Cvar_SetValueQuick(&r_useinfinitefarclip, 0);
3420 #endif
3421         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
3422 }
3423
3424 void Render_Init(void)
3425 {
3426         gl_backend_init();
3427         R_Textures_Init();
3428         GL_Main_Init();
3429         Font_Init();
3430         GL_Draw_Init();
3431         R_Shadow_Init();
3432         R_Sky_Init();
3433         GL_Surf_Init();
3434         Sbar_Init();
3435         R_Particles_Init();
3436         R_Explosion_Init();
3437         R_LightningBeams_Init();
3438         Mod_RenderInit();
3439 }
3440
3441 /*
3442 ===============
3443 GL_Init
3444 ===============
3445 */
3446 #ifndef USE_GLES2
3447 extern char *ENGINE_EXTENSIONS;
3448 void GL_Init (void)
3449 {
3450         gl_renderer = (const char *)qglGetString(GL_RENDERER);
3451         gl_vendor = (const char *)qglGetString(GL_VENDOR);
3452         gl_version = (const char *)qglGetString(GL_VERSION);
3453         gl_extensions = (const char *)qglGetString(GL_EXTENSIONS);
3454
3455         if (!gl_extensions)
3456                 gl_extensions = "";
3457         if (!gl_platformextensions)
3458                 gl_platformextensions = "";
3459
3460         Con_Printf("GL_VENDOR: %s\n", gl_vendor);
3461         Con_Printf("GL_RENDERER: %s\n", gl_renderer);
3462         Con_Printf("GL_VERSION: %s\n", gl_version);
3463         Con_DPrintf("GL_EXTENSIONS: %s\n", gl_extensions);
3464         Con_DPrintf("%s_EXTENSIONS: %s\n", gl_platform, gl_platformextensions);
3465
3466         VID_CheckExtensions();
3467
3468         // LordHavoc: report supported extensions
3469 #ifdef CONFIG_MENU
3470         Con_DPrintf("\nQuakeC extensions for server and client: %s\nQuakeC extensions for menu: %s\n", vm_sv_extensions, vm_m_extensions );
3471 #else
3472         Con_DPrintf("\nQuakeC extensions for server and client: %s\n", vm_sv_extensions );
3473 #endif
3474
3475         // clear to black (loading plaque will be seen over this)
3476         GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 128);
3477 }
3478 #endif
3479
3480 int R_CullBox(const vec3_t mins, const vec3_t maxs)
3481 {
3482         int i;
3483         mplane_t *p;
3484         if (r_trippy.integer)
3485                 return false;
3486         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
3487         {
3488                 p = r_refdef.view.frustum + i;
3489                 switch(p->signbits)
3490                 {
3491                 default:
3492                 case 0:
3493                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3494                                 return true;
3495                         break;
3496                 case 1:
3497                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3498                                 return true;
3499                         break;
3500                 case 2:
3501                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3502                                 return true;
3503                         break;
3504                 case 3:
3505                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3506                                 return true;
3507                         break;
3508                 case 4:
3509                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3510                                 return true;
3511                         break;
3512                 case 5:
3513                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3514                                 return true;
3515                         break;
3516                 case 6:
3517                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3518                                 return true;
3519                         break;
3520                 case 7:
3521                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3522                                 return true;
3523                         break;
3524                 }
3525         }
3526         return false;
3527 }
3528
3529 int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
3530 {
3531         int i;
3532         const mplane_t *p;
3533         if (r_trippy.integer)
3534                 return false;
3535         for (i = 0;i < numplanes;i++)
3536         {
3537                 p = planes + i;
3538                 switch(p->signbits)
3539                 {
3540                 default:
3541                 case 0:
3542                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3543                                 return true;
3544                         break;
3545                 case 1:
3546                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3547                                 return true;
3548                         break;
3549                 case 2:
3550                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3551                                 return true;
3552                         break;
3553                 case 3:
3554                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3555                                 return true;
3556                         break;
3557                 case 4:
3558                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3559                                 return true;
3560                         break;
3561                 case 5:
3562                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3563                                 return true;
3564                         break;
3565                 case 6:
3566                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3567                                 return true;
3568                         break;
3569                 case 7:
3570                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3571                                 return true;
3572                         break;
3573                 }
3574         }
3575         return false;
3576 }
3577
3578 //==================================================================================
3579
3580 // LordHavoc: this stores temporary data used within the same frame
3581
3582 typedef struct r_framedata_mem_s
3583 {
3584         struct r_framedata_mem_s *purge; // older mem block to free on next frame
3585         size_t size; // how much usable space
3586         size_t current; // how much space in use
3587         size_t mark; // last "mark" location, temporary memory can be freed by returning to this
3588         size_t wantedsize; // how much space was allocated
3589         unsigned char *data; // start of real data (16byte aligned)
3590 }
3591 r_framedata_mem_t;
3592
3593 static r_framedata_mem_t *r_framedata_mem;
3594
3595 void R_FrameData_Reset(void)
3596 {
3597         while (r_framedata_mem)
3598         {
3599                 r_framedata_mem_t *next = r_framedata_mem->purge;
3600                 Mem_Free(r_framedata_mem);
3601                 r_framedata_mem = next;
3602         }
3603 }
3604
3605 static void R_FrameData_Resize(qboolean mustgrow)
3606 {
3607         size_t wantedsize;
3608         wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
3609         wantedsize = bound(65536, wantedsize, 1000*1024*1024);
3610         if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize || mustgrow)
3611         {
3612                 r_framedata_mem_t *newmem = (r_framedata_mem_t *)Mem_Alloc(r_main_mempool, wantedsize);
3613                 newmem->wantedsize = wantedsize;
3614                 newmem->data = (unsigned char *)(((size_t)(newmem+1) + 15) & ~15);
3615                 newmem->size = (unsigned char *)newmem + wantedsize - newmem->data;
3616                 newmem->current = 0;
3617                 newmem->mark = 0;
3618                 newmem->purge = r_framedata_mem;
3619                 r_framedata_mem = newmem;
3620         }
3621 }
3622
3623 void R_FrameData_NewFrame(void)
3624 {
3625         R_FrameData_Resize(false);
3626         if (!r_framedata_mem)
3627                 return;
3628         // if we ran out of space on the last frame, free the old memory now
3629         while (r_framedata_mem->purge)
3630         {
3631                 // repeatedly remove the second item in the list, leaving only head
3632                 r_framedata_mem_t *next = r_framedata_mem->purge->purge;
3633                 Mem_Free(r_framedata_mem->purge);
3634                 r_framedata_mem->purge = next;
3635         }
3636         // reset the current mem pointer
3637         r_framedata_mem->current = 0;
3638         r_framedata_mem->mark = 0;
3639 }
3640
3641 void *R_FrameData_Alloc(size_t size)
3642 {
3643         void *data;
3644         float newvalue;
3645
3646         // align to 16 byte boundary - the data pointer is already aligned, so we
3647         // only need to ensure the size of every allocation is also aligned
3648         size = (size + 15) & ~15;
3649
3650         while (!r_framedata_mem || r_framedata_mem->current + size > r_framedata_mem->size)
3651         {
3652                 // emergency - we ran out of space, allocate more memory
3653                 // note: this has no upper-bound, we'll fail to allocate memory eventually and just die
3654                 newvalue = r_framedatasize.value * 2.0f;
3655                 // upper bound based on architecture - if we try to allocate more than this we could overflow, better to loop until we error out on allocation failure
3656                 if (sizeof(size_t) >= 8)
3657                         newvalue = bound(0.25f, newvalue, (float)(1ll << 42));
3658                 else
3659                         newvalue = bound(0.25f, newvalue, (float)(1 << 10));
3660                 // this might not be a growing it, but we'll allocate another buffer every time
3661                 Cvar_SetValueQuick(&r_framedatasize, newvalue);
3662                 R_FrameData_Resize(true);
3663         }
3664
3665         data = r_framedata_mem->data + r_framedata_mem->current;
3666         r_framedata_mem->current += size;
3667
3668         // count the usage for stats
3669         r_refdef.stats[r_stat_framedatacurrent] = max(r_refdef.stats[r_stat_framedatacurrent], (int)r_framedata_mem->current);
3670         r_refdef.stats[r_stat_framedatasize] = max(r_refdef.stats[r_stat_framedatasize], (int)r_framedata_mem->size);
3671
3672         return (void *)data;
3673 }
3674
3675 void *R_FrameData_Store(size_t size, void *data)
3676 {
3677         void *d = R_FrameData_Alloc(size);
3678         if (d && data)
3679                 memcpy(d, data, size);
3680         return d;
3681 }
3682
3683 void R_FrameData_SetMark(void)
3684 {
3685         if (!r_framedata_mem)
3686                 return;
3687         r_framedata_mem->mark = r_framedata_mem->current;
3688 }
3689
3690 void R_FrameData_ReturnToMark(void)
3691 {
3692         if (!r_framedata_mem)
3693                 return;
3694         r_framedata_mem->current = r_framedata_mem->mark;
3695 }
3696
3697 //==================================================================================
3698
3699 // avoid reusing the same buffer objects on consecutive frames
3700 #define R_BUFFERDATA_CYCLE 3
3701
3702 typedef struct r_bufferdata_buffer_s
3703 {
3704         struct r_bufferdata_buffer_s *purge; // older buffer to free on next frame
3705         size_t size; // how much usable space
3706         size_t current; // how much space in use
3707         r_meshbuffer_t *buffer; // the buffer itself
3708 }
3709 r_bufferdata_buffer_t;
3710
3711 static int r_bufferdata_cycle = 0; // incremented and wrapped each frame
3712 static r_bufferdata_buffer_t *r_bufferdata_buffer[R_BUFFERDATA_CYCLE][R_BUFFERDATA_COUNT];
3713
3714 /// frees all dynamic buffers
3715 void R_BufferData_Reset(void)
3716 {
3717         int cycle, type;
3718         r_bufferdata_buffer_t **p, *mem;
3719         for (cycle = 0;cycle < R_BUFFERDATA_CYCLE;cycle++)
3720         {
3721                 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3722                 {
3723                         // free all buffers
3724                         p = &r_bufferdata_buffer[cycle][type];
3725                         while (*p)
3726                         {
3727                                 mem = *p;
3728                                 *p = (*p)->purge;
3729                                 if (mem->buffer)
3730                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3731                                 Mem_Free(mem);
3732                         }
3733                 }
3734         }
3735 }
3736
3737 // resize buffer as needed (this actually makes a new one, the old one will be recycled next frame)
3738 static void R_BufferData_Resize(r_bufferdata_type_t type, qboolean mustgrow, size_t minsize)
3739 {
3740         r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3741         size_t size;
3742         float newvalue = r_buffermegs[type].value;
3743
3744         // increase the cvar if we have to (but only if we already have a mem)
3745         if (mustgrow && mem)
3746                 newvalue *= 2.0f;
3747         newvalue = bound(0.25f, newvalue, 256.0f);
3748         while (newvalue * 1024*1024 < minsize)
3749                 newvalue *= 2.0f;
3750
3751         // clamp the cvar to valid range
3752         newvalue = bound(0.25f, newvalue, 256.0f);
3753         if (r_buffermegs[type].value != newvalue)
3754                 Cvar_SetValueQuick(&r_buffermegs[type], newvalue);
3755
3756         // calculate size in bytes
3757         size = (size_t)(newvalue * 1024*1024);
3758         size = bound(131072, size, 256*1024*1024);
3759
3760         // allocate a new buffer if the size is different (purge old one later)
3761         // or if we were told we must grow the buffer
3762         if (!mem || mem->size != size || mustgrow)
3763         {
3764                 mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem));
3765                 mem->size = size;
3766                 mem->current = 0;
3767                 if (type == R_BUFFERDATA_VERTEX)
3768                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbuffervertex", false, false, true, false);
3769                 else if (type == R_BUFFERDATA_INDEX16)
3770                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex16", true, false, true, true);
3771                 else if (type == R_BUFFERDATA_INDEX32)
3772                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex32", true, false, true, false);
3773                 else if (type == R_BUFFERDATA_UNIFORM)
3774                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferuniform", false, true, true, false);
3775                 mem->purge = r_bufferdata_buffer[r_bufferdata_cycle][type];
3776                 r_bufferdata_buffer[r_bufferdata_cycle][type] = mem;
3777         }
3778 }
3779
3780 void R_BufferData_NewFrame(void)
3781 {
3782         int type;
3783         r_bufferdata_buffer_t **p, *mem;
3784         // cycle to the next frame's buffers
3785         r_bufferdata_cycle = (r_bufferdata_cycle + 1) % R_BUFFERDATA_CYCLE;
3786         // if we ran out of space on the last time we used these buffers, free the old memory now
3787         for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3788         {
3789                 if (r_bufferdata_buffer[r_bufferdata_cycle][type])
3790                 {
3791                         R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072);
3792                         // free all but the head buffer, this is how we recycle obsolete
3793                         // buffers after they are no longer in use
3794                         p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge;
3795                         while (*p)
3796                         {
3797                                 mem = *p;
3798                                 *p = (*p)->purge;
3799                                 if (mem->buffer)
3800                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3801                                 Mem_Free(mem);
3802                         }
3803                         // reset the current offset
3804                         r_bufferdata_buffer[r_bufferdata_cycle][type]->current = 0;
3805                 }
3806         }
3807 }
3808
3809 r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset)
3810 {
3811         r_bufferdata_buffer_t *mem;
3812         int offset = 0;
3813         int padsize;
3814
3815         *returnbufferoffset = 0;
3816
3817         // align size to a byte boundary appropriate for the buffer type, this
3818         // makes all allocations have aligned start offsets
3819         if (type == R_BUFFERDATA_UNIFORM)
3820                 padsize = (datasize + r_uniformbufferalignment - 1) & ~(r_uniformbufferalignment - 1);
3821         else
3822                 padsize = (datasize + 15) & ~15;
3823
3824         // if we ran out of space in this buffer we must allocate a new one
3825         if (!r_bufferdata_buffer[r_bufferdata_cycle][type] || r_bufferdata_buffer[r_bufferdata_cycle][type]->current + padsize > r_bufferdata_buffer[r_bufferdata_cycle][type]->size)
3826                 R_BufferData_Resize(type, true, padsize);
3827
3828         // if the resize did not give us enough memory, fail
3829         if (!r_bufferdata_buffer[r_bufferdata_cycle][type] || r_bufferdata_buffer[r_bufferdata_cycle][type]->current + padsize > r_bufferdata_buffer[r_bufferdata_cycle][type]->size)
3830                 Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
3831
3832         mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3833         offset = (int)mem->current;
3834         mem->current += padsize;
3835
3836         // upload the data to the buffer at the chosen offset
3837         if (offset == 0)
3838                 R_Mesh_UpdateMeshBuffer(mem->buffer, NULL, mem->size, false, 0);
3839         R_Mesh_UpdateMeshBuffer(mem->buffer, data, datasize, true, offset);
3840
3841         // count the usage for stats
3842         r_refdef.stats[r_stat_bufferdatacurrent_vertex + type] = max(r_refdef.stats[r_stat_bufferdatacurrent_vertex + type], (int)mem->current);
3843         r_refdef.stats[r_stat_bufferdatasize_vertex + type] = max(r_refdef.stats[r_stat_bufferdatasize_vertex + type], (int)mem->size);
3844
3845         // return the buffer offset
3846         *returnbufferoffset = offset;
3847
3848         return mem->buffer;
3849 }
3850
3851 //==================================================================================
3852
3853 // LordHavoc: animcache originally written by Echon, rewritten since then
3854
3855 /**
3856  * Animation cache prevents re-generating mesh data for an animated model
3857  * multiple times in one frame for lighting, shadowing, reflections, etc.
3858  */
3859
3860 void R_AnimCache_Free(void)
3861 {
3862 }
3863
3864 void R_AnimCache_ClearCache(void)
3865 {
3866         int i;
3867         entity_render_t *ent;
3868
3869         for (i = 0;i < r_refdef.scene.numentities;i++)
3870         {
3871                 ent = r_refdef.scene.entities[i];
3872                 ent->animcache_vertex3f = NULL;
3873                 ent->animcache_vertex3f_vertexbuffer = NULL;
3874                 ent->animcache_vertex3f_bufferoffset = 0;
3875                 ent->animcache_normal3f = NULL;
3876                 ent->animcache_normal3f_vertexbuffer = NULL;
3877                 ent->animcache_normal3f_bufferoffset = 0;
3878                 ent->animcache_svector3f = NULL;
3879                 ent->animcache_svector3f_vertexbuffer = NULL;
3880                 ent->animcache_svector3f_bufferoffset = 0;
3881                 ent->animcache_tvector3f = NULL;
3882                 ent->animcache_tvector3f_vertexbuffer = NULL;
3883                 ent->animcache_tvector3f_bufferoffset = 0;
3884                 ent->animcache_vertexmesh = NULL;
3885                 ent->animcache_vertexmesh_vertexbuffer = NULL;
3886                 ent->animcache_vertexmesh_bufferoffset = 0;
3887                 ent->animcache_skeletaltransform3x4 = NULL;
3888                 ent->animcache_skeletaltransform3x4buffer = NULL;
3889                 ent->animcache_skeletaltransform3x4offset = 0;
3890                 ent->animcache_skeletaltransform3x4size = 0;
3891         }
3892 }
3893
3894 static void R_AnimCache_UpdateEntityMeshBuffers(entity_render_t *ent, int numvertices)
3895 {
3896         int i;
3897
3898         // check if we need the meshbuffers
3899         if (!vid.useinterleavedarrays)
3900                 return;
3901
3902         if (!ent->animcache_vertexmesh && ent->animcache_normal3f)
3903                 ent->animcache_vertexmesh = (r_vertexmesh_t *)R_FrameData_Alloc(sizeof(r_vertexmesh_t)*numvertices);
3904         // TODO: upload vertexbuffer?
3905         if (ent->animcache_vertexmesh)
3906         {
3907                 r_refdef.stats[r_stat_animcache_vertexmesh_count] += 1;
3908                 r_refdef.stats[r_stat_animcache_vertexmesh_vertices] += numvertices;
3909                 r_refdef.stats[r_stat_animcache_vertexmesh_maxvertices] = max(r_refdef.stats[r_stat_animcache_vertexmesh_maxvertices], numvertices);
3910                 memcpy(ent->animcache_vertexmesh, ent->model->surfmesh.data_vertexmesh, sizeof(r_vertexmesh_t)*numvertices);
3911                 for (i = 0;i < numvertices;i++)
3912                         memcpy(ent->animcache_vertexmesh[i].vertex3f, ent->animcache_vertex3f + 3*i, sizeof(float[3]));
3913                 if (ent->animcache_svector3f)
3914                         for (i = 0;i < numvertices;i++)
3915                                 memcpy(ent->animcache_vertexmesh[i].svector3f, ent->animcache_svector3f + 3*i, sizeof(float[3]));
3916                 if (ent->animcache_tvector3f)
3917                         for (i = 0;i < numvertices;i++)
3918                                 memcpy(ent->animcache_vertexmesh[i].tvector3f, ent->animcache_tvector3f + 3*i, sizeof(float[3]));
3919                 if (ent->animcache_normal3f)
3920                         for (i = 0;i < numvertices;i++)
3921                                 memcpy(ent->animcache_vertexmesh[i].normal3f, ent->animcache_normal3f + 3*i, sizeof(float[3]));
3922         }
3923 }
3924
3925 qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
3926 {
3927         dp_model_t *model = ent->model;
3928         int numvertices;
3929
3930         // see if this ent is worth caching
3931         if (!model || !model->Draw || !model->AnimateVertices)
3932                 return false;
3933         // nothing to cache if it contains no animations and has no skeleton
3934         if (!model->surfmesh.isanimated && !(model->num_bones && ent->skeleton && ent->skeleton->relativetransforms))
3935                 return false;
3936         // see if it is already cached for gpuskeletal
3937         if (ent->animcache_skeletaltransform3x4)
3938                 return false;
3939         // see if it is already cached as a mesh
3940         if (ent->animcache_vertex3f)
3941         {
3942                 // check if we need to add normals or tangents
3943                 if (ent->animcache_normal3f)
3944                         wantnormals = false;
3945                 if (ent->animcache_svector3f)
3946                         wanttangents = false;
3947                 if (!wantnormals && !wanttangents)
3948                         return false;
3949         }
3950
3951         // check which kind of cache we need to generate
3952         if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
3953         {
3954                 // cache the skeleton so the vertex shader can use it
3955                 r_refdef.stats[r_stat_animcache_skeletal_count] += 1;
3956                 r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones;
3957                 r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones);
3958                 ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones);
3959                 Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4); 
3960                 // note: this can fail if the buffer is at the grow limit
3961                 ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones;
3962                 ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset);
3963         }
3964         else if (ent->animcache_vertex3f)
3965         {
3966                 // mesh was already cached but we may need to add normals/tangents
3967                 // (this only happens with multiple views, reflections, cameras, etc)
3968                 if (wantnormals || wanttangents)
3969                 {
3970                         numvertices = model->surfmesh.num_vertices;
3971                         if (wantnormals)
3972                                 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3973                         if (wanttangents)
3974                         {
3975                                 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3976                                 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3977                         }
3978                         model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
3979                         R_AnimCache_UpdateEntityMeshBuffers(ent, model->surfmesh.num_vertices);
3980                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3981                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3982                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3983                 }
3984         }
3985         else
3986         {
3987                 // generate mesh cache
3988                 numvertices = model->surfmesh.num_vertices;
3989                 ent->animcache_vertex3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3990                 if (wantnormals)
3991                         ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3992                 if (wanttangents)
3993                 {
3994                         ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3995                         ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3996                 }
3997                 model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
3998                 R_AnimCache_UpdateEntityMeshBuffers(ent, model->surfmesh.num_vertices);
3999                 if (wantnormals || wanttangents)
4000                 {
4001                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
4002                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
4003                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
4004                 }
4005                 r_refdef.stats[r_stat_animcache_shape_count] += 1;
4006                 r_refdef.stats[r_stat_animcache_shape_vertices] += numvertices;
4007                 r_refdef.stats[r_stat_animcache_shape_maxvertices] = max(r_refdef.stats[r_stat_animcache_shape_maxvertices], numvertices);
4008         }
4009         return true;
4010 }
4011
4012 void R_AnimCache_CacheVisibleEntities(void)
4013 {
4014         int i;
4015
4016         // TODO: thread this
4017         // NOTE: R_PrepareRTLights() also caches entities
4018
4019         for (i = 0;i < r_refdef.scene.numentities;i++)
4020                 if (r_refdef.viewcache.entityvisible[i])
4021                         R_AnimCache_GetEntity(r_refdef.scene.entities[i], true, true);
4022 }
4023
4024 //==================================================================================
4025
4026 qboolean R_CanSeeBox(int numsamples, vec_t eyejitter, vec_t entboxenlarge, vec_t entboxexpand, vec_t pad, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs)
4027 {
4028         int i;
4029         vec3_t eyemins, eyemaxs;
4030         vec3_t boxmins, boxmaxs;
4031         vec3_t padmins, padmaxs;
4032         vec3_t start;
4033         vec3_t end;
4034         dp_model_t *model = r_refdef.scene.worldmodel;
4035         static vec3_t positions[] = {
4036                 { 0.5f, 0.5f, 0.5f },
4037                 { 0.0f, 0.0f, 0.0f },
4038                 { 0.0f, 0.0f, 1.0f },
4039                 { 0.0f, 1.0f, 0.0f },
4040                 { 0.0f, 1.0f, 1.0f },
4041                 { 1.0f, 0.0f, 0.0f },
4042                 { 1.0f, 0.0f, 1.0f },
4043                 { 1.0f, 1.0f, 0.0f },
4044                 { 1.0f, 1.0f, 1.0f },
4045         };
4046
4047         // sample count can be set to -1 to skip this logic, for flicker-prone objects
4048         if (numsamples < 0)
4049                 return true;
4050
4051         // view origin is not used for culling in portal/reflection/refraction renders or isometric views
4052         if (!r_refdef.view.usevieworiginculling)
4053                 return true;
4054
4055         if (!r_cullentities_trace_entityocclusion.integer && (!model || !model->brush.TraceLineOfSight))
4056                 return true;
4057
4058         // expand the eye box a little
4059         eyemins[0] = eye[0] - eyejitter;
4060         eyemaxs[0] = eye[0] + eyejitter;
4061         eyemins[1] = eye[1] - eyejitter;
4062         eyemaxs[1] = eye[1] + eyejitter;
4063         eyemins[2] = eye[2] - eyejitter;
4064         eyemaxs[2] = eye[2] + eyejitter;
4065         // expand the box a little
4066         boxmins[0] = (entboxenlarge + 1) * entboxmins[0] - entboxenlarge * entboxmaxs[0] - entboxexpand;
4067         boxmaxs[0] = (entboxenlarge + 1) * entboxmaxs[0] - entboxenlarge * entboxmins[0] + entboxexpand;
4068         boxmins[1] = (entboxenlarge + 1) * entboxmins[1] - entboxenlarge * entboxmaxs[1] - entboxexpand;
4069         boxmaxs[1] = (entboxenlarge + 1) * entboxmaxs[1] - entboxenlarge * entboxmins[1] + entboxexpand;
4070         boxmins[2] = (entboxenlarge + 1) * entboxmins[2] - entboxenlarge * entboxmaxs[2] - entboxexpand;
4071         boxmaxs[2] = (entboxenlarge + 1) * entboxmaxs[2] - entboxenlarge * entboxmins[2] + entboxexpand;
4072         // make an even larger box for the acceptable area
4073         padmins[0] = boxmins[0] - pad;
4074         padmaxs[0] = boxmaxs[0] + pad;
4075         padmins[1] = boxmins[1] - pad;
4076         padmaxs[1] = boxmaxs[1] + pad;
4077         padmins[2] = boxmins[2] - pad;
4078         padmaxs[2] = boxmaxs[2] + pad;
4079
4080         // return true if eye overlaps enlarged box
4081         if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs))
4082                 return true;
4083
4084         // try specific positions in the box first - note that these can be cached
4085         if (r_cullentities_trace_entityocclusion.integer)
4086         {
4087                 for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++)
4088                 {
4089                         VectorCopy(eye, start);
4090                         end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0];
4091                         end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1];
4092                         end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2];
4093                         //trace_t trace = CL_TraceLine(start, end, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, 0.0f, true, false, NULL, true, true);
4094                         trace_t trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
4095                         // not picky - if the trace ended anywhere in the box we're good
4096                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4097                                 return true;
4098                 }
4099         }
4100         else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4101                 return true;
4102
4103         // try various random positions
4104         for (i = 0; i < numsamples; i++)
4105         {
4106                 VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
4107                 VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
4108                 if (r_cullentities_trace_entityocclusion.integer)
4109                 {
4110                         trace_t trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
4111                         // not picky - if the trace ended anywhere in the box we're good
4112                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4113                                 return true;
4114                 }
4115                 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4116                         return true;
4117         }
4118
4119         return false;
4120 }
4121
4122
4123 static void R_View_UpdateEntityVisible (void)
4124 {
4125         int i;
4126         int renderimask;
4127         int samples;
4128         entity_render_t *ent;
4129
4130         if (r_refdef.envmap || r_fb.water.hideplayer)
4131                 renderimask = RENDER_EXTERIORMODEL | RENDER_VIEWMODEL;
4132         else if (chase_active.integer || r_fb.water.renderingscene)
4133                 renderimask = RENDER_VIEWMODEL;
4134         else
4135                 renderimask = RENDER_EXTERIORMODEL;
4136         if (!r_drawviewmodel.integer)
4137                 renderimask |= RENDER_VIEWMODEL;
4138         if (!r_drawexteriormodel.integer)
4139                 renderimask |= RENDER_EXTERIORMODEL;
4140         memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
4141         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
4142         {
4143                 // worldmodel can check visibility
4144                 for (i = 0;i < r_refdef.scene.numentities;i++)
4145                 {
4146                         ent = r_refdef.scene.entities[i];
4147                         if (!(ent->flags & renderimask))
4148                         if (!R_CullBox(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
4149                         if ((ent->flags & (RENDER_NODEPTHTEST | RENDER_WORLDOBJECT | RENDER_VIEWMODEL)) || r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, ent->mins, ent->maxs))
4150                                 r_refdef.viewcache.entityvisible[i] = true;
4151                 }
4152         }
4153         else
4154         {
4155                 // no worldmodel or it can't check visibility
4156                 for (i = 0;i < r_refdef.scene.numentities;i++)
4157                 {
4158                         ent = r_refdef.scene.entities[i];
4159                         if (!(ent->flags & renderimask))
4160                         if (!R_CullBox(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
4161                                 r_refdef.viewcache.entityvisible[i] = true;
4162                 }
4163         }
4164         if (r_cullentities_trace.integer)
4165         {
4166                 for (i = 0;i < r_refdef.scene.numentities;i++)
4167                 {
4168                         if (!r_refdef.viewcache.entityvisible[i])
4169                                 continue;
4170                         ent = r_refdef.scene.entities[i];
4171                         if (!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
4172                         {
4173                                 samples = ent->last_trace_visibility == 0 ? r_cullentities_trace_tempentitysamples.integer : r_cullentities_trace_samples.integer;
4174                                 if (R_CanSeeBox(samples, r_cullentities_trace_eyejitter.value, r_cullentities_trace_enlarge.value, r_cullentities_trace_expand.value, r_cullentities_trace_pad.value, r_refdef.view.origin, ent->mins, ent->maxs))
4175                                         ent->last_trace_visibility = realtime;
4176                                 if (ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
4177                                         r_refdef.viewcache.entityvisible[i] = 0;
4178                         }
4179                 }
4180         }
4181 }
4182
4183 /// only used if skyrendermasked, and normally returns false
4184 static int R_DrawBrushModelsSky (void)
4185 {
4186         int i, sky;
4187         entity_render_t *ent;
4188
4189         sky = false;
4190         for (i = 0;i < r_refdef.scene.numentities;i++)
4191         {
4192                 if (!r_refdef.viewcache.entityvisible[i])
4193                         continue;
4194                 ent = r_refdef.scene.entities[i];
4195                 if (!ent->model || !ent->model->DrawSky)
4196                         continue;
4197                 ent->model->DrawSky(ent);
4198                 sky = true;
4199         }
4200         return sky;
4201 }
4202
4203 static void R_DrawNoModel(entity_render_t *ent);
4204 static void R_DrawModels(void)
4205 {
4206         int i;
4207         entity_render_t *ent;
4208
4209         for (i = 0;i < r_refdef.scene.numentities;i++)
4210         {
4211                 if (!r_refdef.viewcache.entityvisible[i])
4212                         continue;
4213                 ent = r_refdef.scene.entities[i];
4214                 r_refdef.stats[r_stat_entities]++;
4215                 /*
4216                 if (ent->model && !strncmp(ent->model->name, "models/proto_", 13))
4217                 {
4218                         vec3_t f, l, u, o;
4219                         Matrix4x4_ToVectors(&ent->matrix, f, l, u, o);
4220                         Con_Printf("R_DrawModels\n");
4221                         Con_Printf("model %s O %f %f %f F %f %f %f L %f %f %f U %f %f %f\n", ent->model->name, o[0], o[1], o[2], f[0], f[1], f[2], l[0], l[1], l[2], u[0], u[1], u[2]);
4222                         Con_Printf("group: %i %f %i %f %i %f %i %f\n", ent->framegroupblend[0].frame, ent->framegroupblend[0].lerp, ent->framegroupblend[1].frame, ent->framegroupblend[1].lerp, ent->framegroupblend[2].frame, ent->framegroupblend[2].lerp, ent->framegroupblend[3].frame, ent->framegroupblend[3].lerp);
4223                         Con_Printf("blend: %i %f %i %f %i %f %i %f %i %f %i %f %i %f %i %f\n", ent->frameblend[0].subframe, ent->frameblend[0].lerp, ent->frameblend[1].subframe, ent->frameblend[1].lerp, ent->frameblend[2].subframe, ent->frameblend[2].lerp, ent->frameblend[3].subframe, ent->frameblend[3].lerp, ent->frameblend[4].subframe, ent->frameblend[4].lerp, ent->frameblend[5].subframe, ent->frameblend[5].lerp, ent->frameblend[6].subframe, ent->frameblend[6].lerp, ent->frameblend[7].subframe, ent->frameblend[7].lerp);
4224                 }
4225                 */
4226                 if (ent->model && ent->model->Draw != NULL)
4227                         ent->model->Draw(ent);
4228                 else
4229                         R_DrawNoModel(ent);
4230         }
4231 }
4232
4233 static void R_DrawModelsDepth(void)
4234 {
4235         int i;
4236         entity_render_t *ent;
4237
4238         for (i = 0;i < r_refdef.scene.numentities;i++)
4239         {
4240                 if (!r_refdef.viewcache.entityvisible[i])
4241                         continue;
4242                 ent = r_refdef.scene.entities[i];
4243                 if (ent->model && ent->model->DrawDepth != NULL)
4244                         ent->model->DrawDepth(ent);
4245         }
4246 }
4247
4248 static void R_DrawModelsDebug(void)
4249 {
4250         int i;
4251         entity_render_t *ent;
4252
4253         for (i = 0;i < r_refdef.scene.numentities;i++)
4254         {
4255                 if (!r_refdef.viewcache.entityvisible[i])
4256                         continue;
4257                 ent = r_refdef.scene.entities[i];
4258                 if (ent->model && ent->model->DrawDebug != NULL)
4259                         ent->model->DrawDebug(ent);
4260         }
4261 }
4262
4263 static void R_DrawModelsAddWaterPlanes(void)
4264 {
4265         int i;
4266         entity_render_t *ent;
4267
4268         for (i = 0;i < r_refdef.scene.numentities;i++)
4269         {
4270                 if (!r_refdef.viewcache.entityvisible[i])
4271                         continue;
4272                 ent = r_refdef.scene.entities[i];
4273                 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
4274                         ent->model->DrawAddWaterPlanes(ent);
4275         }
4276 }
4277
4278 static float irisvecs[7][3] = {{0, 0, 0}, {-1, 0, 0}, {1, 0, 0}, {0, -1, 0}, {0, 1, 0}, {0, 0, -1}, {0, 0, 1}};
4279
4280 void R_HDR_UpdateIrisAdaptation(const vec3_t point)
4281 {
4282         if (r_hdr_irisadaptation.integer)
4283         {
4284                 vec3_t p;
4285                 vec3_t ambient;
4286                 vec3_t diffuse;
4287                 vec3_t diffusenormal;
4288                 vec3_t forward;
4289                 vec_t brightness = 0.0f;
4290                 vec_t goal;
4291                 vec_t current;
4292                 vec_t d;
4293                 int c;
4294                 VectorCopy(r_refdef.view.forward, forward);
4295                 for (c = 0;c < (int)(sizeof(irisvecs)/sizeof(irisvecs[0]));c++)
4296                 {
4297                         p[0] = point[0] + irisvecs[c][0] * r_hdr_irisadaptation_radius.value;
4298                         p[1] = point[1] + irisvecs[c][1] * r_hdr_irisadaptation_radius.value;
4299                         p[2] = point[2] + irisvecs[c][2] * r_hdr_irisadaptation_radius.value;
4300                         R_CompleteLightPoint(ambient, diffuse, diffusenormal, p, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity);
4301                         d = DotProduct(forward, diffusenormal);
4302                         brightness += VectorLength(ambient);
4303                         if (d > 0)
4304                                 brightness += d * VectorLength(diffuse);
4305                 }
4306                 brightness *= 1.0f / c;
4307                 brightness += 0.00001f; // make sure it's never zero
4308                 goal = r_hdr_irisadaptation_multiplier.value / brightness;
4309                 goal = bound(r_hdr_irisadaptation_minvalue.value, goal, r_hdr_irisadaptation_maxvalue.value);
4310                 current = r_hdr_irisadaptation_value.value;
4311                 if (current < goal)
4312                         current = min(current + r_hdr_irisadaptation_fade_up.value * cl.realframetime, goal);
4313                 else if (current > goal)
4314                         current = max(current - r_hdr_irisadaptation_fade_down.value * cl.realframetime, goal);
4315                 if (fabs(r_hdr_irisadaptation_value.value - current) > 0.0001f)
4316                         Cvar_SetValueQuick(&r_hdr_irisadaptation_value, current);
4317         }
4318         else if (r_hdr_irisadaptation_value.value != 1.0f)
4319                 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, 1.0f);
4320 }
4321
4322 static void R_View_SetFrustum(const int *scissor)
4323 {
4324         int i;
4325         double fpx = +1, fnx = -1, fpy = +1, fny = -1;
4326         vec3_t forward, left, up, origin, v;
4327
4328         if(scissor)
4329         {
4330                 // flipped x coordinates (because x points left here)
4331                 fpx =  1.0 - 2.0 * (scissor[0]              - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4332                 fnx =  1.0 - 2.0 * (scissor[0] + scissor[2] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4333                 // non-flipped y coordinates
4334                 fny = -1.0 + 2.0 * (scissor[1]              - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4335                 fpy = -1.0 + 2.0 * (scissor[1] + scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4336         }
4337
4338         // we can't trust r_refdef.view.forward and friends in reflected scenes
4339         Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin);
4340
4341 #if 0
4342         r_refdef.view.frustum[0].normal[0] = 0 - 1.0 / r_refdef.view.frustum_x;
4343         r_refdef.view.frustum[0].normal[1] = 0 - 0;
4344         r_refdef.view.frustum[0].normal[2] = -1 - 0;
4345         r_refdef.view.frustum[1].normal[0] = 0 + 1.0 / r_refdef.view.frustum_x;
4346         r_refdef.view.frustum[1].normal[1] = 0 + 0;
4347         r_refdef.view.frustum[1].normal[2] = -1 + 0;
4348         r_refdef.view.frustum[2].normal[0] = 0 - 0;
4349         r_refdef.view.frustum[2].normal[1] = 0 - 1.0 / r_refdef.view.frustum_y;
4350         r_refdef.view.frustum[2].normal[2] = -1 - 0;
4351         r_refdef.view.frustum[3].normal[0] = 0 + 0;
4352         r_refdef.view.frustum[3].normal[1] = 0 + 1.0 / r_refdef.view.frustum_y;
4353         r_refdef.view.frustum[3].normal[2] = -1 + 0;
4354 #endif
4355
4356 #if 0
4357         zNear = r_refdef.nearclip;
4358         nudge = 1.0 - 1.0 / (1<<23);
4359         r_refdef.view.frustum[4].normal[0] = 0 - 0;
4360         r_refdef.view.frustum[4].normal[1] = 0 - 0;
4361         r_refdef.view.frustum[4].normal[2] = -1 - -nudge;
4362         r_refdef.view.frustum[4].dist = 0 - -2 * zNear * nudge;
4363         r_refdef.view.frustum[5].normal[0] = 0 + 0;
4364         r_refdef.view.frustum[5].normal[1] = 0 + 0;
4365         r_refdef.view.frustum[5].normal[2] = -1 + -nudge;
4366         r_refdef.view.frustum[5].dist = 0 + -2 * zNear * nudge;
4367 #endif
4368
4369
4370
4371 #if 0
4372         r_refdef.view.frustum[0].normal[0] = m[3] - m[0];
4373         r_refdef.view.frustum[0].normal[1] = m[7] - m[4];
4374         r_refdef.view.frustum[0].normal[2] = m[11] - m[8];
4375         r_refdef.view.frustum[0].dist = m[15] - m[12];
4376
4377         r_refdef.view.frustum[1].normal[0] = m[3] + m[0];
4378         r_refdef.view.frustum[1].normal[1] = m[7] + m[4];
4379         r_refdef.view.frustum[1].normal[2] = m[11] + m[8];
4380         r_refdef.view.frustum[1].dist = m[15] + m[12];
4381
4382         r_refdef.view.frustum[2].normal[0] = m[3] - m[1];
4383         r_refdef.view.frustum[2].normal[1] = m[7] - m[5];
4384         r_refdef.view.frustum[2].normal[2] = m[11] - m[9];
4385         r_refdef.view.frustum[2].dist = m[15] - m[13];
4386
4387         r_refdef.view.frustum[3].normal[0] = m[3] + m[1];
4388         r_refdef.view.frustum[3].normal[1] = m[7] + m[5];
4389         r_refdef.view.frustum[3].normal[2] = m[11] + m[9];
4390         r_refdef.view.frustum[3].dist = m[15] + m[13];
4391
4392         r_refdef.view.frustum[4].normal[0] = m[3] - m[2];
4393         r_refdef.view.frustum[4].normal[1] = m[7] - m[6];
4394         r_refdef.view.frustum[4].normal[2] = m[11] - m[10];
4395         r_refdef.view.frustum[4].dist = m[15] - m[14];
4396
4397         r_refdef.view.frustum[5].normal[0] = m[3] + m[2];
4398         r_refdef.view.frustum[5].normal[1] = m[7] + m[6];
4399         r_refdef.view.frustum[5].normal[2] = m[11] + m[10];
4400         r_refdef.view.frustum[5].dist = m[15] + m[14];
4401 #endif
4402
4403         if (r_refdef.view.useperspective)
4404         {
4405                 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
4406                 VectorMAMAM(1024, forward, fnx * 1024.0 * r_refdef.view.frustum_x, left, fny * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[0]);
4407                 VectorMAMAM(1024, forward, fpx * 1024.0 * r_refdef.view.frustum_x, left, fny * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[1]);
4408                 VectorMAMAM(1024, forward, fnx * 1024.0 * r_refdef.view.frustum_x, left, fpy * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[2]);
4409                 VectorMAMAM(1024, forward, fpx * 1024.0 * r_refdef.view.frustum_x, left, fpy * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[3]);
4410
4411                 // then the normals from the corners relative to origin
4412                 CrossProduct(r_refdef.view.frustumcorner[2], r_refdef.view.frustumcorner[0], r_refdef.view.frustum[0].normal);
4413                 CrossProduct(r_refdef.view.frustumcorner[1], r_refdef.view.frustumcorner[3], r_refdef.view.frustum[1].normal);
4414                 CrossProduct(r_refdef.view.frustumcorner[0], r_refdef.view.frustumcorner[1], r_refdef.view.frustum[2].normal);
4415                 CrossProduct(r_refdef.view.frustumcorner[3], r_refdef.view.frustumcorner[2], r_refdef.view.frustum[3].normal);
4416
4417                 // in a NORMAL view, forward cross left == up
4418                 // in a REFLECTED view, forward cross left == down
4419                 // so our cross products above need to be adjusted for a left handed coordinate system
4420                 CrossProduct(forward, left, v);
4421                 if(DotProduct(v, up) < 0)
4422                 {
4423                         VectorNegate(r_refdef.view.frustum[0].normal, r_refdef.view.frustum[0].normal);
4424                         VectorNegate(r_refdef.view.frustum[1].normal, r_refdef.view.frustum[1].normal);
4425                         VectorNegate(r_refdef.view.frustum[2].normal, r_refdef.view.frustum[2].normal);
4426                         VectorNegate(r_refdef.view.frustum[3].normal, r_refdef.view.frustum[3].normal);
4427                 }
4428
4429                 // Leaving those out was a mistake, those were in the old code, and they
4430                 // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix
4431                 // I couldn't reproduce it after adding those normalizations. --blub
4432                 VectorNormalize(r_refdef.view.frustum[0].normal);
4433                 VectorNormalize(r_refdef.view.frustum[1].normal);
4434                 VectorNormalize(r_refdef.view.frustum[2].normal);
4435                 VectorNormalize(r_refdef.view.frustum[3].normal);
4436
4437                 // make the corners absolute
4438                 VectorAdd(r_refdef.view.frustumcorner[0], r_refdef.view.origin, r_refdef.view.frustumcorner[0]);
4439                 VectorAdd(r_refdef.view.frustumcorner[1], r_refdef.view.origin, r_refdef.view.frustumcorner[1]);
4440                 VectorAdd(r_refdef.view.frustumcorner[2], r_refdef.view.origin, r_refdef.view.frustumcorner[2]);
4441                 VectorAdd(r_refdef.view.frustumcorner[3], r_refdef.view.origin, r_refdef.view.frustumcorner[3]);
4442
4443                 // one more normal
4444                 VectorCopy(forward, r_refdef.view.frustum[4].normal);
4445
4446                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal);
4447                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal);
4448                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal);
4449                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal);
4450                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip;
4451         }
4452         else
4453         {
4454                 VectorScale(left, -1.0f, r_refdef.view.frustum[0].normal);
4455                 VectorScale(left,  1.0f, r_refdef.view.frustum[1].normal);
4456                 VectorScale(up, -1.0f, r_refdef.view.frustum[2].normal);
4457                 VectorScale(up,  1.0f, r_refdef.view.frustum[3].normal);
4458                 VectorScale(forward, -1.0f, r_refdef.view.frustum[4].normal);
4459                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal) - r_refdef.view.ortho_x;
4460                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal) - r_refdef.view.ortho_x;
4461                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal) - r_refdef.view.ortho_y;
4462                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal) - r_refdef.view.ortho_y;
4463                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) - r_refdef.farclip;
4464         }
4465         r_refdef.view.numfrustumplanes = 5;
4466
4467         if (r_refdef.view.useclipplane)
4468         {
4469                 r_refdef.view.numfrustumplanes = 6;
4470                 r_refdef.view.frustum[5] = r_refdef.view.clipplane;
4471         }
4472
4473         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
4474                 PlaneClassify(r_refdef.view.frustum + i);
4475
4476         // LordHavoc: note to all quake engine coders, Quake had a special case
4477         // for 90 degrees which assumed a square view (wrong), so I removed it,
4478         // Quake2 has it disabled as well.
4479
4480         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
4481         //RotatePointAroundVector( r_refdef.view.frustum[0].normal, up, forward, -(90 - r_refdef.fov_x / 2));
4482         //r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, frustum[0].normal);
4483         //PlaneClassify(&frustum[0]);
4484
4485         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
4486         //RotatePointAroundVector( r_refdef.view.frustum[1].normal, up, forward, (90 - r_refdef.fov_x / 2));
4487         //r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, frustum[1].normal);
4488         //PlaneClassify(&frustum[1]);
4489
4490         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
4491         //RotatePointAroundVector( r_refdef.view.frustum[2].normal, left, forward, -(90 - r_refdef.fov_y / 2));
4492         //r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, frustum[2].normal);
4493         //PlaneClassify(&frustum[2]);
4494
4495         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
4496         //RotatePointAroundVector( r_refdef.view.frustum[3].normal, left, forward, (90 - r_refdef.fov_y / 2));
4497         //r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, frustum[3].normal);
4498         //PlaneClassify(&frustum[3]);
4499
4500         // nearclip plane
4501         //VectorCopy(forward, r_refdef.view.frustum[4].normal);
4502         //r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, frustum[4].normal) + r_nearclip.value;
4503         //PlaneClassify(&frustum[4]);
4504 }
4505
4506 static void R_View_UpdateWithScissor(const int *myscissor)
4507 {
4508         R_Main_ResizeViewCache();
4509         R_View_SetFrustum(myscissor);
4510         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4511         R_View_UpdateEntityVisible();
4512 }
4513
4514 static void R_View_Update(void)
4515 {
4516         R_Main_ResizeViewCache();
4517         R_View_SetFrustum(NULL);
4518         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4519         R_View_UpdateEntityVisible();
4520 }
4521
4522 float viewscalefpsadjusted = 1.0f;
4523
4524 static void R_GetScaledViewSize(int width, int height, int *outwidth, int *outheight)
4525 {
4526         float scale = r_viewscale.value * sqrt(viewscalefpsadjusted);
4527         scale = bound(0.03125f, scale, 1.0f);
4528         *outwidth = (int)ceil(width * scale);
4529         *outheight = (int)ceil(height * scale);
4530 }
4531
4532 void R_SetupView(qboolean allowwaterclippingplane, int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4533 {
4534         const float *customclipplane = NULL;
4535         float plane[4];
4536         int /*rtwidth,*/ rtheight;
4537         if (r_refdef.view.useclipplane && allowwaterclippingplane)
4538         {
4539                 // LadyHavoc: couldn't figure out how to make this approach work the same in DPSOFTRAST
4540                 vec_t dist = r_refdef.view.clipplane.dist - r_water_clippingplanebias.value;
4541                 vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
4542                 if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
4543                         dist = r_refdef.view.clipplane.dist;
4544                 plane[0] = r_refdef.view.clipplane.normal[0];
4545                 plane[1] = r_refdef.view.clipplane.normal[1];
4546                 plane[2] = r_refdef.view.clipplane.normal[2];
4547                 plane[3] = -dist;
4548                 customclipplane = plane;
4549         }
4550
4551         //rtwidth = viewfbo ? R_TextureWidth(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.width;
4552         rtheight = viewfbo ? R_TextureHeight(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.height;
4553
4554         if (!r_refdef.view.useperspective)
4555                 R_Viewport_InitOrtho3D(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.ortho_x, r_refdef.view.ortho_y, -r_refdef.farclip, r_refdef.farclip, customclipplane);
4556         else if (vid.stencil && r_useinfinitefarclip.integer)
4557                 R_Viewport_InitPerspectiveInfinite(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, customclipplane);
4558         else
4559                 R_Viewport_InitPerspective(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, r_refdef.farclip, customclipplane);
4560         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4561         R_SetViewport(&r_refdef.view.viewport);
4562 }
4563
4564 void R_EntityMatrix(const matrix4x4_t *matrix)
4565 {
4566         if (gl_modelmatrixchanged || memcmp(matrix, &gl_modelmatrix, sizeof(matrix4x4_t)))
4567         {
4568                 gl_modelmatrixchanged = false;
4569                 gl_modelmatrix = *matrix;
4570                 Matrix4x4_Concat(&gl_modelviewmatrix, &gl_viewmatrix, &gl_modelmatrix);
4571                 Matrix4x4_Concat(&gl_modelviewprojectionmatrix, &gl_projectionmatrix, &gl_modelviewmatrix);
4572                 Matrix4x4_ToArrayFloatGL(&gl_modelviewmatrix, gl_modelview16f);
4573                 Matrix4x4_ToArrayFloatGL(&gl_modelviewprojectionmatrix, gl_modelviewprojection16f);
4574                 CHECKGLERROR
4575                 switch(vid.renderpath)
4576                 {
4577                 case RENDERPATH_GL20:
4578                 case RENDERPATH_GLES2:
4579                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
4580                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
4581                         break;
4582                 }
4583         }
4584 }
4585
4586 void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2)
4587 {
4588         r_viewport_t viewport;
4589
4590         CHECKGLERROR
4591
4592         // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
4593         R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, vid.height - viewheight - viewy, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
4594         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4595         R_SetViewport(&viewport);
4596         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
4597         GL_Color(1, 1, 1, 1);
4598         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4599         GL_BlendFunc(GL_ONE, GL_ZERO);
4600         GL_ScissorTest(false);
4601         GL_DepthMask(false);
4602         GL_DepthRange(0, 1);
4603         GL_DepthTest(false);
4604         GL_DepthFunc(GL_LEQUAL);
4605         R_EntityMatrix(&identitymatrix);
4606         R_Mesh_ResetTextureState();
4607         GL_PolygonOffset(0, 0);
4608         R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
4609         switch(vid.renderpath)
4610         {
4611         case RENDERPATH_GL20:
4612         case RENDERPATH_GLES2:
4613                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4614                 break;
4615         }
4616         GL_CullFace(GL_NONE);
4617
4618         CHECKGLERROR
4619 }
4620
4621 void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4622 {
4623         R_ResetViewRendering2D_Common(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight, 1.0f, 1.0f);
4624 }
4625
4626 void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4627 {
4628         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
4629         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4630         GL_Color(1, 1, 1, 1);
4631         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4632         GL_BlendFunc(GL_ONE, GL_ZERO);
4633         GL_ScissorTest(true);
4634         GL_DepthMask(true);
4635         GL_DepthRange(0, 1);
4636         GL_DepthTest(true);
4637         GL_DepthFunc(GL_LEQUAL);
4638         R_EntityMatrix(&identitymatrix);
4639         R_Mesh_ResetTextureState();
4640         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4641         R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
4642         switch(vid.renderpath)
4643         {
4644         case RENDERPATH_GL20:
4645         case RENDERPATH_GLES2:
4646                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4647                 break;
4648         }
4649         GL_CullFace(r_refdef.view.cullface_back);
4650 }
4651
4652 /*
4653 ================
4654 R_RenderView_UpdateViewVectors
4655 ================
4656 */
4657 void R_RenderView_UpdateViewVectors(void)
4658 {
4659         // break apart the view matrix into vectors for various purposes
4660         // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
4661         // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc
4662         Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
4663         VectorNegate(r_refdef.view.left, r_refdef.view.right);
4664         // make an inverted copy of the view matrix for tracking sprites
4665         Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
4666 }
4667
4668 void R_RenderTarget_FreeUnused(qboolean force)
4669 {
4670         int i, j, end;
4671         end = Mem_ExpandableArray_IndexRange(&r_fb.rendertargets);
4672         for (i = 0; i < end; i++)
4673         {
4674                 r_rendertarget_t *r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4675                 // free resources for rendertargets that have not been used for a while
4676                 // (note: this check is run after the frame render, so any targets used
4677                 // this frame will not be affected even at low framerates)
4678                 if (r && (realtime - r->lastusetime > 0.2 || force))
4679                 {
4680                         if (r->fbo)
4681                                 R_Mesh_DestroyFramebufferObject(r->fbo);
4682                         for (j = 0; j < sizeof(r->colortexture) / sizeof(r->colortexture[0]); j++)
4683                                 if (r->colortexture[j])
4684                                         R_FreeTexture(r->colortexture[j]);
4685                         if (r->depthtexture)
4686                                 R_FreeTexture(r->depthtexture);
4687                         Mem_ExpandableArray_FreeRecord(&r_fb.rendertargets, r);
4688                 }
4689         }
4690 }
4691
4692 static void R_CalcTexCoordsForView(float x, float y, float w, float h, float tw, float th, float *texcoord2f)
4693 {
4694         float iw = 1.0f / tw, ih = 1.0f / th, x1, y1, x2, y2;
4695         x1 = x * iw;
4696         x2 = (x + w) * iw;
4697         y1 = (th - y) * ih;
4698         y2 = (th - y - h) * ih;
4699         texcoord2f[0] = x1;
4700         texcoord2f[2] = x2;
4701         texcoord2f[4] = x2;
4702         texcoord2f[6] = x1;
4703         texcoord2f[1] = y1;
4704         texcoord2f[3] = y1;
4705         texcoord2f[5] = y2;
4706         texcoord2f[7] = y2;
4707 }
4708
4709 r_rendertarget_t *R_RenderTarget_Get(int texturewidth, int textureheight, textype_t depthtextype, qboolean depthisrenderbuffer, textype_t colortextype0, textype_t colortextype1, textype_t colortextype2, textype_t colortextype3)
4710 {
4711         int i, j, end;
4712         r_rendertarget_t *r = NULL;
4713         char vabuf[256];
4714         // first try to reuse an existing slot if possible
4715         end = Mem_ExpandableArray_IndexRange(&r_fb.rendertargets);
4716         for (i = 0; i < end; i++)
4717         {
4718                 r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4719                 if (r && r->lastusetime != realtime && r->texturewidth == texturewidth && r->textureheight == textureheight && r->depthtextype == depthtextype && r->colortextype[0] == colortextype0 && r->colortextype[1] == colortextype1 && r->colortextype[2] == colortextype2 && r->colortextype[3] == colortextype3)
4720                         break;
4721         }
4722         if (i == end)
4723         {
4724                 // no unused exact match found, so we have to make one in the first unused slot
4725                 r = (r_rendertarget_t *)Mem_ExpandableArray_AllocRecord(&r_fb.rendertargets);
4726                 r->texturewidth = texturewidth;
4727                 r->textureheight = textureheight;
4728                 r->colortextype[0] = colortextype0;
4729                 r->colortextype[1] = colortextype1;
4730                 r->colortextype[2] = colortextype2;
4731                 r->colortextype[3] = colortextype3;
4732                 r->depthtextype = depthtextype;
4733                 r->depthisrenderbuffer = depthisrenderbuffer;
4734                 for (j = 0; j < 4; j++)
4735                         if (r->colortextype[j])
4736                                 r->colortexture[j] = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "rendertarget%i_%i_type%i", i, j, (int)r->colortextype[j]), r->texturewidth, r->textureheight, NULL, r->colortextype[j], TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
4737                 if (r->depthtextype)
4738                 {
4739                         if (r->depthisrenderbuffer)
4740                                 r->depthtexture = R_LoadTextureRenderBuffer(r_main_texturepool, va(vabuf, sizeof(vabuf), "renderbuffer%i_depth_type%i", i, (int)r->depthtextype), r->texturewidth, r->textureheight, r->depthtextype);
4741                         else
4742                                 r->depthtexture = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "rendertarget%i_depth_type%i", i, j, (int)r->depthtextype), r->texturewidth, r->textureheight, NULL, r->depthtextype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
4743                 }
4744                 r->fbo = R_Mesh_CreateFramebufferObject(r->depthtexture, r->colortexture[0], r->colortexture[1], r->colortexture[2], r->colortexture[3]);
4745         }
4746         r_refdef.stats[r_stat_rendertargets_used]++;
4747         r_refdef.stats[r_stat_rendertargets_pixels] += r->texturewidth * r->textureheight;
4748         r->lastusetime = realtime;
4749         R_CalcTexCoordsForView(0, 0, r->texturewidth, r->textureheight, r->texturewidth, r->textureheight, r->texcoord2f);
4750         return r;
4751 }
4752
4753 static void R_Water_StartFrame(void)
4754 {
4755         int waterwidth, waterheight;
4756
4757         if (vid.width > (int)vid.maxtexturesize_2d || vid.height > (int)vid.maxtexturesize_2d)
4758                 return;
4759
4760         // set waterwidth and waterheight to the water resolution that will be
4761         // used (often less than the screen resolution for faster rendering)
4762         waterwidth = (int)bound(1, r_refdef.view.width * r_water_resolutionmultiplier.value, r_refdef.view.width);
4763         waterheight = (int)bound(1, r_refdef.view.height * r_water_resolutionmultiplier.value, r_refdef.view.height);
4764         R_GetScaledViewSize(waterwidth, waterheight, &waterwidth, &waterheight);
4765
4766         if (!r_water.integer || r_showsurfaces.integer)
4767                 waterwidth = waterheight = 0;
4768
4769         // set up variables that will be used in shader setup
4770         r_fb.water.waterwidth = waterwidth;
4771         r_fb.water.waterheight = waterheight;
4772         r_fb.water.texturewidth = waterwidth;
4773         r_fb.water.textureheight = waterheight;
4774         r_fb.water.camerawidth = waterwidth;
4775         r_fb.water.cameraheight = waterheight;
4776         r_fb.water.screenscale[0] = 0.5f;
4777         r_fb.water.screenscale[1] = 0.5f;
4778         r_fb.water.screencenter[0] = 0.5f;
4779         r_fb.water.screencenter[1] = 0.5f;
4780         r_fb.water.enabled = waterwidth != 0;
4781
4782         r_fb.water.maxwaterplanes = MAX_WATERPLANES;
4783         r_fb.water.numwaterplanes = 0;
4784 }
4785
4786 void R_Water_AddWaterPlane(msurface_t *surface, int entno)
4787 {
4788         int planeindex, bestplaneindex, vertexindex;
4789         vec3_t mins, maxs, normal, center, v, n;
4790         vec_t planescore, bestplanescore;
4791         mplane_t plane;
4792         r_waterstate_waterplane_t *p;
4793         texture_t *t = R_GetCurrentTexture(surface->texture);
4794
4795         rsurface.texture = t;
4796         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, 1, ((const msurface_t **)&surface));
4797         // if the model has no normals, it's probably off-screen and they were not generated, so don't add it anyway
4798         if (!rsurface.batchnormal3f || rsurface.batchnumvertices < 1)
4799                 return;
4800         // average the vertex normals, find the surface bounds (after deformvertexes)
4801         Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f, v);
4802         Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f, n);
4803         VectorCopy(n, normal);
4804         VectorCopy(v, mins);
4805         VectorCopy(v, maxs);
4806         for (vertexindex = 1;vertexindex < rsurface.batchnumvertices;vertexindex++)
4807         {
4808                 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f + vertexindex*3, v);
4809                 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f + vertexindex*3, n);
4810                 VectorAdd(normal, n, normal);
4811                 mins[0] = min(mins[0], v[0]);
4812                 mins[1] = min(mins[1], v[1]);
4813                 mins[2] = min(mins[2], v[2]);
4814                 maxs[0] = max(maxs[0], v[0]);
4815                 maxs[1] = max(maxs[1], v[1]);
4816                 maxs[2] = max(maxs[2], v[2]);
4817         }
4818         VectorNormalize(normal);
4819         VectorMAM(0.5f, mins, 0.5f, maxs, center);
4820
4821         VectorCopy(normal, plane.normal);
4822         VectorNormalize(plane.normal);
4823         plane.dist = DotProduct(center, plane.normal);
4824         PlaneClassify(&plane);
4825         if (PlaneDiff(r_refdef.view.origin, &plane) < 0)
4826         {
4827                 // skip backfaces (except if nocullface is set)
4828 //              if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE))
4829 //                      return;
4830                 VectorNegate(plane.normal, plane.normal);
4831                 plane.dist *= -1;
4832                 PlaneClassify(&plane);
4833         }
4834
4835
4836         // find a matching plane if there is one
4837         bestplaneindex = -1;
4838         bestplanescore = 1048576.0f;
4839         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4840         {
4841                 if(p->camera_entity == t->camera_entity)
4842                 {
4843                         planescore = 1.0f - DotProduct(plane.normal, p->plane.normal) + fabs(plane.dist - p->plane.dist) * 0.001f;
4844                         if (bestplaneindex < 0 || bestplanescore > planescore)
4845                         {
4846                                 bestplaneindex = planeindex;
4847                                 bestplanescore = planescore;
4848                         }
4849                 }
4850         }
4851         planeindex = bestplaneindex;
4852
4853         // if this surface does not fit any known plane rendered this frame, add one
4854         if (planeindex < 0 || bestplanescore > 0.001f)
4855         {
4856                 if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
4857                 {
4858                         // store the new plane
4859                         planeindex = r_fb.water.numwaterplanes++;
4860                         p = r_fb.water.waterplanes + planeindex;
4861                         p->plane = plane;
4862                         // clear materialflags and pvs
4863                         p->materialflags = 0;
4864                         p->pvsvalid = false;
4865                         p->camera_entity = t->camera_entity;
4866                         VectorCopy(mins, p->mins);
4867                         VectorCopy(maxs, p->maxs);
4868                 }
4869                 else
4870                 {
4871                         // We're totally screwed.
4872                         return;
4873                 }
4874         }
4875         else
4876         {
4877                 // merge mins/maxs when we're adding this surface to the plane
4878                 p = r_fb.water.waterplanes + planeindex;
4879                 p->mins[0] = min(p->mins[0], mins[0]);
4880                 p->mins[1] = min(p->mins[1], mins[1]);
4881                 p->mins[2] = min(p->mins[2], mins[2]);
4882                 p->maxs[0] = max(p->maxs[0], maxs[0]);
4883                 p->maxs[1] = max(p->maxs[1], maxs[1]);
4884                 p->maxs[2] = max(p->maxs[2], maxs[2]);
4885         }
4886         // merge this surface's materialflags into the waterplane
4887         p->materialflags |= t->currentmaterialflags;
4888         if(!(p->materialflags & MATERIALFLAG_CAMERA))
4889         {
4890                 // merge this surface's PVS into the waterplane
4891                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
4892                  && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
4893                 {
4894                         r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
4895                         p->pvsvalid = true;
4896                 }
4897         }
4898 }
4899
4900 extern cvar_t r_drawparticles;
4901 extern cvar_t r_drawdecals;
4902
4903 static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int viewx, int viewy, int viewwidth, int viewheight)
4904 {
4905         int myscissor[4];
4906         r_refdef_view_t originalview;
4907         r_refdef_view_t myview;
4908         int planeindex, qualityreduction = 0, old_r_dynamic = 0, old_r_shadows = 0, old_r_worldrtlight = 0, old_r_dlight = 0, old_r_particles = 0, old_r_decals = 0;
4909         r_waterstate_waterplane_t *p;
4910         vec3_t visorigin;
4911         r_rendertarget_t *rt;
4912
4913         originalview = r_refdef.view;
4914
4915         // lowquality hack, temporarily shut down some cvars and restore afterwards
4916         qualityreduction = r_water_lowquality.integer;
4917         if (qualityreduction > 0)
4918         {
4919                 if (qualityreduction >= 1)
4920                 {
4921                         old_r_shadows = r_shadows.integer;
4922                         old_r_worldrtlight = r_shadow_realtime_world.integer;
4923                         old_r_dlight = r_shadow_realtime_dlight.integer;
4924                         Cvar_SetValueQuick(&r_shadows, 0);
4925                         Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
4926                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, 0);
4927                 }
4928                 if (qualityreduction >= 2)
4929                 {
4930                         old_r_dynamic = r_dynamic.integer;
4931                         old_r_particles = r_drawparticles.integer;
4932                         old_r_decals = r_drawdecals.integer;
4933                         Cvar_SetValueQuick(&r_dynamic, 0);
4934                         Cvar_SetValueQuick(&r_drawparticles, 0);
4935                         Cvar_SetValueQuick(&r_drawdecals, 0);
4936                 }
4937         }
4938
4939         for (planeindex = 0, p = r_fb.water.waterplanes; planeindex < r_fb.water.numwaterplanes; planeindex++, p++)
4940         {
4941                 p->rt_reflection = NULL;
4942                 p->rt_refraction = NULL;
4943                 p->rt_camera = NULL;
4944         }
4945
4946         // render views
4947         r_refdef.view = originalview;
4948         r_refdef.view.showdebug = false;
4949         r_refdef.view.width = r_fb.water.waterwidth;
4950         r_refdef.view.height = r_fb.water.waterheight;
4951         r_refdef.view.useclipplane = true;
4952         myview = r_refdef.view;
4953         r_fb.water.renderingscene = true;
4954         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4955         {
4956                 if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
4957                         continue;
4958
4959                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
4960                 {
4961                         rt = R_RenderTarget_Get(r_fb.water.waterwidth, r_fb.water.waterheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, r_fb.rt_screen->colortextype[0], TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
4962                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4963                                 goto error;
4964                         r_refdef.view = myview;
4965                         Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
4966                         Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
4967                         if(r_water_scissormode.integer)
4968                         {
4969                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4970                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4971                                 {
4972                                         p->rt_reflection = NULL;
4973                                         p->rt_refraction = NULL;
4974                                         p->rt_camera = NULL;
4975                                         continue;
4976                                 }
4977                         }
4978
4979                         r_refdef.view.clipplane = p->plane;
4980                         // reflected view origin may be in solid, so don't cull with it
4981                         r_refdef.view.usevieworiginculling = false;
4982                         // reverse the cullface settings for this render
4983                         r_refdef.view.cullface_front = GL_FRONT;
4984                         r_refdef.view.cullface_back = GL_BACK;
4985                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4986                         {
4987                                 r_refdef.view.usecustompvs = true;
4988                                 if (p->pvsvalid)
4989                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4990                                 else
4991                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4992                         }
4993
4994                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 2) && !chase_active.integer);
4995                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4996                         GL_ScissorTest(false);
4997                         R_ClearScreen(r_refdef.fogenabled);
4998                         GL_ScissorTest(true);
4999                         if(r_water_scissormode.integer & 2)
5000                                 R_View_UpdateWithScissor(myscissor);
5001                         else
5002                                 R_View_Update();
5003                         R_AnimCache_CacheVisibleEntities();
5004                         if(r_water_scissormode.integer & 1)
5005                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
5006                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5007
5008                         r_fb.water.hideplayer = false;
5009                         p->rt_reflection = rt;
5010                 }
5011
5012                 // render the normal view scene and copy into texture
5013                 // (except that a clipping plane should be used to hide everything on one side of the water, and the viewer's weapon model should be omitted)
5014                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
5015                 {
5016                         rt = R_RenderTarget_Get(r_fb.water.waterwidth, r_fb.water.waterheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, r_fb.rt_screen->colortextype[0], TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5017                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
5018                                 goto error;
5019                         r_refdef.view = myview;
5020                         if(r_water_scissormode.integer)
5021                         {
5022                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
5023                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
5024                                 {
5025                                         p->rt_reflection = NULL;
5026                                         p->rt_refraction = NULL;
5027                                         p->rt_camera = NULL;
5028                                         continue;
5029                                 }
5030                         }
5031
5032                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
5033
5034                         r_refdef.view.clipplane = p->plane;
5035                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5036                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5037
5038                         if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity)
5039                         {
5040                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5041                                 r_fb.water.hideplayer = false; // we don't want to hide the player model from these ones
5042                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5043                                 R_RenderView_UpdateViewVectors();
5044                                 if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5045                                 {
5046                                         r_refdef.view.usecustompvs = true;
5047                                         r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, visorigin, 2, r_refdef.viewcache.world_pvsbits, (r_refdef.viewcache.world_numclusters+7)>>3, false);
5048                                 }
5049                         }
5050
5051                         PlaneClassify(&r_refdef.view.clipplane);
5052
5053                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5054                         GL_ScissorTest(false);
5055                         R_ClearScreen(r_refdef.fogenabled);
5056                         GL_ScissorTest(true);
5057                         if(r_water_scissormode.integer & 2)
5058                                 R_View_UpdateWithScissor(myscissor);
5059                         else
5060                                 R_View_Update();
5061                         R_AnimCache_CacheVisibleEntities();
5062                         if(r_water_scissormode.integer & 1)
5063                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
5064                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5065
5066                         r_fb.water.hideplayer = false;
5067                         p->rt_refraction = rt;
5068                 }
5069                 else if (p->materialflags & MATERIALFLAG_CAMERA)
5070                 {
5071                         rt = R_RenderTarget_Get(r_fb.water.waterwidth, r_fb.water.waterheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, r_fb.rt_screen->colortextype[0], TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5072                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
5073                                 goto error;
5074                         r_refdef.view = myview;
5075
5076                         r_refdef.view.clipplane = p->plane;
5077                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5078                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5079
5080                         r_refdef.view.width = r_fb.water.camerawidth;
5081                         r_refdef.view.height = r_fb.water.cameraheight;
5082                         r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0);
5083                         r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0);
5084                         r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView
5085                         r_refdef.view.ortho_y = 90; // abused as angle by VM_CL_R_SetView
5086
5087                         if(p->camera_entity)
5088                         {
5089                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5090                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5091                         }
5092
5093                         // note: all of the view is used for displaying... so
5094                         // there is no use in scissoring
5095
5096                         // reverse the cullface settings for this render
5097                         r_refdef.view.cullface_front = GL_FRONT;
5098                         r_refdef.view.cullface_back = GL_BACK;
5099                         // also reverse the view matrix
5100                         Matrix4x4_ConcatScale3(&r_refdef.view.matrix, 1, 1, -1); // this serves to invert texcoords in the result, as the copied texture is mapped the wrong way round
5101                         R_RenderView_UpdateViewVectors();
5102                         if(p->camera_entity && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5103                         {
5104                                 r_refdef.view.usecustompvs = true;
5105                                 r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, visorigin, 2, r_refdef.viewcache.world_pvsbits, (r_refdef.viewcache.world_numclusters+7)>>3, false);
5106                         }
5107                         
5108                         // camera needs no clipplane
5109                         r_refdef.view.useclipplane = false;
5110                         // TODO: is the camera origin always valid?  if so we don't need to clear this
5111                         r_refdef.view.usevieworiginculling = false;
5112
5113                         PlaneClassify(&r_refdef.view.clipplane);
5114
5115                         r_fb.water.hideplayer = false;
5116
5117                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5118                         GL_ScissorTest(false);
5119                         R_ClearScreen(r_refdef.fogenabled);
5120                         GL_ScissorTest(true);
5121                         R_View_Update();
5122                         R_AnimCache_CacheVisibleEntities();
5123                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5124
5125                         r_fb.water.hideplayer = false;
5126                         p->rt_camera = rt;
5127                 }
5128
5129         }
5130         r_fb.water.renderingscene = false;
5131         r_refdef.view = originalview;
5132         R_ResetViewRendering3D(fbo, depthtexture, colortexture, viewx, viewy, viewwidth, viewheight);
5133         R_View_Update();
5134         R_AnimCache_CacheVisibleEntities();
5135         goto finish;
5136 error:
5137         r_refdef.view = originalview;
5138         r_fb.water.renderingscene = false;
5139         Cvar_SetValueQuick(&r_water, 0);
5140         Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed!  Turned off r_water.\n");
5141 finish:
5142         // lowquality hack, restore cvars
5143         if (qualityreduction > 0)
5144         {
5145                 if (qualityreduction >= 1)
5146                 {
5147                         Cvar_SetValueQuick(&r_shadows, old_r_shadows);
5148                         Cvar_SetValueQuick(&r_shadow_realtime_world, old_r_worldrtlight);
5149                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, old_r_dlight);
5150                 }
5151                 if (qualityreduction >= 2)
5152                 {
5153                         Cvar_SetValueQuick(&r_dynamic, old_r_dynamic);
5154                         Cvar_SetValueQuick(&r_drawparticles, old_r_particles);
5155                         Cvar_SetValueQuick(&r_drawdecals, old_r_decals);
5156                 }
5157         }
5158 }
5159
5160 static void R_Bloom_StartFrame(void)
5161 {
5162         int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight;
5163         int viewwidth, viewheight;
5164         textype_t textype = TEXTYPE_COLORBUFFER;
5165
5166         // clear the pointers to rendertargets from last frame as they're stale
5167         r_fb.rt_screen = NULL;
5168         r_fb.rt_bloom = NULL;
5169
5170         switch (vid.renderpath)
5171         {
5172         case RENDERPATH_GL20:
5173                 r_fb.usedepthtextures = r_usedepthtextures.integer != 0;
5174                 if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
5175                 if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
5176                 // for simplicity, bloom requires FBO render to texture, which basically all video drivers support now
5177                 if (!vid.support.ext_framebuffer_object)
5178                         return;
5179                 break;
5180         case RENDERPATH_GLES2:
5181                 r_fb.usedepthtextures = false;
5182                 break;
5183         }
5184
5185         if (r_viewscale_fpsscaling.integer)
5186         {
5187                 double actualframetime;
5188                 double targetframetime;
5189                 double adjust;
5190                 actualframetime = r_refdef.lastdrawscreentime;
5191                 targetframetime = (1.0 / r_viewscale_fpsscaling_target.value);
5192                 adjust = (targetframetime - actualframetime) * r_viewscale_fpsscaling_multiply.value;
5193                 adjust = bound(-r_viewscale_fpsscaling_stepmax.value, adjust, r_viewscale_fpsscaling_stepmax.value);
5194                 if (r_viewscale_fpsscaling_stepsize.value > 0)
5195                         adjust = (int)(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5196                 viewscalefpsadjusted += adjust;
5197                 viewscalefpsadjusted = bound(r_viewscale_fpsscaling_min.value, viewscalefpsadjusted, 1.0f);
5198         }
5199         else
5200                 viewscalefpsadjusted = 1.0f;
5201
5202         R_GetScaledViewSize(r_refdef.view.width, r_refdef.view.height, &viewwidth, &viewheight);
5203
5204         // set bloomwidth and bloomheight to the bloom resolution that will be
5205         // used (often less than the screen resolution for faster rendering)
5206         r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, vid.width);
5207         r_fb.bloomheight = r_fb.bloomwidth * vid.height / vid.width;
5208         r_fb.bloomheight = bound(1, r_fb.bloomheight, vid.height);
5209         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d);
5210         r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d);
5211
5212         // calculate desired texture sizes
5213         screentexturewidth = viewwidth;
5214         screentextureheight = viewheight;
5215         bloomtexturewidth = r_fb.bloomwidth;
5216         bloomtextureheight = r_fb.bloomheight;
5217
5218         if ((r_bloom.integer || (!R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0))) && ((r_bloom_resolution.integer < 4 || r_bloom_blur.value < 1 || r_bloom_blur.value >= 512) || r_refdef.view.width > (int)vid.maxtexturesize_2d || r_refdef.view.height > (int)vid.maxtexturesize_2d))
5219         {
5220                 Cvar_SetValueQuick(&r_bloom, 0);
5221                 Cvar_SetValueQuick(&r_motionblur, 0);
5222                 Cvar_SetValueQuick(&r_damageblur, 0);
5223         }
5224
5225         // allocate motionblur ghost texture if needed - this is the only persistent texture and is only useful on the main view
5226         if (r_refdef.view.ismain && (r_fb.screentexturewidth != screentexturewidth || r_fb.screentextureheight != screentextureheight || r_fb.textype != textype))
5227         {
5228                 if (r_fb.ghosttexture)
5229                         R_FreeTexture(r_fb.ghosttexture);
5230                 r_fb.ghosttexture = NULL;
5231
5232                 r_fb.screentexturewidth = screentexturewidth;
5233                 r_fb.screentextureheight = screentextureheight;
5234                 r_fb.textype = textype;
5235
5236                 if (r_fb.screentexturewidth && r_fb.screentextureheight)
5237                 {
5238                         if (r_motionblur.value > 0 || r_damageblur.value > 0)
5239                                 r_fb.ghosttexture = R_LoadTexture2D(r_main_texturepool, "framebuffermotionblur", r_fb.screentexturewidth, r_fb.screentextureheight, NULL, r_fb.textype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
5240                         r_fb.ghosttexture_valid = false;
5241                 }
5242         }
5243
5244         if (r_bloom.integer)
5245         {
5246                 // bloom texture is a different resolution
5247                 r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, r_refdef.view.width);
5248                 r_fb.bloomheight = r_fb.bloomwidth * r_refdef.view.height / r_refdef.view.width;
5249                 r_fb.bloomheight = bound(1, r_fb.bloomheight, r_refdef.view.height);
5250         }
5251         else
5252                 r_fb.bloomwidth = r_fb.bloomheight = 0;
5253
5254         r_fb.rt_screen = R_RenderTarget_Get(screentexturewidth, screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5255
5256         r_refdef.view.clear = true;
5257 }
5258
5259 static void R_Bloom_MakeTexture(void)
5260 {
5261         int x, range, dir;
5262         float xoffset, yoffset, r, brighten;
5263         float colorscale = r_bloom_colorscale.value;
5264         r_viewport_t bloomviewport;
5265         r_rendertarget_t *prev, *cur;
5266         textype_t textype = r_fb.rt_screen->colortextype[0];
5267
5268         r_refdef.stats[r_stat_bloom]++;
5269
5270         R_Viewport_InitOrtho(&bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
5271
5272         // scale down screen texture to the bloom texture size
5273         CHECKGLERROR
5274         prev = r_fb.rt_screen;
5275         cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5276         R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5277         R_SetViewport(&bloomviewport);
5278         GL_CullFace(GL_NONE);
5279         GL_DepthTest(false);
5280         GL_BlendFunc(GL_ONE, GL_ZERO);
5281         GL_Color(colorscale, colorscale, colorscale, 1);
5282         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5283         // TODO: do boxfilter scale-down in shader?
5284         R_SetupShader_Generic(prev->colortexture[0], NULL, GL_MODULATE, 1, false, true, true);
5285         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5286         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5287         // we now have a properly scaled bloom image
5288
5289         // multiply bloom image by itself as many times as desired to darken it
5290         // TODO: if people actually use this it could be done more quickly in the previous shader pass
5291         for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
5292         {
5293                 prev = cur;
5294                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5295                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5296                 x *= 2;
5297                 r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1
5298                 if(x <= 2)
5299                         GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 128);
5300                 GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
5301                 GL_Color(1,1,1,1); // no fix factor supported here
5302                 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5303                 R_SetupShader_Generic(prev->colortexture[0], NULL, GL_MODULATE, 1, false, true, false);
5304                 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5305                 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5306         }
5307
5308         range = r_bloom_blur.integer * r_fb.bloomwidth / 320;
5309         brighten = r_bloom_brighten.value;
5310         brighten = sqrt(brighten);
5311         if(range >= 1)
5312                 brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
5313
5314         for (dir = 0;dir < 2;dir++)
5315         {
5316                 prev = cur;
5317                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5318                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5319                 // blend on at multiple vertical offsets to achieve a vertical blur
5320                 // TODO: do offset blends using GLSL
5321                 // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
5322                 GL_BlendFunc(GL_ONE, GL_ZERO);
5323                 R_SetupShader_Generic(prev->colortexture[0], NULL, GL_MODULATE, 1, false, true, false);
5324                 for (x = -range;x <= range;x++)
5325                 {
5326                         if (!dir){xoffset = 0;yoffset = x;}
5327                         else {xoffset = x;yoffset = 0;}
5328                         xoffset /= (float)prev->texturewidth;
5329                         yoffset /= (float)prev->textureheight;
5330                         // compute a texcoord array with the specified x and y offset
5331                         r_fb.offsettexcoord2f[0] = xoffset+prev->texcoord2f[0];
5332                         r_fb.offsettexcoord2f[1] = yoffset+prev->texcoord2f[1];
5333                         r_fb.offsettexcoord2f[2] = xoffset+prev->texcoord2f[2];
5334                         r_fb.offsettexcoord2f[3] = yoffset+prev->texcoord2f[3];
5335                         r_fb.offsettexcoord2f[4] = xoffset+prev->texcoord2f[4];
5336                         r_fb.offsettexcoord2f[5] = yoffset+prev->texcoord2f[5];
5337                         r_fb.offsettexcoord2f[6] = xoffset+prev->texcoord2f[6];
5338                         r_fb.offsettexcoord2f[7] = yoffset+prev->texcoord2f[7];
5339                         // this r value looks like a 'dot' particle, fading sharply to
5340                         // black at the edges
5341                         // (probably not realistic but looks good enough)
5342                         //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
5343                         //r = brighten/(range*2+1);
5344                         r = brighten / (range * 2 + 1);
5345                         if(range >= 1)
5346                                 r *= (1 - x*x/(float)((range+1)*(range+1)));
5347                         if (r <= 0)
5348                                 continue;
5349                         GL_Color(r, r, r, 1);
5350                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f);
5351                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5352                         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5353                         GL_BlendFunc(GL_ONE, GL_ONE);
5354                 }
5355         }
5356
5357         // now we have the bloom image, so keep track of it
5358         r_fb.rt_bloom = cur;
5359 }
5360
5361 static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5362 {
5363         dpuint64 permutation;
5364         float uservecs[4][4];
5365         rtexture_t *viewtexture;
5366         rtexture_t *bloomtexture;
5367
5368         R_EntityMatrix(&identitymatrix);
5369
5370         if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
5371         {
5372                 // declare variables
5373                 float blur_factor, blur_mouseaccel, blur_velocity;
5374                 static float blur_average; 
5375                 static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
5376
5377                 // set a goal for the factoring
5378                 blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value) 
5379                         / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
5380                 blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value) 
5381                         / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
5382                 blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value) 
5383                         + (blur_mouseaccel * r_motionblur_mousefactor.value));
5384
5385                 // from the goal, pick an averaged value between goal and last value
5386                 cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
5387                 blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
5388
5389                 // enforce minimum amount of blur 
5390                 blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
5391
5392                 //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
5393
5394                 // calculate values into a standard alpha
5395                 cl.motionbluralpha = 1 - exp(-
5396                                 (
5397                                         (r_motionblur.value * blur_factor / 80)
5398                                         +
5399                                         (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
5400                                 )
5401                                 /
5402                                 max(0.0001, cl.time - cl.oldtime) // fps independent
5403                                 );
5404
5405                 // randomization for the blur value to combat persistent ghosting
5406                 cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
5407                 cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
5408
5409                 // apply the blur
5410                 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5411                 if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
5412                 {
5413                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5414                         GL_Color(1, 1, 1, cl.motionbluralpha);
5415                         R_CalcTexCoordsForView(0, 0, viewwidth, viewheight, viewwidth, viewheight, r_fb.ghosttexcoord2f);
5416                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.ghosttexcoord2f);
5417                         R_SetupShader_Generic(r_fb.ghosttexture, NULL, GL_MODULATE, 1, false, true, true);
5418                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5419                         r_refdef.stats[r_stat_bloom_drawpixels] += viewwidth * viewheight;
5420                 }
5421
5422                 // updates old view angles for next pass
5423                 VectorCopy(cl.viewangles, blur_oldangles);
5424
5425                 // copy view into the ghost texture
5426                 R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, viewx, viewy, viewwidth, viewheight);
5427                 r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight;
5428                 r_fb.ghosttexture_valid = true;
5429         }
5430
5431         if (r_fb.bloomwidth)
5432         {
5433                 // make the bloom texture
5434                 R_Bloom_MakeTexture();
5435         }
5436
5437 #if _MSC_VER >= 1400
5438 #define sscanf sscanf_s
5439 #endif
5440         memset(uservecs, 0, sizeof(uservecs));
5441         if (r_glsl_postprocess_uservec1_enable.integer)
5442                 sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
5443         if (r_glsl_postprocess_uservec2_enable.integer)
5444                 sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
5445         if (r_glsl_postprocess_uservec3_enable.integer)
5446                 sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
5447         if (r_glsl_postprocess_uservec4_enable.integer)
5448                 sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
5449
5450         // render to the screen fbo
5451         R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5452         GL_Color(1, 1, 1, 1);
5453         GL_BlendFunc(GL_ONE, GL_ZERO);
5454
5455         viewtexture = r_fb.rt_screen->colortexture[0];
5456         bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL;
5457
5458         if (r_rendertarget_debug.integer >= 0)
5459         {
5460                 r_rendertarget_t *rt = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, r_rendertarget_debug.integer);
5461                 if (rt && rt->colortexture[0])
5462                 {
5463                         viewtexture = rt->colortexture[0];
5464                         bloomtexture = NULL;
5465                 }
5466         }
5467
5468         R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.rt_screen->texcoord2f, bloomtexture ? r_fb.rt_bloom->texcoord2f : NULL);
5469         switch(vid.renderpath)
5470         {
5471         case RENDERPATH_GL20:
5472         case RENDERPATH_GLES2:
5473                 permutation =
5474                         (r_fb.bloomwidth ? SHADERPERMUTATION_BLOOM : 0)
5475                         | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
5476                         | (!vid_gammatables_trivial ? SHADERPERMUTATION_GAMMARAMPS : 0)
5477                         | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
5478                         | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
5479                 R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation);
5480                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First     , viewtexture);
5481                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second    , bloomtexture);
5482                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps       );
5483                 if (r_glsl_permutation->loc_ViewTintColor           >= 0) qglUniform4f(r_glsl_permutation->loc_ViewTintColor     , r_refdef.viewblend[0], r_refdef.viewblend[1], r_refdef.viewblend[2], r_refdef.viewblend[3]);
5484                 if (r_glsl_permutation->loc_PixelSize               >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize         , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
5485                 if (r_glsl_permutation->loc_UserVec1                >= 0) qglUniform4f(r_glsl_permutation->loc_UserVec1          , uservecs[0][0], uservecs[0][1], uservecs[0][2], uservecs[0][3]);
5486                 if (r_glsl_permutation->loc_UserVec2                >= 0) qglUniform4f(r_glsl_permutation->loc_UserVec2          , uservecs[1][0], uservecs[1][1], uservecs[1][2], uservecs[1][3]);
5487                 if (r_glsl_permutation->loc_UserVec3                >= 0) qglUniform4f(r_glsl_permutation->loc_UserVec3          , uservecs[2][0], uservecs[2][1], uservecs[2][2], uservecs[2][3]);
5488                 if (r_glsl_permutation->loc_UserVec4                >= 0) qglUniform4f(r_glsl_permutation->loc_UserVec4          , uservecs[3][0], uservecs[3][1], uservecs[3][2], uservecs[3][3]);
5489                 if (r_glsl_permutation->loc_Saturation              >= 0) qglUniform1f(r_glsl_permutation->loc_Saturation        , r_glsl_saturation.value);
5490                 if (r_glsl_permutation->loc_PixelToScreenTexCoord   >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
5491                 if (r_glsl_permutation->loc_BloomColorSubtract      >= 0) qglUniform4f(r_glsl_permutation->loc_BloomColorSubtract   , r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, r_bloom_colorsubtract.value, 0.0f);
5492                 break;
5493         }
5494         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5495         r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height;
5496 }
5497
5498 matrix4x4_t r_waterscrollmatrix;
5499
5500 void R_UpdateFog(void)
5501 {
5502         // Nehahra fog
5503         if (gamemode == GAME_NEHAHRA)
5504         {
5505                 if (gl_fogenable.integer)
5506                 {
5507                         r_refdef.oldgl_fogenable = true;
5508                         r_refdef.fog_density = gl_fogdensity.value;
5509                         r_refdef.fog_red = gl_fogred.value;
5510                         r_refdef.fog_green = gl_foggreen.value;
5511                         r_refdef.fog_blue = gl_fogblue.value;
5512                         r_refdef.fog_alpha = 1;
5513                         r_refdef.fog_start = 0;
5514                         r_refdef.fog_end = gl_skyclip.value;
5515                         r_refdef.fog_height = 1<<30;
5516                         r_refdef.fog_fadedepth = 128;
5517                 }
5518                 else if (r_refdef.oldgl_fogenable)
5519                 {
5520                         r_refdef.oldgl_fogenable = false;
5521                         r_refdef.fog_density = 0;
5522                         r_refdef.fog_red = 0;
5523                         r_refdef.fog_green = 0;
5524                         r_refdef.fog_blue = 0;
5525                         r_refdef.fog_alpha = 0;
5526                         r_refdef.fog_start = 0;
5527                         r_refdef.fog_end = 0;
5528                         r_refdef.fog_height = 1<<30;
5529                         r_refdef.fog_fadedepth = 128;
5530                 }
5531         }
5532
5533         // fog parms
5534         r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1);
5535         r_refdef.fog_start = max(0, r_refdef.fog_start);
5536         r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end);
5537
5538         if (r_refdef.fog_density && r_drawfog.integer)
5539         {
5540                 r_refdef.fogenabled = true;
5541                 // this is the point where the fog reaches 0.9986 alpha, which we
5542                 // consider a good enough cutoff point for the texture
5543                 // (0.9986 * 256 == 255.6)
5544                 if (r_fog_exp2.integer)
5545                         r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start;
5546                 else
5547                         r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start;
5548                 r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end);
5549                 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
5550                 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
5551                 if (strcmp(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename))
5552                         R_BuildFogHeightTexture();
5553                 // fog color was already set
5554                 // update the fog texture
5555                 if (r_refdef.fogmasktable_start != r_refdef.fog_start || r_refdef.fogmasktable_alpha != r_refdef.fog_alpha || r_refdef.fogmasktable_density != r_refdef.fog_density || r_refdef.fogmasktable_range != r_refdef.fogrange)
5556                         R_BuildFogTexture();
5557                 r_refdef.fog_height_texcoordscale = 1.0f / max(0.125f, r_refdef.fog_fadedepth);
5558                 r_refdef.fog_height_tablescale = r_refdef.fog_height_tablesize * r_refdef.fog_height_texcoordscale;
5559         }
5560         else
5561                 r_refdef.fogenabled = false;
5562
5563         // fog color
5564         if (r_refdef.fog_density)
5565         {
5566                 r_refdef.fogcolor[0] = r_refdef.fog_red;
5567                 r_refdef.fogcolor[1] = r_refdef.fog_green;
5568                 r_refdef.fogcolor[2] = r_refdef.fog_blue;
5569
5570                 Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height);
5571                 r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3];
5572                 r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0;
5573                 r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth);
5574
5575                 {
5576                         vec3_t fogvec;
5577                         VectorCopy(r_refdef.fogcolor, fogvec);
5578                         //   color.rgb *= ContrastBoost * SceneBrightness;
5579                         VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
5580                         r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
5581                         r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f);
5582                         r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f);
5583                 }
5584         }
5585 }
5586
5587 void R_UpdateVariables(void)
5588 {
5589         R_Textures_Frame();
5590
5591         r_refdef.scene.ambientintensity = r_ambient.value * (1.0f / 64.0f);
5592
5593         r_refdef.farclip = r_farclip_base.value;
5594         if (r_refdef.scene.worldmodel)
5595                 r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2;
5596         r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
5597
5598         if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
5599                 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
5600         r_refdef.polygonfactor = 0;
5601         r_refdef.polygonoffset = 0;
5602         r_refdef.shadowpolygonfactor = r_refdef.polygonfactor + r_shadow_polygonfactor.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
5603         r_refdef.shadowpolygonoffset = r_refdef.polygonoffset + r_shadow_polygonoffset.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
5604
5605         r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
5606         r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil;
5607         r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer;
5608         r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil;
5609         r_refdef.scene.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
5610         if (FAKELIGHT_ENABLED)
5611         {
5612                 r_refdef.scene.lightmapintensity *= r_fakelight_intensity.value;
5613         }
5614         else if (r_refdef.scene.worldmodel)
5615         {
5616                 r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
5617         }
5618         if (r_showsurfaces.integer)
5619         {
5620                 r_refdef.scene.rtworld = false;
5621                 r_refdef.scene.rtworldshadows = false;
5622                 r_refdef.scene.rtdlight = false;
5623                 r_refdef.scene.rtdlightshadows = false;
5624                 r_refdef.scene.lightmapintensity = 0;
5625         }
5626
5627         r_gpuskeletal = false;
5628         switch(vid.renderpath)
5629         {
5630         case RENDERPATH_GL20:
5631                 r_gpuskeletal = vid.support.arb_uniform_buffer_object && r_glsl_skeletal.integer && !r_showsurfaces.integer; // FIXME add r_showsurfaces support to GLSL skeletal!
5632         case RENDERPATH_GLES2:
5633                 if(!vid_gammatables_trivial)
5634                 {
5635                         if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
5636                         {
5637                                 // build GLSL gamma texture
5638 #define RAMPWIDTH 256
5639                                 unsigned short ramp[RAMPWIDTH * 3];
5640                                 unsigned char rampbgr[RAMPWIDTH][4];
5641                                 int i;
5642
5643                                 r_texture_gammaramps_serial = vid_gammatables_serial;
5644
5645                                 VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
5646                                 for(i = 0; i < RAMPWIDTH; ++i)
5647                                 {
5648                                         rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5649                                         rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5650                                         rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
5651                                         rampbgr[i][3] = 0;
5652                                 }
5653                                 if (r_texture_gammaramps)
5654                                 {
5655                                         R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1);
5656                                 }
5657                                 else
5658                                 {
5659                                         r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
5660                                 }
5661                         }
5662                 }
5663                 else
5664                 {
5665                         // remove GLSL gamma texture
5666                 }
5667                 break;
5668         }
5669 }
5670
5671 static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT;
5672 static r_refdef_scene_t r_scenes_store[ RST_COUNT ];
5673 /*
5674 ================
5675 R_SelectScene
5676 ================
5677 */
5678 void R_SelectScene( r_refdef_scene_type_t scenetype ) {
5679         if( scenetype != r_currentscenetype ) {
5680                 // store the old scenetype
5681                 r_scenes_store[ r_currentscenetype ] = r_refdef.scene;
5682                 r_currentscenetype = scenetype;
5683                 // move in the new scene
5684                 r_refdef.scene = r_scenes_store[ r_currentscenetype ];
5685         }
5686 }
5687
5688 /*
5689 ================
5690 R_GetScenePointer
5691 ================
5692 */
5693 r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype )
5694 {
5695         // of course, we could also add a qboolean that provides a lock state and a ReleaseScenePointer function..
5696         if( scenetype == r_currentscenetype ) {
5697                 return &r_refdef.scene;
5698         } else {
5699                 return &r_scenes_store[ scenetype ];
5700         }
5701 }
5702
5703 static int R_SortEntities_Compare(const void *ap, const void *bp)
5704 {
5705         const entity_render_t *a = *(const entity_render_t **)ap;
5706         const entity_render_t *b = *(const entity_render_t **)bp;
5707
5708         // 1. compare model
5709         if(a->model < b->model)
5710                 return -1;
5711         if(a->model > b->model)
5712                 return +1;
5713
5714         // 2. compare skin
5715         // TODO possibly calculate the REAL skinnum here first using
5716         // skinscenes?
5717         if(a->skinnum < b->skinnum)
5718                 return -1;
5719         if(a->skinnum > b->skinnum)
5720                 return +1;
5721
5722         // everything we compared is equal
5723         return 0;
5724 }
5725 static void R_SortEntities(void)
5726 {
5727         // below or equal 2 ents, sorting never gains anything
5728         if(r_refdef.scene.numentities <= 2)
5729                 return;
5730         // sort
5731         qsort(r_refdef.scene.entities, r_refdef.scene.numentities, sizeof(*r_refdef.scene.entities), R_SortEntities_Compare);
5732 }
5733
5734 /*
5735 ================
5736 R_RenderView
5737 ================
5738 */
5739 extern cvar_t r_shadow_bouncegrid;
5740 extern cvar_t v_isometric;
5741 extern void V_MakeViewIsometric(void);
5742 void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5743 {
5744         matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
5745         int viewfbo = 0;
5746         rtexture_t *viewdepthtexture = NULL;
5747         rtexture_t *viewcolortexture = NULL;
5748         int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
5749
5750         // finish any 2D rendering that was queued
5751         DrawQ_Finish();
5752
5753         if (r_timereport_active)
5754                 R_TimeReport("start");
5755         r_textureframe++; // used only by R_GetCurrentTexture
5756         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5757
5758         if(R_CompileShader_CheckStaticParms())
5759                 R_GLSL_Restart_f();
5760
5761         if (!r_drawentities.integer)
5762                 r_refdef.scene.numentities = 0;
5763         else if (r_sortentities.integer)
5764                 R_SortEntities();
5765
5766         R_AnimCache_ClearCache();
5767
5768         /* adjust for stereo display */
5769         if(R_Stereo_Active())
5770         {
5771                 Matrix4x4_CreateFromQuakeEntity(&offsetmatrix, 0, r_stereo_separation.value * (0.5f - r_stereo_side), 0, 0, r_stereo_angle.value * (0.5f - r_stereo_side), 0, 1);
5772                 Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);
5773         }
5774
5775         if (r_refdef.view.isoverlay)
5776         {
5777                 // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
5778                 R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
5779                 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
5780                 R_TimeReport("depthclear");
5781
5782                 r_refdef.view.showdebug = false;
5783
5784                 r_fb.water.enabled = false;
5785                 r_fb.water.numwaterplanes = 0;
5786
5787                 R_RenderScene(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5788
5789                 r_refdef.view.matrix = originalmatrix;
5790
5791                 CHECKGLERROR
5792                 return;
5793         }
5794
5795         if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/)
5796         {
5797                 r_refdef.view.matrix = originalmatrix;
5798                 return;
5799         }
5800
5801         r_refdef.view.usevieworiginculling = !r_trippy.value && r_refdef.view.useperspective;
5802         if (v_isometric.integer && r_refdef.view.ismain)
5803                 V_MakeViewIsometric();
5804
5805         r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value;
5806
5807         if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D)
5808                 // in sRGB fallback, behave similar to true sRGB: convert this
5809                 // value from linear to sRGB
5810                 r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale);
5811
5812         R_RenderView_UpdateViewVectors();
5813
5814         R_Shadow_UpdateWorldLightSelection();
5815
5816         // this will set up r_fb.rt_screen
5817         R_Bloom_StartFrame();
5818
5819         // apply bloom brightness offset
5820         if(r_fb.rt_bloom)
5821                 r_refdef.view.colorscale *= r_bloom_scenebrightness.value;
5822
5823         // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
5824         if (r_fb.rt_screen)
5825         {
5826                 viewfbo = r_fb.rt_screen->fbo;
5827                 viewdepthtexture = r_fb.rt_screen->depthtexture;
5828                 viewcolortexture = r_fb.rt_screen->colortexture[0];
5829                 viewx = 0;
5830                 viewy = 0;
5831                 viewwidth = width;
5832                 viewheight = height;
5833         }
5834
5835         R_Water_StartFrame();
5836
5837         CHECKGLERROR
5838         if (r_timereport_active)
5839                 R_TimeReport("viewsetup");
5840
5841         R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5842
5843         // clear the whole fbo every frame - otherwise the driver will consider
5844         // it to be an inter-frame texture and stall in multi-gpu configurations
5845         if (r_fb.rt_screen)
5846                 GL_ScissorTest(false);
5847         R_ClearScreen(r_refdef.fogenabled);
5848         if (r_timereport_active)
5849                 R_TimeReport("viewclear");
5850
5851         r_refdef.view.clear = true;
5852
5853         r_refdef.view.showdebug = true;
5854
5855         R_View_Update();
5856         if (r_timereport_active)
5857                 R_TimeReport("visibility");
5858
5859         R_AnimCache_CacheVisibleEntities();
5860         if (r_timereport_active)
5861                 R_TimeReport("animcache");
5862
5863         R_Shadow_UpdateBounceGridTexture();
5864         if (r_timereport_active && r_shadow_bouncegrid.integer)
5865                 R_TimeReport("bouncegrid");
5866
5867         r_fb.water.numwaterplanes = 0;
5868         if (r_fb.water.enabled)
5869                 R_RenderWaterPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5870
5871         // for the actual view render we use scissoring a fair amount, so scissor
5872         // test needs to be on
5873         if (r_fb.rt_screen)
5874                 GL_ScissorTest(true);
5875         GL_Scissor(viewx, viewy, viewwidth, viewheight);
5876         R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5877         r_fb.water.numwaterplanes = 0;
5878
5879         // postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring
5880         GL_ScissorTest(false);
5881
5882         R_BlendView(fbo, depthtexture, colortexture, x, y, width, height);
5883         if (r_timereport_active)
5884                 R_TimeReport("blendview");
5885
5886         r_refdef.view.matrix = originalmatrix;
5887
5888         CHECKGLERROR
5889
5890         // go back to 2d rendering
5891         DrawQ_Start();
5892 }
5893
5894 void R_RenderWaterPlanes(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5895 {
5896         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
5897         {
5898                 r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity);
5899                 if (r_timereport_active)
5900                         R_TimeReport("waterworld");
5901         }
5902
5903         // don't let sound skip if going slow
5904         if (r_refdef.scene.extraupdate)
5905                 S_ExtraUpdate ();
5906
5907         R_DrawModelsAddWaterPlanes();
5908         if (r_timereport_active)
5909                 R_TimeReport("watermodels");
5910
5911         if (r_fb.water.numwaterplanes)
5912         {
5913                 R_Water_ProcessPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5914                 if (r_timereport_active)
5915                         R_TimeReport("waterscenes");
5916         }
5917 }
5918
5919 extern cvar_t cl_locs_show;
5920 static void R_DrawLocs(void);
5921 static void R_DrawEntityBBoxes(prvm_prog_t *prog);
5922 static void R_DrawModelDecals(void);
5923 extern cvar_t cl_decals_newsystem;
5924 extern qboolean r_shadow_usingdeferredprepass;
5925 extern int r_shadow_shadowmapatlas_modelshadows_size;
5926 void R_RenderScene(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5927 {
5928         qboolean shadowmapping = false;
5929
5930         if (r_timereport_active)
5931                 R_TimeReport("beginscene");
5932
5933         r_refdef.stats[r_stat_renders]++;
5934
5935         R_UpdateFog();
5936
5937         // don't let sound skip if going slow
5938         if (r_refdef.scene.extraupdate)
5939                 S_ExtraUpdate ();
5940
5941         R_MeshQueue_BeginScene();
5942
5943         R_SkyStartFrame();
5944
5945         Matrix4x4_CreateTranslate(&r_waterscrollmatrix, sin(r_refdef.scene.time) * 0.025 * r_waterscroll.value, sin(r_refdef.scene.time * 0.8f) * 0.025 * r_waterscroll.value, 0);
5946
5947         if (r_timereport_active)
5948                 R_TimeReport("skystartframe");
5949
5950         if (cl.csqc_vidvars.drawworld)
5951         {
5952                 // don't let sound skip if going slow
5953                 if (r_refdef.scene.extraupdate)
5954                         S_ExtraUpdate ();
5955
5956                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawSky)
5957                 {
5958                         r_refdef.scene.worldmodel->DrawSky(r_refdef.scene.worldentity);
5959                         if (r_timereport_active)
5960                                 R_TimeReport("worldsky");
5961                 }
5962
5963                 if (R_DrawBrushModelsSky() && r_timereport_active)
5964                         R_TimeReport("bmodelsky");
5965
5966                 if (skyrendermasked && skyrenderlater)
5967                 {
5968                         // we have to force off the water clipping plane while rendering sky
5969                         R_SetupView(false, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5970                         R_Sky();
5971                         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5972                         if (r_timereport_active)
5973                                 R_TimeReport("sky");
5974                 }
5975         }
5976
5977         // save the framebuffer info for R_Shadow_RenderMode_Reset during this view render
5978         r_shadow_viewfbo = viewfbo;
5979         r_shadow_viewdepthtexture = viewdepthtexture;
5980         r_shadow_viewcolortexture = viewcolortexture;
5981         r_shadow_viewx = viewx;
5982         r_shadow_viewy = viewy;
5983         r_shadow_viewwidth = viewwidth;
5984         r_shadow_viewheight = viewheight;
5985
5986         R_Shadow_PrepareModelShadows();
5987         R_Shadow_PrepareLights();
5988         if (r_timereport_active)
5989                 R_TimeReport("preparelights");
5990
5991         // render all the shadowmaps that will be used for this view
5992         shadowmapping = R_Shadow_ShadowMappingEnabled();
5993         if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
5994         {
5995                 R_Shadow_DrawShadowMaps();
5996                 if (r_timereport_active)
5997                         R_TimeReport("shadowmaps");
5998         }
5999
6000         // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
6001         if (r_shadow_usingdeferredprepass)
6002                 R_Shadow_DrawPrepass();
6003
6004         // now we begin the forward pass of the view render
6005         if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
6006         {
6007                 r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
6008                 if (r_timereport_active)
6009                         R_TimeReport("worlddepth");
6010         }
6011         if (r_depthfirst.integer >= 2)
6012         {
6013                 R_DrawModelsDepth();
6014                 if (r_timereport_active)
6015                         R_TimeReport("modeldepth");
6016         }
6017
6018         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
6019         {
6020                 r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
6021                 if (r_timereport_active)
6022                         R_TimeReport("world");
6023         }
6024
6025         // don't let sound skip if going slow
6026         if (r_refdef.scene.extraupdate)
6027                 S_ExtraUpdate ();
6028
6029         R_DrawModels();
6030         if (r_timereport_active)
6031                 R_TimeReport("models");
6032
6033         // don't let sound skip if going slow
6034         if (r_refdef.scene.extraupdate)
6035                 S_ExtraUpdate ();
6036
6037         if ((r_shadows.integer == 1 || (r_shadows.integer > 0 && !shadowmapping)) && !r_shadows_drawafterrtlighting.integer && r_refdef.scene.lightmapintensity > 0)
6038         {
6039                 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
6040                 R_Shadow_DrawModelShadows();
6041                 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
6042                 // don't let sound skip if going slow
6043                 if (r_refdef.scene.extraupdate)
6044                         S_ExtraUpdate ();
6045         }
6046
6047         if (!r_shadow_usingdeferredprepass)
6048         {
6049                 R_Shadow_DrawLights();
6050                 if (r_timereport_active)
6051                         R_TimeReport("rtlights");
6052         }
6053
6054         // don't let sound skip if going slow
6055         if (r_refdef.scene.extraupdate)
6056                 S_ExtraUpdate ();
6057
6058         if ((r_shadows.integer == 1 || (r_shadows.integer > 0 && !shadowmapping)) && r_shadows_drawafterrtlighting.integer && r_refdef.scene.lightmapintensity > 0)
6059         {
6060                 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
6061                 R_Shadow_DrawModelShadows();
6062                 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
6063                 // don't let sound skip if going slow
6064                 if (r_refdef.scene.extraupdate)
6065                         S_ExtraUpdate ();
6066         }
6067
6068         if (cl.csqc_vidvars.drawworld)
6069         {
6070                 if (cl_decals_newsystem.integer)
6071                 {
6072                         R_DrawModelDecals();
6073                         if (r_timereport_active)
6074                                 R_TimeReport("modeldecals");
6075                 }
6076                 else
6077                 {
6078                         R_DrawDecals();
6079                         if (r_timereport_active)
6080                                 R_TimeReport("decals");
6081                 }
6082
6083                 R_DrawParticles();
6084                 if (r_timereport_active)
6085                         R_TimeReport("particles");
6086
6087                 R_DrawExplosions();
6088                 if (r_timereport_active)
6089                         R_TimeReport("explosions");
6090         }
6091
6092         if (r_refdef.view.showdebug)
6093         {
6094                 if (cl_locs_show.integer)
6095                 {
6096                         R_DrawLocs();
6097                         if (r_timereport_active)
6098                                 R_TimeReport("showlocs");
6099                 }
6100
6101                 if (r_drawportals.integer)
6102                 {
6103                         R_DrawPortals();
6104                         if (r_timereport_active)
6105                                 R_TimeReport("portals");
6106                 }
6107
6108                 if (r_showbboxes_client.value > 0)
6109                 {
6110                         R_DrawEntityBBoxes(CLVM_prog);
6111                         if (r_timereport_active)
6112                                 R_TimeReport("clbboxes");
6113                 }
6114                 if (r_showbboxes.value > 0)
6115                 {
6116                         R_DrawEntityBBoxes(SVVM_prog);
6117                         if (r_timereport_active)
6118                                 R_TimeReport("svbboxes");
6119                 }
6120         }
6121
6122         if (r_transparent.integer)
6123         {
6124                 R_MeshQueue_RenderTransparent();
6125                 if (r_timereport_active)
6126                         R_TimeReport("drawtrans");
6127         }
6128
6129         if (r_refdef.view.showdebug && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDebug && (r_showtris.value > 0 || r_shownormals.value != 0 || r_showcollisionbrushes.value > 0 || r_showoverdraw.value > 0))
6130         {
6131                 r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity);
6132                 if (r_timereport_active)
6133                         R_TimeReport("worlddebug");
6134                 R_DrawModelsDebug();
6135                 if (r_timereport_active)
6136                         R_TimeReport("modeldebug");
6137         }
6138
6139         if (cl.csqc_vidvars.drawworld)
6140         {
6141                 R_Shadow_DrawCoronas();
6142                 if (r_timereport_active)
6143                         R_TimeReport("coronas");
6144         }
6145
6146         // don't let sound skip if going slow
6147         if (r_refdef.scene.extraupdate)
6148                 S_ExtraUpdate ();
6149 }
6150
6151 static const unsigned short bboxelements[36] =
6152 {
6153         5, 1, 3, 5, 3, 7,
6154         6, 2, 0, 6, 0, 4,
6155         7, 3, 2, 7, 2, 6,
6156         4, 0, 1, 4, 1, 5,
6157         4, 5, 7, 4, 7, 6,
6158         1, 0, 2, 1, 2, 3,
6159 };
6160
6161 #define BBOXEDGES 13
6162 static const float bboxedges[BBOXEDGES][6] = 
6163 {
6164         // whole box
6165         { 0, 0, 0, 1, 1, 1 },
6166         // bottom edges
6167         { 0, 0, 0, 0, 1, 0 },
6168         { 0, 0, 0, 1, 0, 0 },
6169         { 0, 1, 0, 1, 1, 0 },
6170         { 1, 0, 0, 1, 1, 0 },
6171         // top edges
6172         { 0, 0, 1, 0, 1, 1 },
6173         { 0, 0, 1, 1, 0, 1 },
6174         { 0, 1, 1, 1, 1, 1 },
6175         { 1, 0, 1, 1, 1, 1 },
6176         // vertical edges
6177         { 0, 0, 0, 0, 0, 1 },
6178         { 1, 0, 0, 1, 0, 1 },
6179         { 0, 1, 0, 0, 1, 1 },
6180         { 1, 1, 0, 1, 1, 1 },
6181 };
6182
6183 static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
6184 {
6185         int numvertices = BBOXEDGES * 8;
6186         float vertex3f[BBOXEDGES * 8 * 3], color4f[BBOXEDGES * 8 * 4];
6187         int numtriangles = BBOXEDGES * 12;
6188         unsigned short elements[BBOXEDGES * 36];
6189         int i, edge;
6190         float *v, *c, f1, f2, edgemins[3], edgemaxs[3];
6191
6192         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6193
6194         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6195         GL_DepthMask(false);
6196         GL_DepthRange(0, 1);
6197         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
6198
6199         for (edge = 0; edge < BBOXEDGES; edge++)
6200         {
6201                 for (i = 0; i < 3; i++)
6202                 {
6203                         edgemins[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][i] - 0.25f;
6204                         edgemaxs[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][3 + i] + 0.25f;
6205                 }
6206                 vertex3f[edge * 24 + 0] = edgemins[0]; vertex3f[edge * 24 + 1] = edgemins[1]; vertex3f[edge * 24 + 2] = edgemins[2];
6207                 vertex3f[edge * 24 + 3] = edgemaxs[0]; vertex3f[edge * 24 + 4] = edgemins[1]; vertex3f[edge * 24 + 5] = edgemins[2];
6208                 vertex3f[edge * 24 + 6] = edgemins[0]; vertex3f[edge * 24 + 7] = edgemaxs[1]; vertex3f[edge * 24 + 8] = edgemins[2];
6209                 vertex3f[edge * 24 + 9] = edgemaxs[0]; vertex3f[edge * 24 + 10] = edgemaxs[1]; vertex3f[edge * 24 + 11] = edgemins[2];
6210                 vertex3f[edge * 24 + 12] = edgemins[0]; vertex3f[edge * 24 + 13] = edgemins[1]; vertex3f[edge * 24 + 14] = edgemaxs[2];
6211                 vertex3f[edge * 24 + 15] = edgemaxs[0]; vertex3f[edge * 24 + 16] = edgemins[1]; vertex3f[edge * 24 + 17] = edgemaxs[2];
6212                 vertex3f[edge * 24 + 18] = edgemins[0]; vertex3f[edge * 24 + 19] = edgemaxs[1]; vertex3f[edge * 24 + 20] = edgemaxs[2];
6213                 vertex3f[edge * 24 + 21] = edgemaxs[0]; vertex3f[edge * 24 + 22] = edgemaxs[1]; vertex3f[edge * 24 + 23] = edgemaxs[2];
6214                 for (i = 0; i < 36; i++)
6215                         elements[edge * 36 + i] = edge * 8 + bboxelements[i];
6216         }
6217         R_FillColors(color4f, numvertices, cr, cg, cb, ca);
6218         if (r_refdef.fogenabled)
6219         {
6220                 for (i = 0, v = vertex3f, c = color4f; i < numvertices; i++, v += 3, c += 4)
6221                 {
6222                         f1 = RSurf_FogVertex(v);
6223                         f2 = 1 - f1;
6224                         c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
6225                         c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
6226                         c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
6227                 }
6228         }
6229         R_Mesh_PrepareVertices_Generic_Arrays(numvertices, vertex3f, color4f, NULL);
6230         R_Mesh_ResetTextureState();
6231         R_SetupShader_Generic_NoTexture(false, false);
6232         R_Mesh_Draw(0, numvertices, 0, numtriangles, NULL, NULL, 0, elements, NULL, 0);
6233 }
6234
6235 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6236 {
6237         // hacky overloading of the parameters
6238         prvm_prog_t *prog = (prvm_prog_t *)rtlight;
6239         int i;
6240         float color[4];
6241         prvm_edict_t *edict;
6242
6243         GL_CullFace(GL_NONE);
6244         R_SetupShader_Generic_NoTexture(false, false);
6245
6246         for (i = 0;i < numsurfaces;i++)
6247         {
6248                 edict = PRVM_EDICT_NUM(surfacelist[i]);
6249                 switch ((int)PRVM_serveredictfloat(edict, solid))
6250                 {
6251                         case SOLID_NOT:      Vector4Set(color, 1, 1, 1, 0.05);break;
6252                         case SOLID_TRIGGER:  Vector4Set(color, 1, 0, 1, 0.10);break;
6253                         case SOLID_BBOX:     Vector4Set(color, 0, 1, 0, 0.10);break;
6254                         case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
6255                         case SOLID_BSP:      Vector4Set(color, 0, 0, 1, 0.05);break;
6256                         case SOLID_CORPSE:   Vector4Set(color, 1, 0.5, 0, 0.05);break;
6257                         default:             Vector4Set(color, 0, 0, 0, 0.50);break;
6258                 }
6259                 if (prog == CLVM_prog)
6260                         color[3] *= r_showbboxes_client.value;
6261                 else
6262                         color[3] *= r_showbboxes.value;
6263                 color[3] = bound(0, color[3], 1);
6264                 GL_DepthTest(!r_showdisabledepthtest.integer);
6265                 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
6266         }
6267 }
6268
6269 static void R_DrawEntityBBoxes(prvm_prog_t *prog)
6270 {
6271         int i;
6272         prvm_edict_t *edict;
6273         vec3_t center;
6274
6275         if (prog == NULL)
6276                 return;
6277
6278         for (i = 0; i < prog->num_edicts; i++)
6279         {
6280                 edict = PRVM_EDICT_NUM(i);
6281                 if (edict->priv.server->free)
6282                         continue;
6283                 // exclude the following for now, as they don't live in world coordinate space and can't be solid:
6284                 if (PRVM_serveredictedict(edict, tag_entity) != 0)
6285                         continue;
6286                 if (PRVM_serveredictedict(edict, viewmodelforclient) != 0)
6287                         continue;
6288                 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
6289                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)prog);
6290         }
6291 }
6292
6293 static const int nomodelelement3i[24] =
6294 {
6295         5, 2, 0,
6296         5, 1, 2,
6297         5, 0, 3,
6298         5, 3, 1,
6299         0, 2, 4,
6300         2, 1, 4,
6301         3, 0, 4,
6302         1, 3, 4
6303 };
6304
6305 static const unsigned short nomodelelement3s[24] =
6306 {
6307         5, 2, 0,
6308         5, 1, 2,
6309         5, 0, 3,
6310         5, 3, 1,
6311         0, 2, 4,
6312         2, 1, 4,
6313         3, 0, 4,
6314         1, 3, 4
6315 };
6316
6317 static const float nomodelvertex3f[6*3] =
6318 {
6319         -16,   0,   0,
6320          16,   0,   0,
6321           0, -16,   0,
6322           0,  16,   0,
6323           0,   0, -16,
6324           0,   0,  16
6325 };
6326
6327 static const float nomodelcolor4f[6*4] =
6328 {
6329         0.0f, 0.0f, 0.5f, 1.0f,
6330         0.0f, 0.0f, 0.5f, 1.0f,
6331         0.0f, 0.5f, 0.0f, 1.0f,
6332         0.0f, 0.5f, 0.0f, 1.0f,
6333         0.5f, 0.0f, 0.0f, 1.0f,
6334         0.5f, 0.0f, 0.0f, 1.0f
6335 };
6336
6337 static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6338 {
6339         int i;
6340         float f1, f2, *c;
6341         float color4f[6*4];
6342
6343         RSurf_ActiveCustomEntity(&ent->matrix, &ent->inversematrix, ent->flags, ent->shadertime, ent->colormod[0], ent->colormod[1], ent->colormod[2], ent->alpha, 6, nomodelvertex3f, NULL, NULL, NULL, NULL, nomodelcolor4f, 8, nomodelelement3i, nomodelelement3s, false, false);
6344
6345         // this is only called once per entity so numsurfaces is always 1, and
6346         // surfacelist is always {0}, so this code does not handle batches
6347
6348         if (rsurface.ent_flags & RENDER_ADDITIVE)
6349         {
6350                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
6351                 GL_DepthMask(false);
6352         }
6353         else if (ent->alpha < 1)
6354         {
6355                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6356                 GL_DepthMask(false);
6357         }
6358         else
6359         {
6360                 GL_BlendFunc(GL_ONE, GL_ZERO);
6361                 GL_DepthMask(true);
6362         }
6363         GL_DepthRange(0, (rsurface.ent_flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
6364         GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
6365         GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
6366         GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
6367         memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
6368         for (i = 0, c = color4f;i < 6;i++, c += 4)
6369         {
6370                 c[0] *= ent->render_fullbright[0] * r_refdef.view.colorscale;
6371                 c[1] *= ent->render_fullbright[1] * r_refdef.view.colorscale;
6372                 c[2] *= ent->render_fullbright[2] * r_refdef.view.colorscale;
6373                 c[3] *= ent->alpha;
6374         }
6375         if (r_refdef.fogenabled)
6376         {
6377                 for (i = 0, c = color4f;i < 6;i++, c += 4)
6378                 {
6379                         f1 = RSurf_FogVertex(nomodelvertex3f + 3*i);
6380                         f2 = 1 - f1;
6381                         c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
6382                         c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
6383                         c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
6384                 }
6385         }
6386 //      R_Mesh_ResetTextureState();
6387         R_SetupShader_Generic_NoTexture(false, false);
6388         R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
6389         R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
6390 }
6391
6392 void R_DrawNoModel(entity_render_t *ent)
6393 {
6394         vec3_t org;
6395         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
6396         if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1))
6397                 R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
6398         else
6399                 R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
6400 }
6401
6402 void R_CalcBeam_Vertex3f (float *vert, const float *org1, const float *org2, float width)
6403 {
6404         vec3_t right1, right2, diff, normal;
6405
6406         VectorSubtract (org2, org1, normal);
6407
6408         // calculate 'right' vector for start
6409         VectorSubtract (r_refdef.view.origin, org1, diff);
6410         CrossProduct (normal, diff, right1);
6411         VectorNormalize (right1);
6412
6413         // calculate 'right' vector for end
6414         VectorSubtract (r_refdef.view.origin, org2, diff);
6415         CrossProduct (normal, diff, right2);
6416         VectorNormalize (right2);
6417
6418         vert[ 0] = org1[0] + width * right1[0];
6419         vert[ 1] = org1[1] + width * right1[1];
6420         vert[ 2] = org1[2] + width * right1[2];
6421         vert[ 3] = org1[0] - width * right1[0];
6422         vert[ 4] = org1[1] - width * right1[1];
6423         vert[ 5] = org1[2] - width * right1[2];
6424         vert[ 6] = org2[0] - width * right2[0];
6425         vert[ 7] = org2[1] - width * right2[1];
6426         vert[ 8] = org2[2] - width * right2[2];
6427         vert[ 9] = org2[0] + width * right2[0];
6428         vert[10] = org2[1] + width * right2[1];
6429         vert[11] = org2[2] + width * right2[2];
6430 }
6431
6432 void R_CalcSprite_Vertex3f(float *vertex3f, const vec3_t origin, const vec3_t left, const vec3_t up, float scalex1, float scalex2, float scaley1, float scaley2)
6433 {
6434         vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
6435         vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
6436         vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
6437         vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
6438         vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
6439         vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
6440         vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
6441         vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
6442         vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
6443         vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
6444         vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
6445         vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
6446 }
6447
6448 static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
6449 {
6450         int i;
6451         float *vertex3f;
6452         float v[3];
6453         VectorSet(v, x, y, z);
6454         for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
6455                 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
6456                         break;
6457         if (i == mesh->numvertices)
6458         {
6459                 if (mesh->numvertices < mesh->maxvertices)
6460                 {
6461                         VectorCopy(v, vertex3f);
6462                         mesh->numvertices++;
6463                 }
6464                 return mesh->numvertices;
6465         }
6466         else
6467                 return i;
6468 }
6469
6470 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
6471 {
6472         int i;
6473         int *e, element[3];
6474         element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6475         element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6476         e = mesh->element3i + mesh->numtriangles * 3;
6477         for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
6478         {
6479                 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
6480                 if (mesh->numtriangles < mesh->maxtriangles)
6481                 {
6482                         *e++ = element[0];
6483                         *e++ = element[1];
6484                         *e++ = element[2];
6485                         mesh->numtriangles++;
6486                 }
6487                 element[1] = element[2];
6488         }
6489 }
6490
6491 static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
6492 {
6493         int i;
6494         int *e, element[3];
6495         element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6496         element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6497         e = mesh->element3i + mesh->numtriangles * 3;
6498         for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
6499         {
6500                 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
6501                 if (mesh->numtriangles < mesh->maxtriangles)
6502                 {
6503                         *e++ = element[0];
6504                         *e++ = element[1];
6505                         *e++ = element[2];
6506                         mesh->numtriangles++;
6507                 }
6508                 element[1] = element[2];
6509         }
6510 }
6511
6512 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
6513 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
6514 {
6515         int planenum, planenum2;
6516         int w;
6517         int tempnumpoints;
6518         mplane_t *plane, *plane2;
6519         double maxdist;
6520         double temppoints[2][256*3];
6521         // figure out how large a bounding box we need to properly compute this brush
6522         maxdist = 0;
6523         for (w = 0;w < numplanes;w++)
6524                 maxdist = max(maxdist, fabs(planes[w].dist));
6525         // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
6526         maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
6527         for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
6528         {
6529                 w = 0;
6530                 tempnumpoints = 4;
6531                 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
6532                 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
6533                 {
6534                         if (planenum2 == planenum)
6535                                 continue;
6536                         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);
6537                         w = !w;
6538                 }
6539                 if (tempnumpoints < 3)
6540                         continue;
6541                 // generate elements forming a triangle fan for this polygon
6542                 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
6543         }
6544 }
6545
6546 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)
6547 {
6548         texturelayer_t *layer;
6549         layer = t->currentlayers + t->currentnumlayers++;
6550         layer->type = type;
6551         layer->depthmask = depthmask;
6552         layer->blendfunc1 = blendfunc1;
6553         layer->blendfunc2 = blendfunc2;
6554         layer->texture = texture;
6555         layer->texmatrix = *matrix;
6556         layer->color[0] = r;
6557         layer->color[1] = g;
6558         layer->color[2] = b;
6559         layer->color[3] = a;
6560 }
6561
6562 static qboolean R_TestQ3WaveFunc(q3wavefunc_t func, const float *parms)
6563 {
6564         if(parms[0] == 0 && parms[1] == 0)
6565                 return false;
6566         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6567                 if(rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)] == 0)
6568                         return false;
6569         return true;
6570 }
6571
6572 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
6573 {
6574         double index, f;
6575         index = parms[2] + rsurface.shadertime * parms[3];
6576         index -= floor(index);
6577         switch (func & ((1 << Q3WAVEFUNC_USER_SHIFT) - 1))
6578         {
6579         default:
6580         case Q3WAVEFUNC_NONE:
6581         case Q3WAVEFUNC_NOISE:
6582         case Q3WAVEFUNC_COUNT:
6583                 f = 0;
6584                 break;
6585         case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
6586         case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
6587         case Q3WAVEFUNC_SAWTOOTH: f = index;break;
6588         case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
6589         case Q3WAVEFUNC_TRIANGLE:
6590                 index *= 4;
6591                 f = index - floor(index);
6592                 if (index < 1)
6593                 {
6594                         // f = f;
6595                 }
6596                 else if (index < 2)
6597                         f = 1 - f;
6598                 else if (index < 3)
6599                         f = -f;
6600                 else
6601                         f = -(1 - f);
6602                 break;
6603         }
6604         f = parms[0] + parms[1] * f;
6605         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6606                 f *= rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)];
6607         return (float) f;
6608 }
6609
6610 static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
6611 {
6612         int w, h, idx;
6613         float shadertime;
6614         float f;
6615         float offsetd[2];
6616         float tcmat[12];
6617         matrix4x4_t matrix, temp;
6618         // if shadertime exceeds about 9 hours (32768 seconds), just wrap it,
6619         // it's better to have one huge fixup every 9 hours than gradual
6620         // degradation over time which looks consistently bad after many hours.
6621         //
6622         // tcmod scroll in particular suffers from this degradation which can't be
6623         // effectively worked around even with floor() tricks because we don't
6624         // know if tcmod scroll is the last tcmod being applied, and for clampmap
6625         // a workaround involving floor() would be incorrect anyway...
6626         shadertime = rsurface.shadertime;
6627         if (shadertime >= 32768.0f)
6628                 shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f;
6629         switch(tcmod->tcmod)
6630         {
6631                 case Q3TCMOD_COUNT:
6632                 case Q3TCMOD_NONE:
6633                         if (currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6634                                 matrix = r_waterscrollmatrix;
6635                         else
6636                                 matrix = identitymatrix;
6637                         break;
6638                 case Q3TCMOD_ENTITYTRANSLATE:
6639                         // this is used in Q3 to allow the gamecode to control texcoord
6640                         // scrolling on the entity, which is not supported in darkplaces yet.
6641                         Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
6642                         break;
6643                 case Q3TCMOD_ROTATE:
6644                         Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
6645                         Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
6646                         Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
6647                         break;
6648                 case Q3TCMOD_SCALE:
6649                         Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
6650                         break;
6651                 case Q3TCMOD_SCROLL:
6652                         // this particular tcmod is a "bug for bug" compatible one with regards to
6653                         // Quake3, the wrapping is unnecessary with our shadetime fix but quake3
6654                         // specifically did the wrapping and so we must mimic that...
6655                         offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
6656                         offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
6657                         Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
6658                         break;
6659                 case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
6660                         w = (int) tcmod->parms[0];
6661                         h = (int) tcmod->parms[1];
6662                         f = rsurface.shadertime / (tcmod->parms[2] * w * h);
6663                         f = f - floor(f);
6664                         idx = (int) floor(f * w * h);
6665                         Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
6666                         break;
6667                 case Q3TCMOD_STRETCH:
6668                         f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
6669                         Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
6670                         break;
6671                 case Q3TCMOD_TRANSFORM:
6672                         VectorSet(tcmat +  0, tcmod->parms[0], tcmod->parms[1], 0);
6673                         VectorSet(tcmat +  3, tcmod->parms[2], tcmod->parms[3], 0);
6674                         VectorSet(tcmat +  6, 0                   , 0                , 1);
6675                         VectorSet(tcmat +  9, tcmod->parms[4], tcmod->parms[5], 0);
6676                         Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
6677                         break;
6678                 case Q3TCMOD_TURBULENT:
6679                         // this is handled in the RSurf_PrepareVertices function
6680                         matrix = identitymatrix;
6681                         break;
6682         }
6683         temp = *texmatrix;
6684         Matrix4x4_Concat(texmatrix, &matrix, &temp);
6685 }
6686
6687 static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
6688 {
6689         int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP;
6690         char name[MAX_QPATH];
6691         skinframe_t *skinframe;
6692         unsigned char pixels[296*194];
6693         strlcpy(cache->name, skinname, sizeof(cache->name));
6694         dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name);
6695         if (developer_loading.integer)
6696                 Con_Printf("loading %s\n", name);
6697         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
6698         if (!skinframe || !skinframe->base)
6699         {
6700                 unsigned char *f;
6701                 fs_offset_t filesize;
6702                 skinframe = NULL;
6703                 f = FS_LoadFile(name, tempmempool, true, &filesize);
6704                 if (f)
6705                 {
6706                         if (LoadPCX_QWSkin(f, (int)filesize, pixels, 296, 194))
6707                                 skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
6708                         Mem_Free(f);
6709                 }
6710         }
6711         cache->skinframe = skinframe;
6712 }
6713
6714 texture_t *R_GetCurrentTexture(texture_t *t)
6715 {
6716         int i, q;
6717         const entity_render_t *ent = rsurface.entity;
6718         dp_model_t *model = ent->model; // when calling this, ent must not be NULL
6719         q3shaderinfo_layer_tcmod_t *tcmod;
6720         float specularscale = 0.0f;
6721
6722         if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate)
6723                 return t->currentframe;
6724         t->update_lastrenderframe = r_textureframe;
6725         t->update_lastrenderentity = (void *)ent;
6726
6727         if(ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS)
6728                 t->camera_entity = ent->entitynumber;
6729         else
6730                 t->camera_entity = 0;
6731
6732         // switch to an alternate material if this is a q1bsp animated material
6733         {
6734                 texture_t *texture = t;
6735                 int s = rsurface.ent_skinnum;
6736                 if ((unsigned int)s >= (unsigned int)model->numskins)
6737                         s = 0;
6738                 if (model->skinscenes)
6739                 {
6740                         if (model->skinscenes[s].framecount > 1)
6741                                 s = model->skinscenes[s].firstframe + (unsigned int) (rsurface.shadertime * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
6742                         else
6743                                 s = model->skinscenes[s].firstframe;
6744                 }
6745                 if (s > 0)
6746                         t = t + s * model->num_surfaces;
6747                 if (t->animated)
6748                 {
6749                         // use an alternate animation if the entity's frame is not 0,
6750                         // and only if the texture has an alternate animation
6751                         if (t->animated == 2) // q2bsp
6752                                 t = t->anim_frames[0][ent->framegroupblend[0].frame % t->anim_total[0]];
6753                         else if (rsurface.ent_alttextures && t->anim_total[1])
6754                                 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
6755                         else
6756                                 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
6757                 }
6758                 texture->currentframe = t;
6759         }
6760
6761         // update currentskinframe to be a qw skin or animation frame
6762         if (rsurface.ent_qwskin >= 0)
6763         {
6764                 i = rsurface.ent_qwskin;
6765                 if (!r_qwskincache || r_qwskincache_size != cl.maxclients)
6766                 {
6767                         r_qwskincache_size = cl.maxclients;
6768                         if (r_qwskincache)
6769                                 Mem_Free(r_qwskincache);
6770                         r_qwskincache = (r_qwskincache_t *)Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size);
6771                 }
6772                 if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
6773                         R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
6774                 t->currentskinframe = r_qwskincache[i].skinframe;
6775                 if (t->materialshaderpass && t->currentskinframe == NULL)
6776                         t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6777         }
6778         else if (t->materialshaderpass && t->materialshaderpass->numframes >= 2)
6779                 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6780         if (t->backgroundshaderpass && t->backgroundshaderpass->numframes >= 2)
6781                 t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
6782
6783         t->currentmaterialflags = t->basematerialflags;
6784         t->currentalpha = rsurface.entity->alpha * t->basealpha;
6785         if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_novis.integer || r_trippy.integer))
6786                 t->currentalpha *= r_wateralpha.value;
6787         if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay)
6788                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later
6789         if(!r_fb.water.enabled || r_refdef.view.isoverlay)
6790                 t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA);
6791
6792         // decide on which type of lighting to use for this surface
6793         if (rsurface.entity->render_modellight_forced)
6794                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6795         if (rsurface.entity->render_rtlight_disabled)
6796                 t->currentmaterialflags |= MATERIALFLAG_NORTLIGHT;
6797         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND && !(R_BlendFuncFlags(t->customblendfunc[0], t->customblendfunc[1]) & BLENDFUNC_ALLOWS_COLORMOD))
6798         {
6799                 // some CUSTOMBLEND blendfuncs are too weird, we have to ignore colormod and view colorscale
6800                 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_NORTLIGHT;
6801                 for (q = 0; q < 3; q++)
6802                 {
6803                         t->render_glowmod[q] = rsurface.entity->glowmod[q];
6804                         t->render_modellight_lightdir[q] = q == 2;
6805                         t->render_modellight_ambient[q] = 1;
6806                         t->render_modellight_diffuse[q] = 0;
6807                         t->render_modellight_specular[q] = 0;
6808                         t->render_lightmap_ambient[q] = 0;
6809                         t->render_lightmap_diffuse[q] = 0;
6810                         t->render_lightmap_specular[q] = 0;
6811                         t->render_rtlight_diffuse[q] = 0;
6812                         t->render_rtlight_specular[q] = 0;
6813                 }
6814         }
6815         else if ((t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !(rsurface.ent_flags & RENDER_LIGHT))
6816         {
6817                 // fullbright is basically MATERIALFLAG_MODELLIGHT but with ambient locked to 1,1,1 and no shading
6818                 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_NORTLIGHT | MATERIALFLAG_MODELLIGHT;
6819                 for (q = 0; q < 3; q++)
6820                 {
6821                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6822                         t->render_modellight_ambient[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6823                         t->render_modellight_lightdir[q] = q == 2;
6824                         t->render_modellight_diffuse[q] = 0;
6825                         t->render_modellight_specular[q] = 0;
6826                         t->render_lightmap_ambient[q] = 0;
6827                         t->render_lightmap_diffuse[q] = 0;
6828                         t->render_lightmap_specular[q] = 0;
6829                         t->render_rtlight_diffuse[q] = 0;
6830                         t->render_rtlight_specular[q] = 0;
6831                 }
6832         }
6833         else if (FAKELIGHT_ENABLED)
6834         {
6835                 // no modellight if using fakelight for the map
6836                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_NORTLIGHT) & ~(MATERIALFLAG_MODELLIGHT);
6837                 for (q = 0; q < 3; q++)
6838                 {
6839                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6840                         t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6841                         t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6842                         t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6843                         t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6844                         t->render_lightmap_ambient[q] = 0;
6845                         t->render_lightmap_diffuse[q] = 0;
6846                         t->render_lightmap_specular[q] = 0;
6847                         t->render_rtlight_diffuse[q] = 0;
6848                         t->render_rtlight_specular[q] = 0;
6849                 }
6850         }
6851         else if ((rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT)) || rsurface.modeltexcoordlightmap2f == NULL)
6852         {
6853                 // ambient + single direction light (modellight)
6854                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6855                 for (q = 0; q < 3; q++)
6856                 {
6857                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6858                         t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6859                         t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6860                         t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6861                         t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6862                         t->render_lightmap_ambient[q] = 0;
6863                         t->render_lightmap_diffuse[q] = 0;
6864                         t->render_lightmap_specular[q] = 0;
6865                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6866                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6867                 }
6868         }
6869         else
6870         {
6871                 // lightmap - 2x diffuse and specular brightness because bsp files have 0-2 colors as 0-1
6872                 for (q = 0; q < 3; q++)
6873                 {
6874                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6875                         t->render_modellight_lightdir[q] = q == 2;
6876                         t->render_modellight_ambient[q] = 0;
6877                         t->render_modellight_diffuse[q] = 0;
6878                         t->render_modellight_specular[q] = 0;
6879                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6880                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6881                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6882                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6883                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6884                 }
6885         }
6886
6887         if (t->currentmaterialflags & MATERIALFLAG_VERTEXCOLOR)
6888         {
6889                 // since MATERIALFLAG_VERTEXCOLOR uses the lightmapcolor4f vertex
6890                 // attribute, we punt it to the lightmap path and hope for the best,
6891                 // but lighting doesn't work.
6892                 //
6893                 // FIXME: this is fine for effects but CSQC polygons should be subject
6894                 // to lighting.
6895                 t->currentmaterialflags &= ~MATERIALFLAG_MODELLIGHT;
6896                 for (q = 0; q < 3; q++)
6897                 {
6898                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6899                         t->render_modellight_lightdir[q] = q == 2;
6900                         t->render_modellight_ambient[q] = 0;
6901                         t->render_modellight_diffuse[q] = 0;
6902                         t->render_modellight_specular[q] = 0;
6903                         t->render_lightmap_ambient[q] = 0;
6904                         t->render_lightmap_diffuse[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6905                         t->render_lightmap_specular[q] = 0;
6906                         t->render_rtlight_diffuse[q] = 0;
6907                         t->render_rtlight_specular[q] = 0;
6908                 }
6909         }
6910
6911         for (q = 0; q < 3; q++)
6912         {
6913                 t->render_colormap_pants[q] = rsurface.entity->colormap_pantscolor[q];
6914                 t->render_colormap_shirt[q] = rsurface.entity->colormap_shirtcolor[q];
6915         }
6916
6917         if (rsurface.ent_flags & RENDER_ADDITIVE)
6918                 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6919         else if (t->currentalpha < 1)
6920                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6921         // LordHavoc: prevent bugs where code checks add or alpha at higher priority than customblend by clearing these flags
6922         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6923                 t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA);
6924         if (rsurface.ent_flags & RENDER_DOUBLESIDED)
6925                 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
6926         if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
6927                 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
6928         if (t->backgroundshaderpass)
6929                 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
6930         if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
6931         {
6932                 if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA))
6933                         t->currentmaterialflags &= ~MATERIALFLAG_BLENDED;
6934         }
6935         else
6936                 t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA);
6937         if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)))
6938         {
6939                 // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on
6940                 t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST;
6941         }
6942         if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
6943                 t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
6944
6945         // there is no tcmod
6946         if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6947         {
6948                 t->currenttexmatrix = r_waterscrollmatrix;
6949                 t->currentbackgroundtexmatrix = r_waterscrollmatrix;
6950         }
6951         else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE))
6952         {
6953                 Matrix4x4_CreateIdentity(&t->currenttexmatrix);
6954                 Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
6955         }
6956
6957         if (t->materialshaderpass)
6958                 for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
6959                         R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
6960
6961         t->colormapping = VectorLength2(t->render_colormap_pants) + VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f);
6962         if (t->currentskinframe->qpixels)
6963                 R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
6964         t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
6965         if (!t->basetexture)
6966                 t->basetexture = r_texture_notexture;
6967         t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
6968         t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
6969         t->nmaptexture = t->currentskinframe->nmap;
6970         if (!t->nmaptexture)
6971                 t->nmaptexture = r_texture_blanknormalmap;
6972         t->glosstexture = r_texture_black;
6973         t->glowtexture = t->currentskinframe->glow;
6974         t->fogtexture = t->currentskinframe->fog;
6975         t->reflectmasktexture = t->currentskinframe->reflect;
6976         if (t->backgroundshaderpass)
6977         {
6978                 for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
6979                         R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
6980                 t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
6981                 t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
6982                 t->backgroundglosstexture = r_texture_black;
6983                 t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
6984                 if (!t->backgroundnmaptexture)
6985                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6986                 // make sure that if glow is going to be used, both textures are not NULL
6987                 if (!t->backgroundglowtexture && t->glowtexture)
6988                         t->backgroundglowtexture = r_texture_black;
6989                 if (!t->glowtexture && t->backgroundglowtexture)
6990                         t->glowtexture = r_texture_black;
6991         }
6992         else
6993         {
6994                 t->backgroundbasetexture = r_texture_white;
6995                 t->backgroundnmaptexture = r_texture_blanknormalmap;
6996                 t->backgroundglosstexture = r_texture_black;
6997                 t->backgroundglowtexture = NULL;
6998         }
6999         t->specularpower = r_shadow_glossexponent.value;
7000         // TODO: store reference values for these in the texture?
7001         if (r_shadow_gloss.integer > 0)
7002         {
7003                 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
7004                 {
7005                         if (r_shadow_glossintensity.value > 0)
7006                         {
7007                                 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
7008                                 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
7009                                 specularscale = r_shadow_glossintensity.value;
7010                         }
7011                 }
7012                 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
7013                 {
7014                         t->glosstexture = r_texture_white;
7015                         t->backgroundglosstexture = r_texture_white;
7016                         specularscale = r_shadow_gloss2intensity.value;
7017                         t->specularpower = r_shadow_gloss2exponent.value;
7018                 }
7019         }
7020         specularscale *= t->specularscalemod;
7021         t->specularpower *= t->specularpowermod;
7022
7023         // lightmaps mode looks bad with dlights using actual texturing, so turn
7024         // off the colormap and glossmap, but leave the normalmap on as it still
7025         // accurately represents the shading involved
7026         if (gl_lightmaps.integer)
7027         {
7028                 t->basetexture = r_texture_grey128;
7029                 t->pantstexture = r_texture_black;
7030                 t->shirttexture = r_texture_black;
7031                 if (gl_lightmaps.integer < 2)
7032                         t->nmaptexture = r_texture_blanknormalmap;
7033                 t->glosstexture = r_texture_black;
7034                 t->glowtexture = NULL;
7035                 t->fogtexture = NULL;
7036                 t->reflectmasktexture = NULL;
7037                 t->backgroundbasetexture = NULL;
7038                 if (gl_lightmaps.integer < 2)
7039                         t->backgroundnmaptexture = r_texture_blanknormalmap;
7040                 t->backgroundglosstexture = r_texture_black;
7041                 t->backgroundglowtexture = NULL;
7042                 specularscale = 0;
7043                 t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
7044         }
7045
7046         if (specularscale != 1.0f)
7047         {
7048                 for (q = 0; q < 3; q++)
7049                 {
7050                         t->render_modellight_specular[q] *= specularscale;
7051                         t->render_lightmap_specular[q] *= specularscale;
7052                         t->render_rtlight_specular[q] *= specularscale;
7053                 }
7054         }
7055
7056         t->currentnumlayers = 0;
7057         if (t->currentmaterialflags & MATERIALFLAG_WALL)
7058         {
7059                 int blendfunc1, blendfunc2;
7060                 qboolean depthmask;
7061                 if (t->currentmaterialflags & MATERIALFLAG_ADD)
7062                 {
7063                         blendfunc1 = GL_SRC_ALPHA;
7064                         blendfunc2 = GL_ONE;
7065                 }
7066                 else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
7067                 {
7068                         blendfunc1 = GL_SRC_ALPHA;
7069                         blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
7070                 }
7071                 else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
7072                 {
7073                         blendfunc1 = t->customblendfunc[0];
7074                         blendfunc2 = t->customblendfunc[1];
7075                 }
7076                 else
7077                 {
7078                         blendfunc1 = GL_ONE;
7079                         blendfunc2 = GL_ZERO;
7080                 }
7081                 depthmask = !(t->currentmaterialflags & MATERIALFLAG_BLENDED);
7082                 if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
7083                 {
7084                         // basic lit geometry
7085                         R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE, t->basetexture, &t->currenttexmatrix, 2, 2, 2, t->currentalpha);
7086                         // add pants/shirt if needed
7087                         if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7088                                 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->pantstexture, &t->currenttexmatrix, 2 * t->render_colormap_pants[0], 2 * t->render_colormap_pants[1], 2 * t->render_colormap_pants[2], t->currentalpha);
7089                         if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7090                                 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->shirttexture, &t->currenttexmatrix, 2 * t->render_colormap_shirt[0], 2 * t->render_colormap_shirt[1], 2 * t->render_colormap_shirt[2], t->currentalpha);
7091                 }
7092                 else
7093                 {
7094                         // basic lit geometry
7095                         R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE, t->basetexture, &t->currenttexmatrix, t->render_lightmap_diffuse[0], t->render_lightmap_diffuse[1], t->render_lightmap_diffuse[2], t->currentalpha);
7096                         // add pants/shirt if needed
7097                         if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7098                                 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->pantstexture, &t->currenttexmatrix, t->render_colormap_pants[0] * t->render_lightmap_diffuse[0], t->render_colormap_pants[1] * t->render_lightmap_diffuse[1], t->render_colormap_pants[2]  * t->render_lightmap_diffuse[2], t->currentalpha);
7099                         if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7100                                 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->shirttexture, &t->currenttexmatrix, t->render_colormap_shirt[0] * t->render_lightmap_diffuse[0], t->render_colormap_shirt[1] * t->render_lightmap_diffuse[1], t->render_colormap_shirt[2] * t->render_lightmap_diffuse[2], t->currentalpha);
7101                         // now add ambient passes if needed
7102                         if (VectorLength2(t->render_lightmap_ambient) >= (1.0f/1048576.0f))
7103                         {
7104                                 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->basetexture, &t->currenttexmatrix, t->render_lightmap_ambient[0], t->render_lightmap_ambient[1], t->render_lightmap_ambient[2], t->currentalpha);
7105                                 if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7106                                         R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->pantstexture, &t->currenttexmatrix, t->render_colormap_pants[0] * t->render_lightmap_ambient[0], t->render_colormap_pants[1] * t->render_lightmap_ambient[1], t->render_colormap_pants[2] * t->render_lightmap_ambient[2], t->currentalpha);
7107                                 if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7108                                         R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->shirttexture, &t->currenttexmatrix, t->render_colormap_shirt[0] * t->render_lightmap_ambient[0], t->render_colormap_shirt[1] * t->render_lightmap_ambient[1], t->render_colormap_shirt[2] * t->render_lightmap_ambient[2], t->currentalpha);
7109                         }
7110                 }
7111                 if (t->glowtexture != NULL && !gl_lightmaps.integer)
7112                         R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_TEXTURE, t->glowtexture, &t->currenttexmatrix, t->render_glowmod[0], t->render_glowmod[1], t->render_glowmod[2], t->currentalpha);
7113                 if (r_refdef.fogenabled && !(t->currentmaterialflags & MATERIALFLAG_ADD))
7114                 {
7115                         // if this is opaque use alpha blend which will darken the earlier
7116                         // passes cheaply.
7117                         //
7118                         // if this is an alpha blended material, all the earlier passes
7119                         // were darkened by fog already, so we only need to add the fog
7120                         // color ontop through the fog mask texture
7121                         //
7122                         // if this is an additive blended material, all the earlier passes
7123                         // were darkened by fog already, and we should not add fog color
7124                         // (because the background was not darkened, there is no fog color
7125                         // that was lost behind it).
7126                         R_Texture_AddLayer(t, false, GL_SRC_ALPHA, (t->currentmaterialflags & MATERIALFLAG_BLENDED) ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA, TEXTURELAYERTYPE_FOG, t->fogtexture, &t->currenttexmatrix, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], t->currentalpha);
7127                 }
7128         }
7129
7130         return t;
7131 }
7132
7133 rsurfacestate_t rsurface;
7134
7135 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass)
7136 {
7137         dp_model_t *model = ent->model;
7138         //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
7139         //      return;
7140         rsurface.entity = (entity_render_t *)ent;
7141         rsurface.skeleton = ent->skeleton;
7142         memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
7143         rsurface.ent_skinnum = ent->skinnum;
7144         rsurface.ent_qwskin = (ent->entitynumber <= cl.maxclients && ent->entitynumber >= 1 && cls.protocol == PROTOCOL_QUAKEWORLD && cl.scores[ent->entitynumber - 1].qw_skin[0] && !strcmp(ent->model->name, "progs/player.mdl")) ? (ent->entitynumber - 1) : -1;
7145         rsurface.ent_flags = ent->flags;
7146         if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
7147                 rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
7148         rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
7149         rsurface.matrix = ent->matrix;
7150         rsurface.inversematrix = ent->inversematrix;
7151         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7152         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7153         R_EntityMatrix(&rsurface.matrix);
7154         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7155         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7156         rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist * rsurface.inversematrixscale;
7157         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7158         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7159         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7160         memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
7161         rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
7162         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7163         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7164         if (ent->model->brush.submodel && !prepass)
7165         {
7166                 rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
7167                 rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
7168         }
7169         // if the animcache code decided it should use the shader path, skip the deform step
7170         rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4;
7171         rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer;
7172         rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset;
7173         rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size;
7174         rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0;
7175         if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4)
7176         {
7177                 if (ent->animcache_vertex3f)
7178                 {
7179                         r_refdef.stats[r_stat_batch_entitycache_count]++;
7180                         r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
7181                         r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
7182                         r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
7183                         rsurface.modelvertex3f = ent->animcache_vertex3f;
7184                         rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer;
7185                         rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset;
7186                         rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
7187                         rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL;
7188                         rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0;
7189                         rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
7190                         rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL;
7191                         rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0;
7192                         rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
7193                         rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL;
7194                         rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0;
7195                         rsurface.modelvertexmesh = ent->animcache_vertexmesh;
7196                         rsurface.modelvertexmesh_vertexbuffer = ent->animcache_vertexmesh_vertexbuffer;
7197                         rsurface.modelvertexmesh_bufferoffset = ent->animcache_vertexmesh_bufferoffset;
7198                 }
7199                 else if (wanttangents)
7200                 {
7201                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7202                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7203                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7204                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7205                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7206                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7207                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7208                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7209                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f);
7210                         rsurface.modelvertexmesh = NULL;
7211                         rsurface.modelvertexmesh_vertexbuffer = NULL;
7212                         rsurface.modelvertexmesh_bufferoffset = 0;
7213                         rsurface.modelvertex3f_vertexbuffer = NULL;
7214                         rsurface.modelvertex3f_bufferoffset = 0;
7215                         rsurface.modelvertex3f_vertexbuffer = 0;
7216                         rsurface.modelvertex3f_bufferoffset = 0;
7217                         rsurface.modelsvector3f_vertexbuffer = 0;
7218                         rsurface.modelsvector3f_bufferoffset = 0;
7219                         rsurface.modeltvector3f_vertexbuffer = 0;
7220                         rsurface.modeltvector3f_bufferoffset = 0;
7221                         rsurface.modelnormal3f_vertexbuffer = 0;
7222                         rsurface.modelnormal3f_bufferoffset = 0;
7223                 }
7224                 else if (wantnormals)
7225                 {
7226                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7227                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7228                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7229                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7230                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7231                         rsurface.modelsvector3f = NULL;
7232                         rsurface.modeltvector3f = NULL;
7233                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7234                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL);
7235                         rsurface.modelvertexmesh = NULL;
7236                         rsurface.modelvertexmesh_vertexbuffer = NULL;
7237                         rsurface.modelvertexmesh_bufferoffset = 0;
7238                         rsurface.modelvertex3f_vertexbuffer = NULL;
7239                         rsurface.modelvertex3f_bufferoffset = 0;
7240                         rsurface.modelvertex3f_vertexbuffer = 0;
7241                         rsurface.modelvertex3f_bufferoffset = 0;
7242                         rsurface.modelsvector3f_vertexbuffer = 0;
7243                         rsurface.modelsvector3f_bufferoffset = 0;
7244                         rsurface.modeltvector3f_vertexbuffer = 0;
7245                         rsurface.modeltvector3f_bufferoffset = 0;
7246                         rsurface.modelnormal3f_vertexbuffer = 0;
7247                         rsurface.modelnormal3f_bufferoffset = 0;
7248                 }
7249                 else
7250                 {
7251                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7252                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7253                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7254                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7255                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7256                         rsurface.modelsvector3f = NULL;
7257                         rsurface.modeltvector3f = NULL;
7258                         rsurface.modelnormal3f = NULL;
7259                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL);
7260                         rsurface.modelvertexmesh = NULL;
7261                         rsurface.modelvertexmesh_vertexbuffer = NULL;
7262                         rsurface.modelvertexmesh_bufferoffset = 0;
7263                         rsurface.modelvertex3f_vertexbuffer = NULL;
7264                         rsurface.modelvertex3f_bufferoffset = 0;
7265                         rsurface.modelvertex3f_vertexbuffer = 0;
7266                         rsurface.modelvertex3f_bufferoffset = 0;
7267                         rsurface.modelsvector3f_vertexbuffer = 0;
7268                         rsurface.modelsvector3f_bufferoffset = 0;
7269                         rsurface.modeltvector3f_vertexbuffer = 0;
7270                         rsurface.modeltvector3f_bufferoffset = 0;
7271                         rsurface.modelnormal3f_vertexbuffer = 0;
7272                         rsurface.modelnormal3f_bufferoffset = 0;
7273                 }
7274                 rsurface.modelgeneratedvertex = true;
7275         }
7276         else
7277         {
7278                 if (rsurface.entityskeletaltransform3x4)
7279                 {
7280                         r_refdef.stats[r_stat_batch_entityskeletal_count]++;
7281                         r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
7282                         r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
7283                         r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
7284                 }
7285                 else
7286                 {
7287                         r_refdef.stats[r_stat_batch_entitystatic_count]++;
7288                         r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
7289                         r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
7290                         r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
7291                 }
7292                 rsurface.modelvertex3f  = model->surfmesh.data_vertex3f;
7293                 rsurface.modelvertex3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7294                 rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f;
7295                 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
7296                 rsurface.modelsvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7297                 rsurface.modelsvector3f_bufferoffset = model->surfmesh.vbooffset_svector3f;
7298                 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
7299                 rsurface.modeltvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7300                 rsurface.modeltvector3f_bufferoffset = model->surfmesh.vbooffset_tvector3f;
7301                 rsurface.modelnormal3f  = model->surfmesh.data_normal3f;
7302                 rsurface.modelnormal3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7303                 rsurface.modelnormal3f_bufferoffset = model->surfmesh.vbooffset_normal3f;
7304                 rsurface.modelvertexmesh = model->surfmesh.data_vertexmesh;
7305                 rsurface.modelvertexmesh_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7306                 rsurface.modelvertexmesh_bufferoffset = model->surfmesh.vbooffset_vertex3f;
7307                 rsurface.modelgeneratedvertex = false;
7308         }
7309         rsurface.modellightmapcolor4f  = model->surfmesh.data_lightmapcolor4f;
7310         rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7311         rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.vbooffset_lightmapcolor4f;
7312         rsurface.modeltexcoordtexture2f  = model->surfmesh.data_texcoordtexture2f;
7313         rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7314         rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.vbooffset_texcoordtexture2f;
7315         rsurface.modeltexcoordlightmap2f  = model->surfmesh.data_texcoordlightmap2f;
7316         rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7317         rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f;
7318         rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
7319         rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7320         rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.vbooffset_skeletalindex4ub;
7321         rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
7322         rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7323         rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.vbooffset_skeletalweight4ub;
7324         rsurface.modelelement3i = model->surfmesh.data_element3i;
7325         rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
7326         rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
7327         rsurface.modelelement3s = model->surfmesh.data_element3s;
7328         rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
7329         rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
7330         rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
7331         rsurface.modelnumvertices = model->surfmesh.num_vertices;
7332         rsurface.modelnumtriangles = model->surfmesh.num_triangles;
7333         rsurface.modelsurfaces = model->data_surfaces;
7334         rsurface.batchgeneratedvertex = false;
7335         rsurface.batchfirstvertex = 0;
7336         rsurface.batchnumvertices = 0;
7337         rsurface.batchfirsttriangle = 0;
7338         rsurface.batchnumtriangles = 0;
7339         rsurface.batchvertex3f  = NULL;
7340         rsurface.batchvertex3f_vertexbuffer = NULL;
7341         rsurface.batchvertex3f_bufferoffset = 0;
7342         rsurface.batchsvector3f = NULL;
7343         rsurface.batchsvector3f_vertexbuffer = NULL;
7344         rsurface.batchsvector3f_bufferoffset = 0;
7345         rsurface.batchtvector3f = NULL;
7346         rsurface.batchtvector3f_vertexbuffer = NULL;
7347         rsurface.batchtvector3f_bufferoffset = 0;
7348         rsurface.batchnormal3f  = NULL;
7349         rsurface.batchnormal3f_vertexbuffer = NULL;
7350         rsurface.batchnormal3f_bufferoffset = 0;
7351         rsurface.batchlightmapcolor4f = NULL;
7352         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7353         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7354         rsurface.batchtexcoordtexture2f = NULL;
7355         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7356         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7357         rsurface.batchtexcoordlightmap2f = NULL;
7358         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7359         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7360         rsurface.batchskeletalindex4ub = NULL;
7361         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7362         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7363         rsurface.batchskeletalweight4ub = NULL;
7364         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7365         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7366         rsurface.batchvertexmesh = NULL;
7367         rsurface.batchvertexmesh_vertexbuffer = NULL;
7368         rsurface.batchvertexmesh_bufferoffset = 0;
7369         rsurface.batchelement3i = NULL;
7370         rsurface.batchelement3i_indexbuffer = NULL;
7371         rsurface.batchelement3i_bufferoffset = 0;
7372         rsurface.batchelement3s = NULL;
7373         rsurface.batchelement3s_indexbuffer = NULL;
7374         rsurface.batchelement3s_bufferoffset = 0;
7375         rsurface.forcecurrenttextureupdate = false;
7376 }
7377
7378 void RSurf_ActiveCustomEntity(const matrix4x4_t *matrix, const matrix4x4_t *inversematrix, int entflags, double shadertime, float r, float g, float b, float a, int numvertices, const float *vertex3f, const float *texcoord2f, const float *normal3f, const float *svector3f, const float *tvector3f, const float *color4f, int numtriangles, const int *element3i, const unsigned short *element3s, qboolean wantnormals, qboolean wanttangents)
7379 {
7380         rsurface.entity = r_refdef.scene.worldentity;
7381         rsurface.skeleton = NULL;
7382         rsurface.ent_skinnum = 0;
7383         rsurface.ent_qwskin = -1;
7384         rsurface.ent_flags = entflags;
7385         rsurface.shadertime = r_refdef.scene.time - shadertime;
7386         rsurface.modelnumvertices = numvertices;
7387         rsurface.modelnumtriangles = numtriangles;
7388         rsurface.matrix = *matrix;
7389         rsurface.inversematrix = *inversematrix;
7390         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7391         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7392         R_EntityMatrix(&rsurface.matrix);
7393         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7394         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7395         rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
7396         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7397         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7398         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7399         memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
7400         rsurface.frameblend[0].lerp = 1;
7401         rsurface.ent_alttextures = false;
7402         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7403         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7404         rsurface.entityskeletaltransform3x4 = NULL;
7405         rsurface.entityskeletaltransform3x4buffer = NULL;
7406         rsurface.entityskeletaltransform3x4offset = 0;
7407         rsurface.entityskeletaltransform3x4size = 0;
7408         rsurface.entityskeletalnumtransforms = 0;
7409         r_refdef.stats[r_stat_batch_entitycustom_count]++;
7410         r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
7411         r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
7412         r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
7413         if (wanttangents)
7414         {
7415                 rsurface.modelvertex3f = (float *)vertex3f;
7416                 rsurface.modelsvector3f = svector3f ? (float *)svector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7417                 rsurface.modeltvector3f = tvector3f ? (float *)tvector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7418                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7419         }
7420         else if (wantnormals)
7421         {
7422                 rsurface.modelvertex3f = (float *)vertex3f;
7423                 rsurface.modelsvector3f = NULL;
7424                 rsurface.modeltvector3f = NULL;
7425                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7426         }
7427         else
7428         {
7429                 rsurface.modelvertex3f = (float *)vertex3f;
7430                 rsurface.modelsvector3f = NULL;
7431                 rsurface.modeltvector3f = NULL;
7432                 rsurface.modelnormal3f = NULL;
7433         }
7434         rsurface.modelvertexmesh = NULL;
7435         rsurface.modelvertexmesh_vertexbuffer = NULL;
7436         rsurface.modelvertexmesh_bufferoffset = 0;
7437         rsurface.modelvertex3f_vertexbuffer = 0;
7438         rsurface.modelvertex3f_bufferoffset = 0;
7439         rsurface.modelsvector3f_vertexbuffer = 0;
7440         rsurface.modelsvector3f_bufferoffset = 0;
7441         rsurface.modeltvector3f_vertexbuffer = 0;
7442         rsurface.modeltvector3f_bufferoffset = 0;
7443         rsurface.modelnormal3f_vertexbuffer = 0;
7444         rsurface.modelnormal3f_bufferoffset = 0;
7445         rsurface.modelgeneratedvertex = true;
7446         rsurface.modellightmapcolor4f  = (float *)color4f;
7447         rsurface.modellightmapcolor4f_vertexbuffer = 0;
7448         rsurface.modellightmapcolor4f_bufferoffset = 0;
7449         rsurface.modeltexcoordtexture2f  = (float *)texcoord2f;
7450         rsurface.modeltexcoordtexture2f_vertexbuffer = 0;
7451         rsurface.modeltexcoordtexture2f_bufferoffset = 0;
7452         rsurface.modeltexcoordlightmap2f  = NULL;
7453         rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
7454         rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
7455         rsurface.modelskeletalindex4ub = NULL;
7456         rsurface.modelskeletalindex4ub_vertexbuffer = NULL;
7457         rsurface.modelskeletalindex4ub_bufferoffset = 0;
7458         rsurface.modelskeletalweight4ub = NULL;
7459         rsurface.modelskeletalweight4ub_vertexbuffer = NULL;
7460         rsurface.modelskeletalweight4ub_bufferoffset = 0;
7461         rsurface.modelelement3i = (int *)element3i;
7462         rsurface.modelelement3i_indexbuffer = NULL;
7463         rsurface.modelelement3i_bufferoffset = 0;
7464         rsurface.modelelement3s = (unsigned short *)element3s;
7465         rsurface.modelelement3s_indexbuffer = NULL;
7466         rsurface.modelelement3s_bufferoffset = 0;
7467         rsurface.modellightmapoffsets = NULL;
7468         rsurface.modelsurfaces = NULL;
7469         rsurface.batchgeneratedvertex = false;
7470         rsurface.batchfirstvertex = 0;
7471         rsurface.batchnumvertices = 0;
7472         rsurface.batchfirsttriangle = 0;
7473         rsurface.batchnumtriangles = 0;
7474         rsurface.batchvertex3f  = NULL;
7475         rsurface.batchvertex3f_vertexbuffer = NULL;
7476         rsurface.batchvertex3f_bufferoffset = 0;
7477         rsurface.batchsvector3f = NULL;
7478         rsurface.batchsvector3f_vertexbuffer = NULL;
7479         rsurface.batchsvector3f_bufferoffset = 0;
7480         rsurface.batchtvector3f = NULL;
7481         rsurface.batchtvector3f_vertexbuffer = NULL;
7482         rsurface.batchtvector3f_bufferoffset = 0;
7483         rsurface.batchnormal3f  = NULL;
7484         rsurface.batchnormal3f_vertexbuffer = NULL;
7485         rsurface.batchnormal3f_bufferoffset = 0;
7486         rsurface.batchlightmapcolor4f = NULL;
7487         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7488         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7489         rsurface.batchtexcoordtexture2f = NULL;
7490         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7491         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7492         rsurface.batchtexcoordlightmap2f = NULL;
7493         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7494         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7495         rsurface.batchskeletalindex4ub = NULL;
7496         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7497         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7498         rsurface.batchskeletalweight4ub = NULL;
7499         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7500         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7501         rsurface.batchvertexmesh = NULL;
7502         rsurface.batchvertexmesh_vertexbuffer = NULL;
7503         rsurface.batchvertexmesh_bufferoffset = 0;
7504         rsurface.batchelement3i = NULL;
7505         rsurface.batchelement3i_indexbuffer = NULL;
7506         rsurface.batchelement3i_bufferoffset = 0;
7507         rsurface.batchelement3s = NULL;
7508         rsurface.batchelement3s_indexbuffer = NULL;
7509         rsurface.batchelement3s_bufferoffset = 0;
7510         rsurface.forcecurrenttextureupdate = true;
7511
7512         if (rsurface.modelnumvertices && rsurface.modelelement3i)
7513         {
7514                 if ((wantnormals || wanttangents) && !normal3f)
7515                 {
7516                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7517                         Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
7518                 }
7519                 if (wanttangents && !svector3f)
7520                 {
7521                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7522                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7523                         Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.modelsvector3f, rsurface.modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
7524                 }
7525         }
7526 }
7527
7528 float RSurf_FogPoint(const float *v)
7529 {
7530         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7531         float FogPlaneViewDist = r_refdef.fogplaneviewdist;
7532         float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3];
7533         float FogHeightFade = r_refdef.fogheightfade;
7534         float fogfrac;
7535         unsigned int fogmasktableindex;
7536         if (r_refdef.fogplaneviewabove)
7537                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7538         else
7539                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7540         fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier);
7541         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7542 }
7543
7544 float RSurf_FogVertex(const float *v)
7545 {
7546         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7547         float FogPlaneViewDist = rsurface.fogplaneviewdist;
7548         float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3];
7549         float FogHeightFade = rsurface.fogheightfade;
7550         float fogfrac;
7551         unsigned int fogmasktableindex;
7552         if (r_refdef.fogplaneviewabove)
7553                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7554         else
7555                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7556         fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.fogmasktabledistmultiplier);
7557         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7558 }
7559
7560 static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
7561 {
7562         int i;
7563         for (i = 0;i < numelements;i++)
7564                 outelement3i[i] = inelement3i[i] + adjust;
7565 }
7566
7567 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
7568 extern cvar_t gl_vbo;
7569 void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist)
7570 {
7571         int deformindex;
7572         int firsttriangle;
7573         int numtriangles;
7574         int firstvertex;
7575         int endvertex;
7576         int numvertices;
7577         int surfacefirsttriangle;
7578         int surfacenumtriangles;
7579         int surfacefirstvertex;
7580         int surfaceendvertex;
7581         int surfacenumvertices;
7582         int batchnumsurfaces = texturenumsurfaces;
7583         int batchnumvertices;
7584         int batchnumtriangles;
7585         int needsupdate;
7586         int i, j;
7587         qboolean gaps;
7588         qboolean dynamicvertex;
7589         float amplitude;
7590         float animpos;
7591         float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
7592         float waveparms[4];
7593         unsigned char *ub;
7594         q3shaderinfo_deform_t *deform;
7595         const msurface_t *surface, *firstsurface;
7596         r_vertexmesh_t *vertexmesh;
7597         if (!texturenumsurfaces)
7598                 return;
7599         // find vertex range of this surface batch
7600         gaps = false;
7601         firstsurface = texturesurfacelist[0];
7602         firsttriangle = firstsurface->num_firsttriangle;
7603         batchnumvertices = 0;
7604         batchnumtriangles = 0;
7605         firstvertex = endvertex = firstsurface->num_firstvertex;
7606         for (i = 0;i < texturenumsurfaces;i++)
7607         {
7608                 surface = texturesurfacelist[i];
7609                 if (surface != firstsurface + i)
7610                         gaps = true;
7611                 surfacefirstvertex = surface->num_firstvertex;
7612                 surfaceendvertex = surfacefirstvertex + surface->num_vertices;
7613                 surfacenumvertices = surface->num_vertices;
7614                 surfacenumtriangles = surface->num_triangles;
7615                 if (firstvertex > surfacefirstvertex)
7616                         firstvertex = surfacefirstvertex;
7617                 if (endvertex < surfaceendvertex)
7618                         endvertex = surfaceendvertex;
7619                 batchnumvertices += surfacenumvertices;
7620                 batchnumtriangles += surfacenumtriangles;
7621         }
7622
7623         r_refdef.stats[r_stat_batch_batches]++;
7624         if (gaps)
7625                 r_refdef.stats[r_stat_batch_withgaps]++;
7626         r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces;
7627         r_refdef.stats[r_stat_batch_vertices] += batchnumvertices;
7628         r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles;
7629
7630         // we now know the vertex range used, and if there are any gaps in it
7631         rsurface.batchfirstvertex = firstvertex;
7632         rsurface.batchnumvertices = endvertex - firstvertex;
7633         rsurface.batchfirsttriangle = firsttriangle;
7634         rsurface.batchnumtriangles = batchnumtriangles;
7635
7636         // this variable holds flags for which properties have been updated that
7637         // may require regenerating vertexmesh array...
7638         needsupdate = 0;
7639
7640         // check if any dynamic vertex processing must occur
7641         dynamicvertex = false;
7642
7643         // a cvar to force the dynamic vertex path to be taken, for debugging
7644         if (r_batch_debugdynamicvertexpath.integer)
7645         {
7646                 if (!dynamicvertex)
7647                 {
7648                         r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1;
7649                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces;
7650                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices;
7651                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles;
7652                 }
7653                 dynamicvertex = true;
7654         }
7655
7656         // if there is a chance of animated vertex colors, it's a dynamic batch
7657         if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_ARRAY_VERTEXCOLOR)) && texturesurfacelist[0]->lightmapinfo)
7658         {
7659                 if (!dynamicvertex)
7660                 {
7661                         r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1;
7662                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces;
7663                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices;
7664                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles;
7665                 }
7666                 dynamicvertex = true;
7667                 needsupdate |= BATCHNEED_VERTEXMESH_VERTEXCOLOR;
7668         }
7669
7670         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
7671         {
7672                 switch (deform->deform)
7673                 {
7674                 default:
7675                 case Q3DEFORM_PROJECTIONSHADOW:
7676                 case Q3DEFORM_TEXT0:
7677                 case Q3DEFORM_TEXT1:
7678                 case Q3DEFORM_TEXT2:
7679                 case Q3DEFORM_TEXT3:
7680                 case Q3DEFORM_TEXT4:
7681                 case Q3DEFORM_TEXT5:
7682                 case Q3DEFORM_TEXT6:
7683                 case Q3DEFORM_TEXT7:
7684                 case Q3DEFORM_NONE:
7685                         break;
7686                 case Q3DEFORM_AUTOSPRITE:
7687                         if (!dynamicvertex)
7688                         {
7689                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1;
7690                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces;
7691                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices;
7692                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles;
7693                         }
7694                         dynamicvertex = true;
7695                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD;
7696                         needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7697                         break;
7698                 case Q3DEFORM_AUTOSPRITE2:
7699                         if (!dynamicvertex)
7700                         {
7701                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1;
7702                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces;
7703                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices;
7704                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles;
7705                         }
7706                         dynamicvertex = true;
7707                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7708                         needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7709                         break;
7710                 case Q3DEFORM_NORMAL:
7711                         if (!dynamicvertex)
7712                         {
7713                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1;
7714                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces;
7715                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices;
7716                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles;
7717                         }
7718                         dynamicvertex = true;
7719                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7720                         needsupdate |= BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7721                         break;
7722                 case Q3DEFORM_WAVE:
7723                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7724                                 break; // if wavefunc is a nop, ignore this transform
7725                         if (!dynamicvertex)
7726                         {
7727                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_wave] += 1;
7728                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces;
7729                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices;
7730                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles;
7731                         }
7732                         dynamicvertex = true;
7733                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7734                         needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7735                         break;
7736                 case Q3DEFORM_BULGE:
7737                         if (!dynamicvertex)
7738                         {
7739                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1;
7740                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces;
7741                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices;
7742                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles;
7743                         }
7744                         dynamicvertex = true;
7745                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7746                         needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7747                         break;
7748                 case Q3DEFORM_MOVE:
7749                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7750                                 break; // if wavefunc is a nop, ignore this transform
7751                         if (!dynamicvertex)
7752                         {
7753                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1;
7754                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces;
7755                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices;
7756                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles;
7757                         }
7758                         dynamicvertex = true;
7759                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7760                         needsupdate |= BATCHNEED_VERTEXMESH_VERTEX;
7761                         break;
7762                 }
7763         }
7764         if (rsurface.texture->materialshaderpass)
7765         {
7766                 switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
7767                 {
7768                 default:
7769                 case Q3TCGEN_TEXTURE:
7770                         break;
7771                 case Q3TCGEN_LIGHTMAP:
7772                         if (!dynamicvertex)
7773                         {
7774                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
7775                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
7776                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
7777                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
7778                         }
7779                         dynamicvertex = true;
7780                         batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7781                         needsupdate |= BATCHNEED_VERTEXMESH_LIGHTMAP;
7782                         break;
7783                 case Q3TCGEN_VECTOR:
7784                         if (!dynamicvertex)
7785                         {
7786                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
7787                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
7788                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
7789                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
7790                         }
7791                         dynamicvertex = true;
7792                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7793                         needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
7794                         break;
7795                 case Q3TCGEN_ENVIRONMENT:
7796                         if (!dynamicvertex)
7797                         {
7798                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
7799                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
7800                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
7801                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
7802                         }
7803                         dynamicvertex = true;
7804                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
7805                         needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
7806                         break;
7807                 }
7808                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
7809                 {
7810                         if (!dynamicvertex)
7811                         {
7812                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
7813                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
7814                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
7815                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
7816                         }
7817                         dynamicvertex = true;
7818                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7819                         needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
7820                 }
7821         }
7822
7823         if (!rsurface.modelvertexmesh && (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)))
7824         {
7825                 if (!dynamicvertex)
7826                 {
7827                         r_refdef.stats[r_stat_batch_dynamic_batches_because_interleavedarrays] += 1;
7828                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_interleavedarrays] += batchnumsurfaces;
7829                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_interleavedarrays] += batchnumvertices;
7830                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_interleavedarrays] += batchnumtriangles;
7831                 }
7832                 dynamicvertex = true;
7833                 needsupdate |= (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP));
7834         }
7835
7836         // when the model data has no vertex buffer (dynamic mesh), we need to
7837         // eliminate gaps
7838         if (vid.useinterleavedarrays && !rsurface.modelvertexmesh_vertexbuffer)
7839                 batchneed |= BATCHNEED_NOGAPS;
7840
7841         // the caller can specify BATCHNEED_NOGAPS to force a batch with
7842         // firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex),
7843         // we ensure this by treating the vertex batch as dynamic...
7844         if ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0))
7845         {
7846                 if (!dynamicvertex)
7847                 {
7848                         r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1;
7849                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces;
7850                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices;
7851                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles;
7852                 }
7853                 dynamicvertex = true;
7854         }
7855
7856         if (dynamicvertex)
7857         {
7858                 // when copying, we need to consider the regeneration of vertexmesh, any dependencies it may have must be set...
7859                 if (batchneed & BATCHNEED_VERTEXMESH_VERTEX)      batchneed |= BATCHNEED_ARRAY_VERTEX;
7860                 if (batchneed & BATCHNEED_VERTEXMESH_NORMAL)      batchneed |= BATCHNEED_ARRAY_NORMAL;
7861                 if (batchneed & BATCHNEED_VERTEXMESH_VECTOR)      batchneed |= BATCHNEED_ARRAY_VECTOR;
7862                 if (batchneed & BATCHNEED_VERTEXMESH_VERTEXCOLOR) batchneed |= BATCHNEED_ARRAY_VERTEXCOLOR;
7863                 if (batchneed & BATCHNEED_VERTEXMESH_TEXCOORD)    batchneed |= BATCHNEED_ARRAY_TEXCOORD;
7864                 if (batchneed & BATCHNEED_VERTEXMESH_LIGHTMAP)    batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7865                 if (batchneed & BATCHNEED_VERTEXMESH_SKELETAL)    batchneed |= BATCHNEED_ARRAY_SKELETAL;
7866         }
7867
7868         // if needsupdate, we have to do a dynamic vertex batch for sure
7869         if (needsupdate & batchneed)
7870         {
7871                 if (!dynamicvertex)
7872                 {
7873                         r_refdef.stats[r_stat_batch_dynamic_batches_because_derived] += 1;
7874                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_derived] += batchnumsurfaces;
7875                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_derived] += batchnumvertices;
7876                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_derived] += batchnumtriangles;
7877                 }
7878                 dynamicvertex = true;
7879         }
7880
7881         // see if we need to build vertexmesh from arrays
7882         if (!rsurface.modelvertexmesh && (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)))
7883         {
7884                 if (!dynamicvertex)
7885                 {
7886                         r_refdef.stats[r_stat_batch_dynamic_batches_because_interleavedarrays] += 1;
7887                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_interleavedarrays] += batchnumsurfaces;
7888                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_interleavedarrays] += batchnumvertices;
7889                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_interleavedarrays] += batchnumtriangles;
7890                 }
7891                 dynamicvertex = true;
7892         }
7893
7894         // if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data
7895         if (dynamicvertex && rsurface.entityskeletaltransform3x4)
7896                 batchneed |= BATCHNEED_ARRAY_SKELETAL;
7897
7898         rsurface.batchvertex3f = rsurface.modelvertex3f;
7899         rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer;
7900         rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
7901         rsurface.batchsvector3f = rsurface.modelsvector3f;
7902         rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer;
7903         rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
7904         rsurface.batchtvector3f = rsurface.modeltvector3f;
7905         rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer;
7906         rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
7907         rsurface.batchnormal3f = rsurface.modelnormal3f;
7908         rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer;
7909         rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
7910         rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f;
7911         rsurface.batchlightmapcolor4f_vertexbuffer  = rsurface.modellightmapcolor4f_vertexbuffer;
7912         rsurface.batchlightmapcolor4f_bufferoffset  = rsurface.modellightmapcolor4f_bufferoffset;
7913         rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f;
7914         rsurface.batchtexcoordtexture2f_vertexbuffer  = rsurface.modeltexcoordtexture2f_vertexbuffer;
7915         rsurface.batchtexcoordtexture2f_bufferoffset  = rsurface.modeltexcoordtexture2f_bufferoffset;
7916         rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
7917         rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer;
7918         rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
7919         rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub;
7920         rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer;
7921         rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset;
7922         rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub;
7923         rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer;
7924         rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset;
7925         rsurface.batchvertexmesh = rsurface.modelvertexmesh;
7926         rsurface.batchvertexmesh_vertexbuffer = rsurface.modelvertexmesh_vertexbuffer;
7927         rsurface.batchvertexmesh_bufferoffset = rsurface.modelvertexmesh_bufferoffset;
7928         rsurface.batchelement3i = rsurface.modelelement3i;
7929         rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer;
7930         rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset;
7931         rsurface.batchelement3s = rsurface.modelelement3s;
7932         rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer;
7933         rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset;
7934         rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4;
7935         rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer;
7936         rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset;
7937         rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size;
7938         rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms;
7939
7940         // if any dynamic vertex processing has to occur in software, we copy the
7941         // entire surface list together before processing to rebase the vertices
7942         // to start at 0 (otherwise we waste a lot of room in a vertex buffer).
7943         //
7944         // if any gaps exist and we do not have a static vertex buffer, we have to
7945         // copy the surface list together to avoid wasting upload bandwidth on the
7946         // vertices in the gaps.
7947         //
7948         // if gaps exist and we have a static vertex buffer, we can choose whether
7949         // to combine the index buffer ranges into one dynamic index buffer or
7950         // simply issue multiple glDrawElements calls (BATCHNEED_ALLOWMULTIDRAW).
7951         //
7952         // in many cases the batch is reduced to one draw call.
7953
7954         rsurface.batchmultidraw = false;
7955         rsurface.batchmultidrawnumsurfaces = 0;
7956         rsurface.batchmultidrawsurfacelist = NULL;
7957
7958         if (!dynamicvertex)
7959         {
7960                 // static vertex data, just set pointers...
7961                 rsurface.batchgeneratedvertex = false;
7962                 // if there are gaps, we want to build a combined index buffer,
7963                 // otherwise use the original static buffer with an appropriate offset
7964                 if (gaps)
7965                 {
7966                         r_refdef.stats[r_stat_batch_copytriangles_batches] += 1;
7967                         r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces;
7968                         r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices;
7969                         r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles;
7970                         if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer)
7971                         {
7972                                 rsurface.batchmultidraw = true;
7973                                 rsurface.batchmultidrawnumsurfaces = texturenumsurfaces;
7974                                 rsurface.batchmultidrawsurfacelist = texturesurfacelist;
7975                                 return;
7976                         }
7977                         // build a new triangle elements array for this batch
7978                         rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7979                         rsurface.batchfirsttriangle = 0;
7980                         numtriangles = 0;
7981                         for (i = 0;i < texturenumsurfaces;i++)
7982                         {
7983                                 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7984                                 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7985                                 memcpy(rsurface.batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3]));
7986                                 numtriangles += surfacenumtriangles;
7987                         }
7988                         rsurface.batchelement3i_indexbuffer = NULL;
7989                         rsurface.batchelement3i_bufferoffset = 0;
7990                         rsurface.batchelement3s = NULL;
7991                         rsurface.batchelement3s_indexbuffer = NULL;
7992                         rsurface.batchelement3s_bufferoffset = 0;
7993                         if (endvertex <= 65536)
7994                         {
7995                                 // make a 16bit (unsigned short) index array if possible
7996                                 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7997                                 for (i = 0;i < numtriangles*3;i++)
7998                                         rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7999                         }
8000                         // upload buffer data for the copytriangles batch
8001                         if (((r_batch_dynamicbuffer.integer || gl_vbo_dynamicindex.integer) && vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo)
8002                         {
8003                                 if (rsurface.batchelement3s)
8004                                         rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
8005                                 else if (rsurface.batchelement3i)
8006                                         rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
8007                         }
8008                 }
8009                 else
8010                 {
8011                         r_refdef.stats[r_stat_batch_fast_batches] += 1;
8012                         r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces;
8013                         r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices;
8014                         r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles;
8015                 }
8016                 return;
8017         }
8018
8019         // something needs software processing, do it for real...
8020         // we only directly handle separate array data in this case and then
8021         // generate interleaved data if needed...
8022         rsurface.batchgeneratedvertex = true;
8023         r_refdef.stats[r_stat_batch_dynamic_batches] += 1;
8024         r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces;
8025         r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices;
8026         r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles;
8027
8028         // now copy the vertex data into a combined array and make an index array
8029         // (this is what Quake3 does all the time)
8030         // we also apply any skeletal animation here that would have been done in
8031         // the vertex shader, because most of the dynamic vertex animation cases
8032         // need actual vertex positions and normals
8033         //if (dynamicvertex)
8034         {
8035                 rsurface.batchvertexmesh = NULL;
8036                 rsurface.batchvertexmesh_vertexbuffer = NULL;
8037                 rsurface.batchvertexmesh_bufferoffset = 0;
8038                 rsurface.batchvertex3f = NULL;
8039                 rsurface.batchvertex3f_vertexbuffer = NULL;
8040                 rsurface.batchvertex3f_bufferoffset = 0;
8041                 rsurface.batchsvector3f = NULL;
8042                 rsurface.batchsvector3f_vertexbuffer = NULL;
8043                 rsurface.batchsvector3f_bufferoffset = 0;
8044                 rsurface.batchtvector3f = NULL;
8045                 rsurface.batchtvector3f_vertexbuffer = NULL;
8046                 rsurface.batchtvector3f_bufferoffset = 0;
8047                 rsurface.batchnormal3f = NULL;
8048                 rsurface.batchnormal3f_vertexbuffer = NULL;
8049                 rsurface.batchnormal3f_bufferoffset = 0;
8050                 rsurface.batchlightmapcolor4f = NULL;
8051                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8052                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8053                 rsurface.batchtexcoordtexture2f = NULL;
8054                 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8055                 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8056                 rsurface.batchtexcoordlightmap2f = NULL;
8057                 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
8058                 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
8059                 rsurface.batchskeletalindex4ub = NULL;
8060                 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
8061                 rsurface.batchskeletalindex4ub_bufferoffset = 0;
8062                 rsurface.batchskeletalweight4ub = NULL;
8063                 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
8064                 rsurface.batchskeletalweight4ub_bufferoffset = 0;
8065                 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
8066                 rsurface.batchelement3i_indexbuffer = NULL;
8067                 rsurface.batchelement3i_bufferoffset = 0;
8068                 rsurface.batchelement3s = NULL;
8069                 rsurface.batchelement3s_indexbuffer = NULL;
8070                 rsurface.batchelement3s_bufferoffset = 0;
8071                 rsurface.batchskeletaltransform3x4buffer = NULL;
8072                 rsurface.batchskeletaltransform3x4offset = 0;
8073                 rsurface.batchskeletaltransform3x4size = 0;
8074                 // we'll only be setting up certain arrays as needed
8075                 if (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP))
8076                         rsurface.batchvertexmesh = (r_vertexmesh_t *)R_FrameData_Alloc(batchnumvertices * sizeof(r_vertexmesh_t));
8077                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
8078                         rsurface.batchvertex3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8079                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
8080                         rsurface.batchnormal3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8081                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
8082                 {
8083                         rsurface.batchsvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8084                         rsurface.batchtvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8085                 }
8086                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
8087                         rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8088                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
8089                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8090                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
8091                         rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8092                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
8093                 {
8094                         rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
8095                         rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
8096                 }
8097                 numvertices = 0;
8098                 numtriangles = 0;
8099                 for (i = 0;i < texturenumsurfaces;i++)
8100                 {
8101                         surfacefirstvertex = texturesurfacelist[i]->num_firstvertex;
8102                         surfacenumvertices = texturesurfacelist[i]->num_vertices;
8103                         surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
8104                         surfacenumtriangles = texturesurfacelist[i]->num_triangles;
8105                         // copy only the data requested
8106                         if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)) && rsurface.modelvertexmesh)
8107                                 memcpy(rsurface.batchvertexmesh + numvertices, rsurface.modelvertexmesh + surfacefirstvertex, surfacenumvertices * sizeof(rsurface.batchvertexmesh[0]));
8108                         if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
8109                         {
8110                                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
8111                                 {
8112                                         if (rsurface.batchvertex3f)
8113                                                 memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8114                                         else
8115                                                 memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8116                                 }
8117                                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
8118                                 {
8119                                         if (rsurface.modelnormal3f)
8120                                                 memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8121                                         else
8122                                                 memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8123                                 }
8124                                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
8125                                 {
8126                                         if (rsurface.modelsvector3f)
8127                                         {
8128                                                 memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8129                                                 memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8130                                         }
8131                                         else
8132                                         {
8133                                                 memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8134                                                 memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8135                                         }
8136                                 }
8137                                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
8138                                 {
8139                                         if (rsurface.modellightmapcolor4f)
8140                                                 memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
8141                                         else
8142                                                 memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4]));
8143                                 }
8144                                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
8145                                 {
8146                                         if (rsurface.modeltexcoordtexture2f)
8147                                                 memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
8148                                         else
8149                                                 memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
8150                                 }
8151                                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
8152                                 {
8153                                         if (rsurface.modeltexcoordlightmap2f)
8154                                                 memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
8155                                         else
8156                                                 memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
8157                                 }
8158                                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
8159                                 {
8160                                         if (rsurface.modelskeletalindex4ub)
8161                                         {
8162                                                 memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
8163                                                 memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
8164                                         }
8165                                         else
8166                                         {
8167                                                 memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
8168                                                 memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
8169                                                 ub = rsurface.batchskeletalweight4ub + 4*numvertices;
8170                                                 for (j = 0;j < surfacenumvertices;j++)
8171                                                         ub[j*4] = 255;
8172                                         }
8173                                 }
8174                         }
8175                         RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
8176                         numvertices += surfacenumvertices;
8177                         numtriangles += surfacenumtriangles;
8178                 }
8179
8180                 // generate a 16bit index array as well if possible
8181                 // (in general, dynamic batches fit)
8182                 if (numvertices <= 65536)
8183                 {
8184                         rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
8185                         for (i = 0;i < numtriangles*3;i++)
8186                                 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
8187                 }
8188
8189                 // since we've copied everything, the batch now starts at 0
8190                 rsurface.batchfirstvertex = 0;
8191                 rsurface.batchnumvertices = batchnumvertices;
8192                 rsurface.batchfirsttriangle = 0;
8193                 rsurface.batchnumtriangles = batchnumtriangles;
8194         }
8195
8196         // apply skeletal animation that would have been done in the vertex shader
8197         if (rsurface.batchskeletaltransform3x4)
8198         {
8199                 const unsigned char *si;
8200                 const unsigned char *sw;
8201                 const float *t[4];
8202                 const float *b = rsurface.batchskeletaltransform3x4;
8203                 float *vp, *vs, *vt, *vn;
8204                 float w[4];
8205                 float m[3][4], n[3][4];
8206                 float tp[3], ts[3], tt[3], tn[3];
8207                 r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1;
8208                 r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces;
8209                 r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices;
8210                 r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles;
8211                 si = rsurface.batchskeletalindex4ub;
8212                 sw = rsurface.batchskeletalweight4ub;
8213                 vp = rsurface.batchvertex3f;
8214                 vs = rsurface.batchsvector3f;
8215                 vt = rsurface.batchtvector3f;
8216                 vn = rsurface.batchnormal3f;
8217                 memset(m[0], 0, sizeof(m));
8218                 memset(n[0], 0, sizeof(n));
8219                 for (i = 0;i < batchnumvertices;i++)
8220                 {
8221                         t[0] = b + si[0]*12;
8222                         if (sw[0] == 255)
8223                         {
8224                                 // common case - only one matrix
8225                                 m[0][0] = t[0][ 0];
8226                                 m[0][1] = t[0][ 1];
8227                                 m[0][2] = t[0][ 2];
8228                                 m[0][3] = t[0][ 3];
8229                                 m[1][0] = t[0][ 4];
8230                                 m[1][1] = t[0][ 5];
8231                                 m[1][2] = t[0][ 6];
8232                                 m[1][3] = t[0][ 7];
8233                                 m[2][0] = t[0][ 8];
8234                                 m[2][1] = t[0][ 9];
8235                                 m[2][2] = t[0][10];
8236                                 m[2][3] = t[0][11];
8237                         }
8238                         else if (sw[2] + sw[3])
8239                         {
8240                                 // blend 4 matrices
8241                                 t[1] = b + si[1]*12;
8242                                 t[2] = b + si[2]*12;
8243                                 t[3] = b + si[3]*12;
8244                                 w[0] = sw[0] * (1.0f / 255.0f);
8245                                 w[1] = sw[1] * (1.0f / 255.0f);
8246                                 w[2] = sw[2] * (1.0f / 255.0f);
8247                                 w[3] = sw[3] * (1.0f / 255.0f);
8248                                 // blend the matrices
8249                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3];
8250                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3];
8251                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3];
8252                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3];
8253                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3];
8254                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3];
8255                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3];
8256                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3];
8257                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3];
8258                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3];
8259                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3];
8260                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3];
8261                         }
8262                         else
8263                         {
8264                                 // blend 2 matrices
8265                                 t[1] = b + si[1]*12;
8266                                 w[0] = sw[0] * (1.0f / 255.0f);
8267                                 w[1] = sw[1] * (1.0f / 255.0f);
8268                                 // blend the matrices
8269                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1];
8270                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1];
8271                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1];
8272                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1];
8273                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1];
8274                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1];
8275                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1];
8276                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1];
8277                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1];
8278                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1];
8279                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1];
8280                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1];
8281                         }
8282                         si += 4;
8283                         sw += 4;
8284                         // modify the vertex
8285                         VectorCopy(vp, tp);
8286                         vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3];
8287                         vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3];
8288                         vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3];
8289                         vp += 3;
8290                         if (vn)
8291                         {
8292                                 // the normal transformation matrix is a set of cross products...
8293                                 CrossProduct(m[1], m[2], n[0]);
8294                                 CrossProduct(m[2], m[0], n[1]);
8295                                 CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m)
8296                                 VectorCopy(vn, tn);
8297                                 vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2];
8298                                 vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2];
8299                                 vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2];
8300                                 VectorNormalize(vn);
8301                                 vn += 3;
8302                                 if (vs)
8303                                 {
8304                                         VectorCopy(vs, ts);
8305                                         vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2];
8306                                         vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2];
8307                                         vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2];
8308                                         VectorNormalize(vs);
8309                                         vs += 3;
8310                                         VectorCopy(vt, tt);
8311                                         vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2];
8312                                         vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2];
8313                                         vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2];
8314                                         VectorNormalize(vt);
8315                                         vt += 3;
8316                                 }
8317                         }
8318                 }
8319                 rsurface.batchskeletaltransform3x4 = NULL;
8320                 rsurface.batchskeletalnumtransforms = 0;
8321         }
8322
8323         // q1bsp surfaces rendered in vertex color mode have to have colors
8324         // calculated based on lightstyles
8325         if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_ARRAY_VERTEXCOLOR)) && texturesurfacelist[0]->lightmapinfo)
8326         {
8327                 // generate color arrays for the surfaces in this list
8328                 int c[4];
8329                 int scale;
8330                 int size3;
8331                 const int *offsets;
8332                 const unsigned char *lm;
8333                 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8334                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8335                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8336                 numvertices = 0;
8337                 for (i = 0;i < texturenumsurfaces;i++)
8338                 {
8339                         surface = texturesurfacelist[i];
8340                         offsets = rsurface.modellightmapoffsets + surface->num_firstvertex;
8341                         surfacenumvertices = surface->num_vertices;
8342                         if (surface->lightmapinfo->samples)
8343                         {
8344                                 for (j = 0;j < surfacenumvertices;j++)
8345                                 {
8346                                         lm = surface->lightmapinfo->samples + offsets[j];
8347                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]];
8348                                         VectorScale(lm, scale, c);
8349                                         if (surface->lightmapinfo->styles[1] != 255)
8350                                         {
8351                                                 size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
8352                                                 lm += size3;
8353                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]];
8354                                                 VectorMA(c, scale, lm, c);
8355                                                 if (surface->lightmapinfo->styles[2] != 255)
8356                                                 {
8357                                                         lm += size3;
8358                                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]];
8359                                                         VectorMA(c, scale, lm, c);
8360                                                         if (surface->lightmapinfo->styles[3] != 255)
8361                                                         {
8362                                                                 lm += size3;
8363                                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]];
8364                                                                 VectorMA(c, scale, lm, c);
8365                                                         }
8366                                                 }
8367                                         }
8368                                         c[0] >>= 7;
8369                                         c[1] >>= 7;
8370                                         c[2] >>= 7;
8371                                         Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, min(c[0], 255) * (1.0f / 255.0f), min(c[1], 255) * (1.0f / 255.0f), min(c[2], 255) * (1.0f / 255.0f), 1);
8372                                         numvertices++;
8373                                 }
8374                         }
8375                         else
8376                         {
8377                                 for (j = 0;j < surfacenumvertices;j++)
8378                                 {
8379                                         Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1);
8380                                         numvertices++;
8381                                 }
8382                         }
8383                 }
8384         }
8385
8386         // if vertices are deformed (sprite flares and things in maps, possibly
8387         // water waves, bulges and other deformations), modify the copied vertices
8388         // in place
8389         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
8390         {
8391                 float scale;
8392                 switch (deform->deform)
8393                 {
8394                 default:
8395                 case Q3DEFORM_PROJECTIONSHADOW:
8396                 case Q3DEFORM_TEXT0:
8397                 case Q3DEFORM_TEXT1:
8398                 case Q3DEFORM_TEXT2:
8399                 case Q3DEFORM_TEXT3:
8400                 case Q3DEFORM_TEXT4:
8401                 case Q3DEFORM_TEXT5:
8402                 case Q3DEFORM_TEXT6:
8403                 case Q3DEFORM_TEXT7:
8404                 case Q3DEFORM_NONE:
8405                         break;
8406                 case Q3DEFORM_AUTOSPRITE:
8407                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8408                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8409                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8410                         VectorNormalize(newforward);
8411                         VectorNormalize(newright);
8412                         VectorNormalize(newup);
8413 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8414 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8415 //                      rsurface.batchvertex3f_bufferoffset = 0;
8416 //                      rsurface.batchsvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f);
8417 //                      rsurface.batchsvector3f_vertexbuffer = NULL;
8418 //                      rsurface.batchsvector3f_bufferoffset = 0;
8419 //                      rsurface.batchtvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f);
8420 //                      rsurface.batchtvector3f_vertexbuffer = NULL;
8421 //                      rsurface.batchtvector3f_bufferoffset = 0;
8422 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8423 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8424 //                      rsurface.batchnormal3f_bufferoffset = 0;
8425                         // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1)
8426                         if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex))
8427                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8428                         if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex))
8429                                 Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchsvector3f, rsurface.batchtvector3f, r_smoothnormals_areaweighting.integer != 0);
8430                         // a single autosprite surface can contain multiple sprites...
8431                         for (j = 0;j < batchnumvertices - 3;j += 4)
8432                         {
8433                                 VectorClear(center);
8434                                 for (i = 0;i < 4;i++)
8435                                         VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8436                                 VectorScale(center, 0.25f, center);
8437                                 VectorCopy(rsurface.batchnormal3f + 3*j, forward);
8438                                 VectorCopy(rsurface.batchsvector3f + 3*j, right);
8439                                 VectorCopy(rsurface.batchtvector3f + 3*j, up);
8440                                 for (i = 0;i < 4;i++)
8441                                 {
8442                                         VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v);
8443                                         VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.batchvertex3f + 3*(j+i));
8444                                 }
8445                         }
8446                         // if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check
8447                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8448                         Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchsvector3f, rsurface.batchtvector3f, r_smoothnormals_areaweighting.integer != 0);
8449                         break;
8450                 case Q3DEFORM_AUTOSPRITE2:
8451                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8452                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8453                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8454                         VectorNormalize(newforward);
8455                         VectorNormalize(newright);
8456                         VectorNormalize(newup);
8457 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8458 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8459 //                      rsurface.batchvertex3f_bufferoffset = 0;
8460                         {
8461                                 const float *v1, *v2;
8462                                 vec3_t start, end;
8463                                 float f, l;
8464                                 struct
8465                                 {
8466                                         float length2;
8467                                         const float *v1;
8468                                         const float *v2;
8469                                 }
8470                                 shortest[2];
8471                                 memset(shortest, 0, sizeof(shortest));
8472                                 // a single autosprite surface can contain multiple sprites...
8473                                 for (j = 0;j < batchnumvertices - 3;j += 4)
8474                                 {
8475                                         VectorClear(center);
8476                                         for (i = 0;i < 4;i++)
8477                                                 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8478                                         VectorScale(center, 0.25f, center);
8479                                         // find the two shortest edges, then use them to define the
8480                                         // axis vectors for rotating around the central axis
8481                                         for (i = 0;i < 6;i++)
8482                                         {
8483                                                 v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]);
8484                                                 v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]);
8485                                                 l = VectorDistance2(v1, v2);
8486                                                 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
8487                                                 if (v1[2] != v2[2])
8488                                                         l += (1.0f / 1024.0f);
8489                                                 if (shortest[0].length2 > l || i == 0)
8490                                                 {
8491                                                         shortest[1] = shortest[0];
8492                                                         shortest[0].length2 = l;
8493                                                         shortest[0].v1 = v1;
8494                                                         shortest[0].v2 = v2;
8495                                                 }
8496                                                 else if (shortest[1].length2 > l || i == 1)
8497                                                 {
8498                                                         shortest[1].length2 = l;
8499                                                         shortest[1].v1 = v1;
8500                                                         shortest[1].v2 = v2;
8501                                                 }
8502                                         }
8503                                         VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
8504                                         VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
8505                                         // this calculates the right vector from the shortest edge
8506                                         // and the up vector from the edge midpoints
8507                                         VectorSubtract(shortest[0].v1, shortest[0].v2, right);
8508                                         VectorNormalize(right);
8509                                         VectorSubtract(end, start, up);
8510                                         VectorNormalize(up);
8511                                         // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
8512                                         VectorSubtract(rsurface.localvieworigin, center, forward);
8513                                         //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
8514                                         VectorNegate(forward, forward);
8515                                         VectorReflect(forward, 0, up, forward);
8516                                         VectorNormalize(forward);
8517                                         CrossProduct(up, forward, newright);
8518                                         VectorNormalize(newright);
8519                                         // rotate the quad around the up axis vector, this is made
8520                                         // especially easy by the fact we know the quad is flat,
8521                                         // so we only have to subtract the center position and
8522                                         // measure distance along the right vector, and then
8523                                         // multiply that by the newright vector and add back the
8524                                         // center position
8525                                         // we also need to subtract the old position to undo the
8526                                         // displacement from the center, which we do with a
8527                                         // DotProduct, the subtraction/addition of center is also
8528                                         // optimized into DotProducts here
8529                                         l = DotProduct(right, center);
8530                                         for (i = 0;i < 4;i++)
8531                                         {
8532                                                 v1 = rsurface.batchvertex3f + 3*(j+i);
8533                                                 f = DotProduct(right, v1) - l;
8534                                                 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.batchvertex3f + 3*(j+i));
8535                                         }
8536                                 }
8537                         }
8538                         if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL
8539                         {
8540 //                              rsurface.batchnormal3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8541 //                              rsurface.batchnormal3f_vertexbuffer = NULL;
8542 //                              rsurface.batchnormal3f_bufferoffset = 0;
8543                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8544                         }
8545                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8546                         {
8547 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8548 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8549 //                              rsurface.batchsvector3f_bufferoffset = 0;
8550 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8551 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8552 //                              rsurface.batchtvector3f_bufferoffset = 0;
8553                                 Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchsvector3f, rsurface.batchtvector3f, r_smoothnormals_areaweighting.integer != 0);
8554                         }
8555                         break;
8556                 case Q3DEFORM_NORMAL:
8557                         // deform the normals to make reflections wavey
8558                         rsurface.batchnormal3f = (float *)R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8559                         rsurface.batchnormal3f_vertexbuffer = NULL;
8560                         rsurface.batchnormal3f_bufferoffset = 0;
8561                         for (j = 0;j < batchnumvertices;j++)
8562                         {
8563                                 float vertex[3];
8564                                 float *normal = rsurface.batchnormal3f + 3*j;
8565                                 VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
8566                                 normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f(      vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8567                                 normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8568                                 normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8569                                 VectorNormalize(normal);
8570                         }
8571                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8572                         {
8573 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8574 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8575 //                              rsurface.batchsvector3f_bufferoffset = 0;
8576 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8577 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8578 //                              rsurface.batchtvector3f_bufferoffset = 0;
8579                                 Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchsvector3f, rsurface.batchtvector3f, r_smoothnormals_areaweighting.integer != 0);
8580                         }
8581                         break;
8582                 case Q3DEFORM_WAVE:
8583                         // deform vertex array to make wavey water and flags and such
8584                         waveparms[0] = deform->waveparms[0];
8585                         waveparms[1] = deform->waveparms[1];
8586                         waveparms[2] = deform->waveparms[2];
8587                         waveparms[3] = deform->waveparms[3];
8588                         if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms))
8589                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8590                         // this is how a divisor of vertex influence on deformation
8591                         animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
8592                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8593 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8594 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8595 //                      rsurface.batchvertex3f_bufferoffset = 0;
8596 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8597 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8598 //                      rsurface.batchnormal3f_bufferoffset = 0;
8599                         for (j = 0;j < batchnumvertices;j++)
8600                         {
8601                                 // if the wavefunc depends on time, evaluate it per-vertex
8602                                 if (waveparms[3])
8603                                 {
8604                                         waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos;
8605                                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8606                                 }
8607                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8608                         }
8609                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8610                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8611                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8612                         {
8613 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8614 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8615 //                              rsurface.batchsvector3f_bufferoffset = 0;
8616 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8617 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8618 //                              rsurface.batchtvector3f_bufferoffset = 0;
8619                                 Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchsvector3f, rsurface.batchtvector3f, r_smoothnormals_areaweighting.integer != 0);
8620                         }
8621                         break;
8622                 case Q3DEFORM_BULGE:
8623                         // deform vertex array to make the surface have moving bulges
8624 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8625 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8626 //                      rsurface.batchvertex3f_bufferoffset = 0;
8627 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8628 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8629 //                      rsurface.batchnormal3f_bufferoffset = 0;
8630                         for (j = 0;j < batchnumvertices;j++)
8631                         {
8632                                 scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1];
8633                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8634                         }
8635                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8636                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8637                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8638                         {
8639 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8640 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8641 //                              rsurface.batchsvector3f_bufferoffset = 0;
8642 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8643 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8644 //                              rsurface.batchtvector3f_bufferoffset = 0;
8645                                 Mod_BuildTextureVectorsFromNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchtexcoordtexture2f, rsurface.batchnormal3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchsvector3f, rsurface.batchtvector3f, r_smoothnormals_areaweighting.integer != 0);
8646                         }
8647                         break;
8648                 case Q3DEFORM_MOVE:
8649                         // deform vertex array
8650                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
8651                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8652                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
8653                         VectorScale(deform->parms, scale, waveparms);
8654 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8655 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8656 //                      rsurface.batchvertex3f_bufferoffset = 0;
8657                         for (j = 0;j < batchnumvertices;j++)
8658                                 VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.batchvertex3f + 3*j);
8659                         break;
8660                 }
8661         }
8662
8663         if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
8664         {
8665         // generate texcoords based on the chosen texcoord source
8666                 switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
8667                 {
8668                 default:
8669                 case Q3TCGEN_TEXTURE:
8670                         break;
8671                 case Q3TCGEN_LIGHTMAP:
8672         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8673         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8674         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8675                         if (rsurface.batchtexcoordlightmap2f)
8676                                 memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
8677                         break;
8678                 case Q3TCGEN_VECTOR:
8679         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8680         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8681         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8682                         for (j = 0;j < batchnumvertices;j++)
8683                         {
8684                                 rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
8685                                 rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
8686                         }
8687                         break;
8688                 case Q3TCGEN_ENVIRONMENT:
8689                         // make environment reflections using a spheremap
8690                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8691                         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8692                         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8693                         for (j = 0;j < batchnumvertices;j++)
8694                         {
8695                                 // identical to Q3A's method, but executed in worldspace so
8696                                 // carried models can be shiny too
8697
8698                                 float viewer[3], d, reflected[3], worldreflected[3];
8699
8700                                 VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
8701                                 // VectorNormalize(viewer);
8702
8703                                 d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
8704
8705                                 reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
8706                                 reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
8707                                 reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
8708                                 // note: this is proportinal to viewer, so we can normalize later
8709
8710                                 Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
8711                                 VectorNormalize(worldreflected);
8712
8713                                 // note: this sphere map only uses world x and z!
8714                                 // so positive and negative y will LOOK THE SAME.
8715                                 rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
8716                                 rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
8717                         }
8718                         break;
8719                 }
8720                 // the only tcmod that needs software vertex processing is turbulent, so
8721                 // check for it here and apply the changes if needed
8722                 // and we only support that as the first one
8723                 // (handling a mixture of turbulent and other tcmods would be problematic
8724                 //  without punting it entirely to a software path)
8725                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
8726                 {
8727                         amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
8728                         animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
8729         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8730         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8731         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8732                         for (j = 0;j < batchnumvertices;j++)
8733                         {
8734                                 rsurface.batchtexcoordtexture2f[j*2+0] += amplitude * sin(((rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+2]) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8735                                 rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1]                                ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8736                         }
8737                 }
8738         }
8739
8740         if (needsupdate & batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP))
8741         {
8742                 // convert the modified arrays to vertex structs
8743 //              rsurface.batchvertexmesh = R_FrameData_Alloc(batchnumvertices * sizeof(r_vertexmesh_t));
8744 //              rsurface.batchvertexmesh_vertexbuffer = NULL;
8745 //              rsurface.batchvertexmesh_bufferoffset = 0;
8746                 if (batchneed & BATCHNEED_VERTEXMESH_VERTEX)
8747                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8748                                 VectorCopy(rsurface.batchvertex3f + 3*j, vertexmesh->vertex3f);
8749                 if (batchneed & BATCHNEED_VERTEXMESH_NORMAL)
8750                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8751                                 VectorCopy(rsurface.batchnormal3f + 3*j, vertexmesh->normal3f);
8752                 if (batchneed & BATCHNEED_VERTEXMESH_VECTOR)
8753                 {
8754                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8755                         {
8756                                 VectorCopy(rsurface.batchsvector3f + 3*j, vertexmesh->svector3f);
8757                                 VectorCopy(rsurface.batchtvector3f + 3*j, vertexmesh->tvector3f);
8758                         }
8759                 }
8760                 if ((batchneed & BATCHNEED_VERTEXMESH_VERTEXCOLOR) && rsurface.batchlightmapcolor4f)
8761                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8762                                 Vector4Copy(rsurface.batchlightmapcolor4f + 4*j, vertexmesh->color4f);
8763                 if (batchneed & BATCHNEED_VERTEXMESH_TEXCOORD)
8764                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8765                                 Vector2Copy(rsurface.batchtexcoordtexture2f + 2*j, vertexmesh->texcoordtexture2f);
8766                 if ((batchneed & BATCHNEED_VERTEXMESH_LIGHTMAP) && rsurface.batchtexcoordlightmap2f)
8767                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8768                                 Vector2Copy(rsurface.batchtexcoordlightmap2f + 2*j, vertexmesh->texcoordlightmap2f);
8769                 if ((batchneed & BATCHNEED_VERTEXMESH_SKELETAL) && rsurface.batchskeletalindex4ub)
8770                 {
8771                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8772                         {
8773                                 Vector4Copy(rsurface.batchskeletalindex4ub + 4*j, vertexmesh->skeletalindex4ub);
8774                                 Vector4Copy(rsurface.batchskeletalweight4ub + 4*j, vertexmesh->skeletalweight4ub);
8775                         }
8776                 }
8777         }
8778
8779         // upload buffer data for the dynamic batch
8780         if (((r_batch_dynamicbuffer.integer || gl_vbo_dynamicvertex.integer || gl_vbo_dynamicindex.integer) && vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo)
8781         {
8782                 if (rsurface.batchvertexmesh)
8783                         rsurface.batchvertexmesh_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(r_vertexmesh_t), rsurface.batchvertexmesh, R_BUFFERDATA_VERTEX, &rsurface.batchvertexmesh_bufferoffset);
8784                 else
8785                 {
8786                         if (rsurface.batchvertex3f)
8787                                 rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
8788                         if (rsurface.batchsvector3f)
8789                                 rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
8790                         if (rsurface.batchtvector3f)
8791                                 rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
8792                         if (rsurface.batchnormal3f)
8793                                 rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
8794                         if (rsurface.batchlightmapcolor4f)
8795                                 rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
8796                         if (rsurface.batchtexcoordtexture2f)
8797                                 rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
8798                         if (rsurface.batchtexcoordlightmap2f)
8799                                 rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
8800                         if (rsurface.batchskeletalindex4ub)
8801                                 rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
8802                         if (rsurface.batchskeletalweight4ub)
8803                                 rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
8804                 }
8805                 if (rsurface.batchelement3s)
8806                         rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
8807                 else if (rsurface.batchelement3i)
8808                         rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
8809         }
8810 }
8811
8812 void RSurf_DrawBatch(void)
8813 {
8814         // sometimes a zero triangle surface (usually a degenerate patch) makes it
8815         // through the pipeline, killing it earlier in the pipeline would have
8816         // per-surface overhead rather than per-batch overhead, so it's best to
8817         // reject it here, before it hits glDraw.
8818         if (rsurface.batchnumtriangles == 0)
8819                 return;
8820 #if 0
8821         // batch debugging code
8822         if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f)
8823         {
8824                 int i;
8825                 int j;
8826                 int c;
8827                 const int *e;
8828                 e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3;
8829                 for (i = 0;i < rsurface.batchnumtriangles*3;i++)
8830                 {
8831                         c = e[i];
8832                         for (j = 0;j < rsurface.entity->model->num_surfaces;j++)
8833                         {
8834                                 if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
8835                                 {
8836                                         if (rsurface.modelsurfaces[j].texture != rsurface.texture)
8837                                                 Sys_Error("RSurf_DrawBatch: index %i uses different texture (%s) than surface %i which it belongs to (which uses %s)\n", c, rsurface.texture->name, j, rsurface.modelsurfaces[j].texture->name);
8838                                         break;
8839                                 }
8840                         }
8841                 }
8842         }
8843 #endif
8844         if (rsurface.batchmultidraw)
8845         {
8846                 // issue multiple draws rather than copying index data
8847                 int numsurfaces = rsurface.batchmultidrawnumsurfaces;
8848                 const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist;
8849                 int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle;
8850                 for (i = 0;i < numsurfaces;)
8851                 {
8852                         // combine consecutive surfaces as one draw
8853                         for (k = i, j = i + 1;j < numsurfaces;k = j, j++)
8854                                 if (surfacelist[j] != surfacelist[k] + 1)
8855                                         break;
8856                         firstvertex = surfacelist[i]->num_firstvertex;
8857                         endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices;
8858                         firsttriangle = surfacelist[i]->num_firsttriangle;
8859                         endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles;
8860                         R_Mesh_Draw(firstvertex, endvertex - firstvertex, firsttriangle, endtriangle - firsttriangle, rsurface.batchelement3i, rsurface.batchelement3i_indexbuffer, rsurface.batchelement3i_bufferoffset, rsurface.batchelement3s, rsurface.batchelement3s_indexbuffer, rsurface.batchelement3s_bufferoffset);
8861                         i = j;
8862                 }
8863         }
8864         else
8865         {
8866                 // there is only one consecutive run of index data (may have been combined)
8867                 R_Mesh_Draw(rsurface.batchfirstvertex, rsurface.batchnumvertices, rsurface.batchfirsttriangle, rsurface.batchnumtriangles, rsurface.batchelement3i, rsurface.batchelement3i_indexbuffer, rsurface.batchelement3i_bufferoffset, rsurface.batchelement3s, rsurface.batchelement3s_indexbuffer, rsurface.batchelement3s_bufferoffset);
8868         }
8869 }
8870
8871 static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface)
8872 {
8873         // pick the closest matching water plane
8874         int planeindex, vertexindex, bestplaneindex = -1;
8875         float d, bestd;
8876         vec3_t vert;
8877         const float *v;
8878         r_waterstate_waterplane_t *p;
8879         qboolean prepared = false;
8880         bestd = 0;
8881         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
8882         {
8883                 if(p->camera_entity != rsurface.texture->camera_entity)
8884                         continue;
8885                 d = 0;
8886                 if(!prepared)
8887                 {
8888                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
8889                         prepared = true;
8890                         if(rsurface.batchnumvertices == 0)
8891                                 break;
8892                 }
8893                 for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
8894                 {
8895                         Matrix4x4_Transform(&rsurface.matrix, v, vert);
8896                         d += fabs(PlaneDiff(vert, &p->plane));
8897                 }
8898                 if (bestd > d || bestplaneindex < 0)
8899                 {
8900                         bestd = d;
8901                         bestplaneindex = planeindex;
8902                 }
8903         }
8904         return bestplaneindex;
8905         // NOTE: this MAY return a totally unrelated water plane; we can ignore
8906         // this situation though, as it might be better to render single larger
8907         // batches with useless stuff (backface culled for example) than to
8908         // render multiple smaller batches
8909 }
8910
8911 void RSurf_SetupDepthAndCulling(void)
8912 {
8913         // submodels are biased to avoid z-fighting with world surfaces that they
8914         // may be exactly overlapping (avoids z-fighting artifacts on certain
8915         // doors and things in Quake maps)
8916         GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
8917         GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
8918         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
8919         GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
8920 }
8921
8922 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8923 {
8924         int i, j;
8925         // transparent sky would be ridiculous
8926         if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8927                 return;
8928         R_SetupShader_Generic_NoTexture(false, false);
8929         skyrenderlater = true;
8930         RSurf_SetupDepthAndCulling();
8931         GL_DepthMask(true);
8932
8933         // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
8934         if (r_sky_scissor.integer)
8935         {
8936                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8937                 for (i = 0; i < texturenumsurfaces; i++)
8938                 {
8939                         const msurface_t *surf = texturesurfacelist[i];
8940                         const float *v;
8941                         float p[3];
8942                         float mins[3], maxs[3];
8943                         int scissor[4];
8944                         for (j = 0, v = rsurface.batchvertex3f + 3 * surf->num_firstvertex; j < surf->num_vertices; j++, v += 3)
8945                         {
8946                                 Matrix4x4_Transform(&rsurface.matrix, v, p);
8947                                 if (j > 0)
8948                                 {
8949                                         if (mins[0] > p[0]) mins[0] = p[0];
8950                                         if (mins[1] > p[1]) mins[1] = p[1];
8951                                         if (mins[2] > p[2]) mins[2] = p[2];
8952                                         if (maxs[0] < p[0]) maxs[0] = p[0];
8953                                         if (maxs[1] < p[1]) maxs[1] = p[1];
8954                                         if (maxs[2] < p[2]) maxs[2] = p[2];
8955                                 }
8956                                 else
8957                                 {
8958                                         VectorCopy(p, mins);
8959                                         VectorCopy(p, maxs);
8960                                 }
8961                         }
8962                         if (!R_ScissorForBBox(mins, maxs, scissor))
8963                         {
8964                                 if (skyscissor[2])
8965                                 {
8966                                         if (skyscissor[0] > scissor[0])
8967                                         {
8968                                                 skyscissor[2] += skyscissor[0] - scissor[0];
8969                                                 skyscissor[0] = scissor[0];
8970                                         }
8971                                         if (skyscissor[1] > scissor[1])
8972                                         {
8973                                                 skyscissor[3] += skyscissor[1] - scissor[1];
8974                                                 skyscissor[1] = scissor[1];
8975                                         }
8976                                         if (skyscissor[0] + skyscissor[2] < scissor[0] + scissor[2])
8977                                                 skyscissor[2] = scissor[0] + scissor[2] - skyscissor[0];
8978                                         if (skyscissor[1] + skyscissor[3] < scissor[1] + scissor[3])
8979                                                 skyscissor[3] = scissor[1] + scissor[3] - skyscissor[1];
8980                                 }
8981                                 else
8982                                         Vector4Copy(scissor, skyscissor);
8983                         }
8984                 }
8985         }
8986
8987         // LadyHavoc: HalfLife maps have freaky skypolys so don't use
8988         // skymasking on them, and Quake3 never did sky masking (unlike
8989         // software Quake and software Quake2), so disable the sky masking
8990         // in Quake3 maps as it causes problems with q3map2 sky tricks,
8991         // and skymasking also looks very bad when noclipping outside the
8992         // level, so don't use it then either.
8993         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.skymasking && (r_refdef.scene.worldmodel->brush.isq3bsp ? r_q3bsp_renderskydepth.integer : r_q1bsp_skymasking.integer) && !r_refdef.viewcache.world_novis && !r_trippy.integer)
8994         {
8995                 R_Mesh_ResetTextureState();
8996                 if (skyrendermasked)
8997                 {
8998                         R_SetupShader_DepthOrShadow(false, false, false);
8999                         // depth-only (masking)
9000                         GL_ColorMask(0, 0, 0, 0);
9001                         // just to make sure that braindead drivers don't draw
9002                         // anything despite that colormask...
9003                         GL_BlendFunc(GL_ZERO, GL_ONE);
9004                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9005                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9006                 }
9007                 else
9008                 {
9009                         R_SetupShader_Generic_NoTexture(false, false);
9010                         // fog sky
9011                         GL_BlendFunc(GL_ONE, GL_ZERO);
9012                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9013                         GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
9014                         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9015                 }
9016                 RSurf_DrawBatch();
9017                 if (skyrendermasked)
9018                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
9019         }
9020         R_Mesh_ResetTextureState();
9021         GL_Color(1, 1, 1, 1);
9022 }
9023
9024 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
9025 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
9026 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
9027 {
9028         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
9029                 return;
9030         if (prepass)
9031         {
9032                 // render screenspace normalmap to texture
9033                 GL_DepthMask(true);
9034                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false);
9035                 RSurf_DrawBatch();
9036                 return;
9037         }
9038
9039         // bind lightmap texture
9040
9041         // water/refraction/reflection/camera surfaces have to be handled specially
9042         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)))
9043         {
9044                 int start, end, startplaneindex;
9045                 for (start = 0;start < texturenumsurfaces;start = end)
9046                 {
9047                         startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]);
9048                         if(startplaneindex < 0)
9049                         {
9050                                 // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this.
9051                                 // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags);
9052                                 end = start + 1;
9053                                 continue;
9054                         }
9055                         for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++)
9056                                 ;
9057                         // now that we have a batch using the same planeindex, render it
9058                         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)))
9059                         {
9060                                 // render water or distortion background
9061                                 GL_DepthMask(true);
9062                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
9063                                 RSurf_DrawBatch();
9064                                 // blend surface on top
9065                                 GL_DepthMask(false);
9066                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false);
9067                                 RSurf_DrawBatch();
9068                         }
9069                         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
9070                         {
9071                                 // render surface with reflection texture as input
9072                                 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
9073                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
9074                                 RSurf_DrawBatch();
9075                         }
9076                 }
9077                 return;
9078         }
9079
9080         // render surface batch normally
9081         GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
9082         R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0);
9083         RSurf_DrawBatch();
9084 }
9085
9086 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
9087 {
9088         int vi;
9089         int j;
9090         r_vertexgeneric_t *batchvertex;
9091         float c[4];
9092         texture_t *t = rsurface.texture;
9093
9094 //      R_Mesh_ResetTextureState();
9095         R_SetupShader_Generic_NoTexture(false, false);
9096
9097         if(t && t->currentskinframe)
9098         {
9099                 memcpy(c, t->currentskinframe->avgcolor, sizeof(c));
9100                 c[3] *= t->currentalpha;
9101         }
9102         else
9103         {
9104                 c[0] = 1;
9105                 c[1] = 0;
9106                 c[2] = 1;
9107                 c[3] = 1;
9108         }
9109
9110         if (t->pantstexture || t->shirttexture)
9111         {
9112                 c[0] = 0.5 * (t->render_colormap_pants[0] * 0.3 + t->render_colormap_shirt[0] * 0.7);
9113                 c[1] = 0.5 * (t->render_colormap_pants[1] * 0.3 + t->render_colormap_shirt[1] * 0.7);
9114                 c[2] = 0.5 * (t->render_colormap_pants[2] * 0.3 + t->render_colormap_shirt[2] * 0.7);
9115         }
9116
9117         // brighten it up (as texture value 127 means "unlit")
9118         c[0] *= 2 * r_refdef.view.colorscale;
9119         c[1] *= 2 * r_refdef.view.colorscale;
9120         c[2] *= 2 * r_refdef.view.colorscale;
9121
9122         if(t->currentmaterialflags & MATERIALFLAG_WATERALPHA)
9123                 c[3] *= r_wateralpha.value;
9124
9125         if(t->currentmaterialflags & MATERIALFLAG_ALPHA && c[3] != 1)
9126         {
9127                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9128                 GL_DepthMask(false);
9129         }
9130         else if(t->currentmaterialflags & MATERIALFLAG_ADD)
9131         {
9132                 GL_BlendFunc(GL_ONE, GL_ONE);
9133                 GL_DepthMask(false);
9134         }
9135         else if(t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
9136         {
9137                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // can't do alpha test without texture, so let's blend instead
9138                 GL_DepthMask(false);
9139         }
9140         else if(t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
9141         {
9142                 GL_BlendFunc(t->customblendfunc[0], t->customblendfunc[1]);
9143                 GL_DepthMask(false);
9144         }
9145         else
9146         {
9147                 GL_BlendFunc(GL_ONE, GL_ZERO);
9148                 GL_DepthMask(writedepth);
9149         }
9150
9151         if (!r_refdef.view.showdebug)
9152         {
9153                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9154                 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchnumvertices);
9155                 for (j = 0, vi = 0;j < rsurface.batchnumvertices;j++, vi++)
9156                 {
9157                         VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
9158                         Vector4Set(batchvertex[vi].color4f, 0, 0, 0, 1);
9159                 }
9160                 R_Mesh_PrepareVertices_Generic_Unlock();
9161                 RSurf_DrawBatch();
9162         }
9163         else if (r_showsurfaces.integer == 4)
9164         {
9165                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9166                 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchnumvertices);
9167                 for (j = 0, vi = 0;j < rsurface.batchnumvertices;j++, vi++)
9168                 {
9169                         float d = (vi << 3) * (1.0f / 256.0f);
9170                         VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
9171                         Vector4Set(batchvertex[vi].color4f, d, d, d, 1);
9172                 }
9173                 R_Mesh_PrepareVertices_Generic_Unlock();
9174                 RSurf_DrawBatch();
9175         }
9176         else if (r_showsurfaces.integer == 2)
9177         {
9178                 const int *e;
9179                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9180                 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(3*rsurface.batchnumtriangles);
9181                 for (j = 0, e = rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle;j < rsurface.batchnumtriangles;j++, e += 3)
9182                 {
9183                         float d = ((j + rsurface.batchfirsttriangle) << 3) * (1.0f / 256.0f);
9184                         VectorCopy(rsurface.batchvertex3f + 3*e[0], batchvertex[j*3+0].vertex3f);
9185                         VectorCopy(rsurface.batchvertex3f + 3*e[1], batchvertex[j*3+1].vertex3f);
9186                         VectorCopy(rsurface.batchvertex3f + 3*e[2], batchvertex[j*3+2].vertex3f);
9187                         Vector4Set(batchvertex[j*3+0].color4f, d, d, d, 1);
9188                         Vector4Set(batchvertex[j*3+1].color4f, d, d, d, 1);
9189                         Vector4Set(batchvertex[j*3+2].color4f, d, d, d, 1);
9190                 }
9191                 R_Mesh_PrepareVertices_Generic_Unlock();
9192                 R_Mesh_Draw(0, rsurface.batchnumtriangles*3, 0, rsurface.batchnumtriangles, NULL, NULL, 0, NULL, NULL, 0);
9193         }
9194         else
9195         {
9196                 int texturesurfaceindex;
9197                 int k;
9198                 const msurface_t *surface;
9199                 float surfacecolor4f[4];
9200                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9201                 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchfirstvertex + rsurface.batchnumvertices);
9202                 vi = 0;
9203                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
9204                 {
9205                         surface = texturesurfacelist[texturesurfaceindex];
9206                         k = (int)(((size_t)surface) / sizeof(msurface_t));
9207                         Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
9208                         for (j = 0;j < surface->num_vertices;j++)
9209                         {
9210                                 VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
9211                                 Vector4Copy(surfacecolor4f, batchvertex[vi].color4f);
9212                                 vi++;
9213                         }
9214                 }
9215                 R_Mesh_PrepareVertices_Generic_Unlock();
9216                 RSurf_DrawBatch();
9217         }
9218 }
9219
9220 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
9221 {
9222         CHECKGLERROR
9223         RSurf_SetupDepthAndCulling();
9224         if (r_showsurfaces.integer)
9225         {
9226                 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
9227                 return;
9228         }
9229         switch (vid.renderpath)
9230         {
9231         case RENDERPATH_GL20:
9232         case RENDERPATH_GLES2:
9233                 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
9234                 break;
9235         }
9236         CHECKGLERROR
9237 }
9238
9239 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9240 {
9241         int i, j;
9242         int texturenumsurfaces, endsurface;
9243         texture_t *texture;
9244         const msurface_t *surface;
9245         const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
9246
9247         RSurf_ActiveModelEntity(ent, true, true, false);
9248
9249         if (r_transparentdepthmasking.integer)
9250         {
9251                 qboolean setup = false;
9252                 for (i = 0;i < numsurfaces;i = j)
9253                 {
9254                         j = i + 1;
9255                         surface = rsurface.modelsurfaces + surfacelist[i];
9256                         texture = surface->texture;
9257                         rsurface.texture = R_GetCurrentTexture(texture);
9258                         rsurface.lightmaptexture = NULL;
9259                         rsurface.deluxemaptexture = NULL;
9260                         rsurface.uselightmaptexture = false;
9261                         // scan ahead until we find a different texture
9262                         endsurface = min(i + 1024, numsurfaces);
9263                         texturenumsurfaces = 0;
9264                         texturesurfacelist[texturenumsurfaces++] = surface;
9265                         for (;j < endsurface;j++)
9266                         {
9267                                 surface = rsurface.modelsurfaces + surfacelist[j];
9268                                 if (texture != surface->texture)
9269                                         break;
9270                                 texturesurfacelist[texturenumsurfaces++] = surface;
9271                         }
9272                         if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
9273                                 continue;
9274                         // render the range of surfaces as depth
9275                         if (!setup)
9276                         {
9277                                 setup = true;
9278                                 GL_ColorMask(0,0,0,0);
9279                                 GL_Color(1,1,1,1);
9280                                 GL_DepthTest(true);
9281                                 GL_BlendFunc(GL_ONE, GL_ZERO);
9282                                 GL_DepthMask(true);
9283 //                              R_Mesh_ResetTextureState();
9284                         }
9285                         RSurf_SetupDepthAndCulling();
9286                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9287                         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
9288                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9289                         RSurf_DrawBatch();
9290                 }
9291                 if (setup)
9292                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
9293         }
9294
9295         for (i = 0;i < numsurfaces;i = j)
9296         {
9297                 j = i + 1;
9298                 surface = rsurface.modelsurfaces + surfacelist[i];
9299                 texture = surface->texture;
9300                 rsurface.texture = R_GetCurrentTexture(texture);
9301                 // scan ahead until we find a different texture
9302                 endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
9303                 texturenumsurfaces = 0;
9304                 texturesurfacelist[texturenumsurfaces++] = surface;
9305                 if(FAKELIGHT_ENABLED)
9306                 {
9307                         rsurface.lightmaptexture = NULL;
9308                         rsurface.deluxemaptexture = NULL;
9309                         rsurface.uselightmaptexture = false;
9310                         for (;j < endsurface;j++)
9311                         {
9312                                 surface = rsurface.modelsurfaces + surfacelist[j];
9313                                 if (texture != surface->texture)
9314                                         break;
9315                                 texturesurfacelist[texturenumsurfaces++] = surface;
9316                         }
9317                 }
9318                 else
9319                 {
9320                         rsurface.lightmaptexture = surface->lightmaptexture;
9321                         rsurface.deluxemaptexture = surface->deluxemaptexture;
9322                         rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
9323                         for (;j < endsurface;j++)
9324                         {
9325                                 surface = rsurface.modelsurfaces + surfacelist[j];
9326                                 if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture)
9327                                         break;
9328                                 texturesurfacelist[texturenumsurfaces++] = surface;
9329                         }
9330                 }
9331                 // render the range of surfaces
9332                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false);
9333         }
9334         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
9335 }
9336
9337 static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
9338 {
9339         // transparent surfaces get pushed off into the transparent queue
9340         int surfacelistindex;
9341         const msurface_t *surface;
9342         vec3_t tempcenter, center;
9343         for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
9344         {
9345                 surface = texturesurfacelist[surfacelistindex];
9346                 if (r_transparent_sortsurfacesbynearest.integer)
9347                 {
9348                         tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]);
9349                         tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]);
9350                         tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]);
9351                 }
9352                 else
9353                 {
9354                         tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
9355                         tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
9356                         tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
9357                 }
9358                 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
9359                 if (rsurface.entity->transparent_offset) // transparent offset
9360                 {
9361                         center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset;
9362                         center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset;
9363                         center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset;
9364                 }
9365                 R_MeshQueue_AddTransparent((rsurface.entity->flags & RENDER_WORLDOBJECT) ? TRANSPARENTSORT_SKY : (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST) ? TRANSPARENTSORT_HUD : rsurface.texture->transparentsort, center, R_DrawSurface_TransparentCallback, rsurface.entity, surface - rsurface.modelsurfaces, rsurface.rtlight);
9366         }
9367 }
9368
9369 static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist)
9370 {
9371         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
9372                 return;
9373         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
9374                 return;
9375         RSurf_SetupDepthAndCulling();
9376         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9377         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9378         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
9379         RSurf_DrawBatch();
9380 }
9381
9382 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass)
9383 {
9384         CHECKGLERROR
9385         if (depthonly)
9386                 R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
9387         else if (prepass)
9388         {
9389                 if (!rsurface.texture->currentnumlayers)
9390                         return;
9391                 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
9392                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9393                 else
9394                         R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
9395         }
9396         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3))
9397                 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
9398         else if (!rsurface.texture->currentnumlayers)
9399                 return;
9400         else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
9401         {
9402                 // in the deferred case, transparent surfaces were queued during prepass
9403                 if (!r_shadow_usingdeferredprepass)
9404                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9405         }
9406         else
9407         {
9408                 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
9409                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass);
9410         }
9411         CHECKGLERROR
9412 }
9413
9414 static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass)
9415 {
9416         int i, j;
9417         texture_t *texture;
9418         R_FrameData_SetMark();
9419         // break the surface list down into batches by texture and use of lightmapping
9420         for (i = 0;i < numsurfaces;i = j)
9421         {
9422                 j = i + 1;
9423                 // texture is the base texture pointer, rsurface.texture is the
9424                 // current frame/skin the texture is directing us to use (for example
9425                 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
9426                 // use skin 1 instead)
9427                 texture = surfacelist[i]->texture;
9428                 rsurface.texture = R_GetCurrentTexture(texture);
9429                 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
9430                 {
9431                         // if this texture is not the kind we want, skip ahead to the next one
9432                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9433                                 ;
9434                         continue;
9435                 }
9436                 if(FAKELIGHT_ENABLED || depthonly || prepass)
9437                 {
9438                         rsurface.lightmaptexture = NULL;
9439                         rsurface.deluxemaptexture = NULL;
9440                         rsurface.uselightmaptexture = false;
9441                         // simply scan ahead until we find a different texture or lightmap state
9442                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9443                                 ;
9444                 }
9445                 else
9446                 {
9447                         rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
9448                         rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
9449                         rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
9450                         // simply scan ahead until we find a different texture or lightmap state
9451                         for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
9452                                 ;
9453                 }
9454                 // render the range of surfaces
9455                 R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass);
9456         }
9457         R_FrameData_ReturnToMark();
9458 }
9459
9460 float locboxvertex3f[6*4*3] =
9461 {
9462         1,0,1, 1,0,0, 1,1,0, 1,1,1,
9463         0,1,1, 0,1,0, 0,0,0, 0,0,1,
9464         1,1,1, 1,1,0, 0,1,0, 0,1,1,
9465         0,0,1, 0,0,0, 1,0,0, 1,0,1,
9466         0,0,1, 1,0,1, 1,1,1, 0,1,1,
9467         1,0,0, 0,0,0, 0,1,0, 1,1,0
9468 };
9469
9470 unsigned short locboxelements[6*2*3] =
9471 {
9472          0, 1, 2, 0, 2, 3,
9473          4, 5, 6, 4, 6, 7,
9474          8, 9,10, 8,10,11,
9475         12,13,14, 12,14,15,
9476         16,17,18, 16,18,19,
9477         20,21,22, 20,22,23
9478 };
9479
9480 static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9481 {
9482         int i, j;
9483         cl_locnode_t *loc = (cl_locnode_t *)ent;
9484         vec3_t mins, size;
9485         float vertex3f[6*4*3];
9486         CHECKGLERROR
9487         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9488         GL_DepthMask(false);
9489         GL_DepthRange(0, 1);
9490         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9491         GL_DepthTest(true);
9492         GL_CullFace(GL_NONE);
9493         R_EntityMatrix(&identitymatrix);
9494
9495 //      R_Mesh_ResetTextureState();
9496
9497         i = surfacelist[0];
9498         GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9499                          ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9500                          ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9501                         surfacelist[0] < 0 ? 0.5f : 0.125f);
9502
9503         if (VectorCompare(loc->mins, loc->maxs))
9504         {
9505                 VectorSet(size, 2, 2, 2);
9506                 VectorMA(loc->mins, -0.5f, size, mins);
9507         }
9508         else
9509         {
9510                 VectorCopy(loc->mins, mins);
9511                 VectorSubtract(loc->maxs, loc->mins, size);
9512         }
9513
9514         for (i = 0;i < 6*4*3;)
9515                 for (j = 0;j < 3;j++, i++)
9516                         vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
9517
9518         R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
9519         R_SetupShader_Generic_NoTexture(false, false);
9520         R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
9521 }
9522
9523 void R_DrawLocs(void)
9524 {
9525         int index;
9526         cl_locnode_t *loc, *nearestloc;
9527         vec3_t center;
9528         nearestloc = CL_Locs_FindNearest(cl.movement_origin);
9529         for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
9530         {
9531                 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
9532                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
9533         }
9534 }
9535
9536 void R_DecalSystem_Reset(decalsystem_t *decalsystem)
9537 {
9538         if (decalsystem->decals)
9539                 Mem_Free(decalsystem->decals);
9540         memset(decalsystem, 0, sizeof(*decalsystem));
9541 }
9542
9543 static void R_DecalSystem_SpawnTriangle(decalsystem_t *decalsystem, const float *v0, const float *v1, const float *v2, const float *t0, const float *t1, const float *t2, const float *c0, const float *c1, const float *c2, int triangleindex, int surfaceindex, unsigned int decalsequence)
9544 {
9545         tridecal_t *decal;
9546         tridecal_t *decals;
9547         int i;
9548
9549         // expand or initialize the system
9550         if (decalsystem->maxdecals <= decalsystem->numdecals)
9551         {
9552                 decalsystem_t old = *decalsystem;
9553                 qboolean useshortelements;
9554                 decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2);
9555                 useshortelements = decalsystem->maxdecals * 3 <= 65536;
9556                 decalsystem->decals = (tridecal_t *)Mem_Alloc(cls.levelmempool, decalsystem->maxdecals * (sizeof(tridecal_t) + sizeof(float[3][3]) + sizeof(float[3][2]) + sizeof(float[3][4]) + sizeof(int[3]) + (useshortelements ? sizeof(unsigned short[3]) : 0)));
9557                 decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals);
9558                 decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12);
9559                 decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6);
9560                 decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
9561                 decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
9562                 if (decalsystem->numdecals)
9563                         memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
9564                 if (old.decals)
9565                         Mem_Free(old.decals);
9566                 for (i = 0;i < decalsystem->maxdecals*3;i++)
9567                         decalsystem->element3i[i] = i;
9568                 if (useshortelements)
9569                         for (i = 0;i < decalsystem->maxdecals*3;i++)
9570                                 decalsystem->element3s[i] = i;
9571         }
9572
9573         // grab a decal and search for another free slot for the next one
9574         decals = decalsystem->decals;
9575         decal = decalsystem->decals + (i = decalsystem->freedecal++);
9576         for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4f[0][3];i++)
9577                 ;
9578         decalsystem->freedecal = i;
9579         if (decalsystem->numdecals <= i)
9580                 decalsystem->numdecals = i + 1;
9581
9582         // initialize the decal
9583         decal->lived = 0;
9584         decal->triangleindex = triangleindex;
9585         decal->surfaceindex = surfaceindex;
9586         decal->decalsequence = decalsequence;
9587         decal->color4f[0][0] = c0[0];
9588         decal->color4f[0][1] = c0[1];
9589         decal->color4f[0][2] = c0[2];
9590         decal->color4f[0][3] = 1;
9591         decal->color4f[1][0] = c1[0];
9592         decal->color4f[1][1] = c1[1];
9593         decal->color4f[1][2] = c1[2];
9594         decal->color4f[1][3] = 1;
9595         decal->color4f[2][0] = c2[0];
9596         decal->color4f[2][1] = c2[1];
9597         decal->color4f[2][2] = c2[2];
9598         decal->color4f[2][3] = 1;
9599         decal->vertex3f[0][0] = v0[0];
9600         decal->vertex3f[0][1] = v0[1];
9601         decal->vertex3f[0][2] = v0[2];
9602         decal->vertex3f[1][0] = v1[0];
9603         decal->vertex3f[1][1] = v1[1];
9604         decal->vertex3f[1][2] = v1[2];
9605         decal->vertex3f[2][0] = v2[0];
9606         decal->vertex3f[2][1] = v2[1];
9607         decal->vertex3f[2][2] = v2[2];
9608         decal->texcoord2f[0][0] = t0[0];
9609         decal->texcoord2f[0][1] = t0[1];
9610         decal->texcoord2f[1][0] = t1[0];
9611         decal->texcoord2f[1][1] = t1[1];
9612         decal->texcoord2f[2][0] = t2[0];
9613         decal->texcoord2f[2][1] = t2[1];
9614         TriangleNormal(v0, v1, v2, decal->plane);
9615         VectorNormalize(decal->plane);
9616         decal->plane[3] = DotProduct(v0, decal->plane);
9617 }
9618
9619 extern cvar_t cl_decals_bias;
9620 extern cvar_t cl_decals_models;
9621 extern cvar_t cl_decals_newsystem_intensitymultiplier;
9622 // baseparms, parms, temps
9623 static void R_DecalSystem_SplatTriangle(decalsystem_t *decalsystem, float r, float g, float b, float a, float s1, float t1, float s2, float t2, unsigned int decalsequence, qboolean dynamic, float (*planes)[4], matrix4x4_t *projection, int triangleindex, int surfaceindex)
9624 {
9625         int cornerindex;
9626         int index;
9627         float v[9][3];
9628         const float *vertex3f;
9629         const float *normal3f;
9630         int numpoints;
9631         float points[2][9][3];
9632         float temp[3];
9633         float tc[9][2];
9634         float f;
9635         float c[9][4];
9636         const int *e;
9637
9638         e = rsurface.modelelement3i + 3*triangleindex;
9639
9640         vertex3f = rsurface.modelvertex3f;
9641         normal3f = rsurface.modelnormal3f;
9642
9643         if (normal3f)
9644         {
9645                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9646                 {
9647                         index = 3*e[cornerindex];
9648                         VectorMA(vertex3f + index, cl_decals_bias.value, normal3f + index, v[cornerindex]);
9649                 }
9650         }
9651         else
9652         {
9653                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9654                 {
9655                         index = 3*e[cornerindex];
9656                         VectorCopy(vertex3f + index, v[cornerindex]);
9657                 }
9658         }
9659
9660         // cull backfaces
9661         //TriangleNormal(v[0], v[1], v[2], normal);
9662         //if (DotProduct(normal, localnormal) < 0.0f)
9663         //      continue;
9664         // clip by each of the box planes formed from the projection matrix
9665         // if anything survives, we emit the decal
9666         numpoints = PolygonF_Clip(3        , v[0]        , planes[0][0], planes[0][1], planes[0][2], planes[0][3], 1.0f/64.0f, sizeof(points[0])/sizeof(points[0][0]), points[1][0]);
9667         if (numpoints < 3)
9668                 return;
9669         numpoints = PolygonF_Clip(numpoints, points[1][0], planes[1][0], planes[1][1], planes[1][2], planes[1][3], 1.0f/64.0f, sizeof(points[0])/sizeof(points[0][0]), points[0][0]);
9670         if (numpoints < 3)
9671                 return;
9672         numpoints = PolygonF_Clip(numpoints, points[0][0], planes[2][0], planes[2][1], planes[2][2], planes[2][3], 1.0f/64.0f, sizeof(points[0])/sizeof(points[0][0]), points[1][0]);
9673         if (numpoints < 3)
9674                 return;
9675         numpoints = PolygonF_Clip(numpoints, points[1][0], planes[3][0], planes[3][1], planes[3][2], planes[3][3], 1.0f/64.0f, sizeof(points[0])/sizeof(points[0][0]), points[0][0]);
9676         if (numpoints < 3)
9677                 return;
9678         numpoints = PolygonF_Clip(numpoints, points[0][0], planes[4][0], planes[4][1], planes[4][2], planes[4][3], 1.0f/64.0f, sizeof(points[0])/sizeof(points[0][0]), points[1][0]);
9679         if (numpoints < 3)
9680                 return;
9681         numpoints = PolygonF_Clip(numpoints, points[1][0], planes[5][0], planes[5][1], planes[5][2], planes[5][3], 1.0f/64.0f, sizeof(points[0])/sizeof(points[0][0]), v[0]);
9682         if (numpoints < 3)
9683                 return;
9684         // some part of the triangle survived, so we have to accept it...
9685         if (dynamic)
9686         {
9687                 // dynamic always uses the original triangle
9688                 numpoints = 3;
9689                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9690                 {
9691                         index = 3*e[cornerindex];
9692                         VectorCopy(vertex3f + index, v[cornerindex]);
9693                 }
9694         }
9695         for (cornerindex = 0;cornerindex < numpoints;cornerindex++)
9696         {
9697                 // convert vertex positions to texcoords
9698                 Matrix4x4_Transform(projection, v[cornerindex], temp);
9699                 tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
9700                 tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
9701                 // calculate distance fade from the projection origin
9702                 f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
9703                 f = bound(0.0f, f, 1.0f);
9704                 c[cornerindex][0] = r * f;
9705                 c[cornerindex][1] = g * f;
9706                 c[cornerindex][2] = b * f;
9707                 c[cornerindex][3] = 1.0f;
9708                 //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
9709         }
9710         if (dynamic)
9711                 R_DecalSystem_SpawnTriangle(decalsystem, v[0], v[1], v[2], tc[0], tc[1], tc[2], c[0], c[1], c[2], triangleindex, surfaceindex, decalsequence);
9712         else
9713                 for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
9714                         R_DecalSystem_SpawnTriangle(decalsystem, v[0], v[cornerindex+1], v[cornerindex+2], tc[0], tc[cornerindex+1], tc[cornerindex+2], c[0], c[cornerindex+1], c[cornerindex+2], -1, surfaceindex, decalsequence);
9715 }
9716 static void R_DecalSystem_SplatEntity(entity_render_t *ent, const vec3_t worldorigin, const vec3_t worldnormal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float worldsize, unsigned int decalsequence)
9717 {
9718         matrix4x4_t projection;
9719         decalsystem_t *decalsystem;
9720         qboolean dynamic;
9721         dp_model_t *model;
9722         const msurface_t *surface;
9723         const msurface_t *surfaces;
9724         const int *surfacelist;
9725         const texture_t *texture;
9726         int numtriangles;
9727         int numsurfacelist;
9728         int surfacelistindex;
9729         int surfaceindex;
9730         int triangleindex;
9731         float localorigin[3];
9732         float localnormal[3];
9733         float localmins[3];
9734         float localmaxs[3];
9735         float localsize;
9736         //float normal[3];
9737         float planes[6][4];
9738         float angles[3];
9739         bih_t *bih;
9740         int bih_triangles_count;
9741         int bih_triangles[256];
9742         int bih_surfaces[256];
9743
9744         decalsystem = &ent->decalsystem;
9745         model = ent->model;
9746         if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST)))
9747         {
9748                 R_DecalSystem_Reset(&ent->decalsystem);
9749                 return;
9750         }
9751
9752         if (!model->brush.data_leafs && !cl_decals_models.integer)
9753         {
9754                 if (decalsystem->model)
9755                         R_DecalSystem_Reset(decalsystem);
9756                 return;
9757         }
9758
9759         if (decalsystem->model != model)
9760                 R_DecalSystem_Reset(decalsystem);
9761         decalsystem->model = model;
9762
9763         RSurf_ActiveModelEntity(ent, true, false, false);
9764
9765         Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
9766         Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
9767         VectorNormalize(localnormal);
9768         localsize = worldsize*rsurface.inversematrixscale;
9769         localmins[0] = localorigin[0] - localsize;
9770         localmins[1] = localorigin[1] - localsize;
9771         localmins[2] = localorigin[2] - localsize;
9772         localmaxs[0] = localorigin[0] + localsize;
9773         localmaxs[1] = localorigin[1] + localsize;
9774         localmaxs[2] = localorigin[2] + localsize;
9775
9776         //VectorCopy(localnormal, planes[4]);
9777         //VectorVectors(planes[4], planes[2], planes[0]);
9778         AnglesFromVectors(angles, localnormal, NULL, false);
9779         AngleVectors(angles, planes[0], planes[2], planes[4]);
9780         VectorNegate(planes[0], planes[1]);
9781         VectorNegate(planes[2], planes[3]);
9782         VectorNegate(planes[4], planes[5]);
9783         planes[0][3] = DotProduct(planes[0], localorigin) - localsize;
9784         planes[1][3] = DotProduct(planes[1], localorigin) - localsize;
9785         planes[2][3] = DotProduct(planes[2], localorigin) - localsize;
9786         planes[3][3] = DotProduct(planes[3], localorigin) - localsize;
9787         planes[4][3] = DotProduct(planes[4], localorigin) - localsize;
9788         planes[5][3] = DotProduct(planes[5], localorigin) - localsize;
9789
9790 #if 1
9791 // works
9792 {
9793         matrix4x4_t forwardprojection;
9794         Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize);
9795         Matrix4x4_Invert_Simple(&projection, &forwardprojection);
9796 }
9797 #else
9798 // broken
9799 {
9800         float projectionvector[4][3];
9801         VectorScale(planes[0], ilocalsize, projectionvector[0]);
9802         VectorScale(planes[2], ilocalsize, projectionvector[1]);
9803         VectorScale(planes[4], ilocalsize, projectionvector[2]);
9804         projectionvector[0][0] = planes[0][0] * ilocalsize;
9805         projectionvector[0][1] = planes[1][0] * ilocalsize;
9806         projectionvector[0][2] = planes[2][0] * ilocalsize;
9807         projectionvector[1][0] = planes[0][1] * ilocalsize;
9808         projectionvector[1][1] = planes[1][1] * ilocalsize;
9809         projectionvector[1][2] = planes[2][1] * ilocalsize;
9810         projectionvector[2][0] = planes[0][2] * ilocalsize;
9811         projectionvector[2][1] = planes[1][2] * ilocalsize;
9812         projectionvector[2][2] = planes[2][2] * ilocalsize;
9813         projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]);
9814         projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]);
9815         projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]);
9816         Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]);
9817 }
9818 #endif
9819
9820         dynamic = model->surfmesh.isanimated;
9821         numsurfacelist = model->nummodelsurfaces;
9822         surfacelist = model->sortedmodelsurfaces;
9823         surfaces = model->data_surfaces;
9824
9825         bih = NULL;
9826         bih_triangles_count = -1;
9827         if(!dynamic)
9828         {
9829                 if(model->render_bih.numleafs)
9830                         bih = &model->render_bih;
9831                 else if(model->collision_bih.numleafs)
9832                         bih = &model->collision_bih;
9833         }
9834         if(bih)
9835                 bih_triangles_count = BIH_GetTriangleListForBox(bih, sizeof(bih_triangles) / sizeof(*bih_triangles), bih_triangles, bih_surfaces, localmins, localmaxs);
9836         if(bih_triangles_count == 0)
9837                 return;
9838         if(bih_triangles_count > (int) (sizeof(bih_triangles) / sizeof(*bih_triangles))) // hit too many, likely bad anyway
9839                 return;
9840         if(bih_triangles_count > 0)
9841         {
9842                 for (triangleindex = 0; triangleindex < bih_triangles_count; ++triangleindex)
9843                 {
9844                         surfaceindex = bih_surfaces[triangleindex];
9845                         surface = surfaces + surfaceindex;
9846                         texture = surface->texture;
9847                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9848                                 continue;
9849                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9850                                 continue;
9851                         R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, bih_triangles[triangleindex], surfaceindex);
9852                 }
9853         }
9854         else
9855         {
9856                 for (surfacelistindex = 0;surfacelistindex < numsurfacelist;surfacelistindex++)
9857                 {
9858                         surfaceindex = surfacelist[surfacelistindex];
9859                         surface = surfaces + surfaceindex;
9860                         // check cull box first because it rejects more than any other check
9861                         if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
9862                                 continue;
9863                         // skip transparent surfaces
9864                         texture = surface->texture;
9865                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9866                                 continue;
9867                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9868                                 continue;
9869                         numtriangles = surface->num_triangles;
9870                         for (triangleindex = 0; triangleindex < numtriangles; triangleindex++)
9871                                 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, triangleindex + surface->num_firsttriangle, surfaceindex);
9872                 }
9873         }
9874 }
9875
9876 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
9877 static void R_DecalSystem_ApplySplatEntities(const vec3_t worldorigin, const vec3_t worldnormal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float worldsize, unsigned int decalsequence)
9878 {
9879         int renderentityindex;
9880         float worldmins[3];
9881         float worldmaxs[3];
9882         entity_render_t *ent;
9883
9884         if (!cl_decals_newsystem.integer)
9885                 return;
9886
9887         worldmins[0] = worldorigin[0] - worldsize;
9888         worldmins[1] = worldorigin[1] - worldsize;
9889         worldmins[2] = worldorigin[2] - worldsize;
9890         worldmaxs[0] = worldorigin[0] + worldsize;
9891         worldmaxs[1] = worldorigin[1] + worldsize;
9892         worldmaxs[2] = worldorigin[2] + worldsize;
9893
9894         R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9895
9896         for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
9897         {
9898                 ent = r_refdef.scene.entities[renderentityindex];
9899                 if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
9900                         continue;
9901
9902                 R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9903         }
9904 }
9905
9906 typedef struct r_decalsystem_splatqueue_s
9907 {
9908         vec3_t worldorigin;
9909         vec3_t worldnormal;
9910         float color[4];
9911         float tcrange[4];
9912         float worldsize;
9913         unsigned int decalsequence;
9914 }
9915 r_decalsystem_splatqueue_t;
9916
9917 int r_decalsystem_numqueued = 0;
9918 r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
9919
9920 void R_DecalSystem_SplatEntities(const vec3_t worldorigin, const vec3_t worldnormal, float r, float g, float b, float a, float s1, float t1, float s2, float t2, float worldsize)
9921 {
9922         r_decalsystem_splatqueue_t *queue;
9923
9924         if (!cl_decals_newsystem.integer || r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
9925                 return;
9926
9927         queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
9928         VectorCopy(worldorigin, queue->worldorigin);
9929         VectorCopy(worldnormal, queue->worldnormal);
9930         Vector4Set(queue->color, r, g, b, a);
9931         Vector4Set(queue->tcrange, s1, t1, s2, t2);
9932         queue->worldsize = worldsize;
9933         queue->decalsequence = cl.decalsequence++;
9934 }
9935
9936 static void R_DecalSystem_ApplySplatEntitiesQueue(void)
9937 {
9938         int i;
9939         r_decalsystem_splatqueue_t *queue;
9940
9941         for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
9942                 R_DecalSystem_ApplySplatEntities(queue->worldorigin, queue->worldnormal, queue->color[0], queue->color[1], queue->color[2], queue->color[3], queue->tcrange[0], queue->tcrange[1], queue->tcrange[2], queue->tcrange[3], queue->worldsize, queue->decalsequence);
9943         r_decalsystem_numqueued = 0;
9944 }
9945
9946 extern cvar_t cl_decals_max;
9947 static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
9948 {
9949         int i;
9950         decalsystem_t *decalsystem = &ent->decalsystem;
9951         int numdecals;
9952         unsigned int killsequence;
9953         tridecal_t *decal;
9954         float frametime;
9955         float lifetime;
9956
9957         if (!decalsystem->numdecals)
9958                 return;
9959
9960         if (r_showsurfaces.integer)
9961                 return;
9962
9963         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9964         {
9965                 R_DecalSystem_Reset(decalsystem);
9966                 return;
9967         }
9968
9969         killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
9970         lifetime = cl_decals_time.value + cl_decals_fadetime.value;
9971
9972         if (decalsystem->lastupdatetime)
9973                 frametime = (r_refdef.scene.time - decalsystem->lastupdatetime);
9974         else
9975                 frametime = 0;
9976         decalsystem->lastupdatetime = r_refdef.scene.time;
9977         numdecals = decalsystem->numdecals;
9978
9979         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9980         {
9981                 if (decal->color4f[0][3])
9982                 {
9983                         decal->lived += frametime;
9984                         if (killsequence > decal->decalsequence || decal->lived >= lifetime)
9985                         {
9986                                 memset(decal, 0, sizeof(*decal));
9987                                 if (decalsystem->freedecal > i)
9988                                         decalsystem->freedecal = i;
9989                         }
9990                 }
9991         }
9992         decal = decalsystem->decals;
9993         while (numdecals > 0 && !decal[numdecals-1].color4f[0][3])
9994                 numdecals--;
9995
9996         // collapse the array by shuffling the tail decals into the gaps
9997         for (;;)
9998         {
9999                 while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4f[0][3])
10000                         decalsystem->freedecal++;
10001                 if (decalsystem->freedecal == numdecals)
10002                         break;
10003                 decal[decalsystem->freedecal] = decal[--numdecals];
10004         }
10005
10006         decalsystem->numdecals = numdecals;
10007
10008         if (numdecals <= 0)
10009         {
10010                 // if there are no decals left, reset decalsystem
10011                 R_DecalSystem_Reset(decalsystem);
10012         }
10013 }
10014
10015 extern skinframe_t *decalskinframe;
10016 static void R_DrawModelDecals_Entity(entity_render_t *ent)
10017 {
10018         int i;
10019         decalsystem_t *decalsystem = &ent->decalsystem;
10020         int numdecals;
10021         tridecal_t *decal;
10022         float faderate;
10023         float alpha;
10024         float *v3f;
10025         float *c4f;
10026         float *t2f;
10027         const int *e;
10028         const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
10029         int numtris = 0;
10030
10031         numdecals = decalsystem->numdecals;
10032         if (!numdecals)
10033                 return;
10034
10035         if (r_showsurfaces.integer)
10036                 return;
10037
10038         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
10039         {
10040                 R_DecalSystem_Reset(decalsystem);
10041                 return;
10042         }
10043
10044         // if the model is static it doesn't matter what value we give for
10045         // wantnormals and wanttangents, so this logic uses only rules applicable
10046         // to a model, knowing that they are meaningless otherwise
10047         RSurf_ActiveModelEntity(ent, false, false, false);
10048
10049         decalsystem->lastupdatetime = r_refdef.scene.time;
10050
10051         faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
10052
10053         // update vertex positions for animated models
10054         v3f = decalsystem->vertex3f;
10055         c4f = decalsystem->color4f;
10056         t2f = decalsystem->texcoord2f;
10057         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
10058         {
10059                 if (!decal->color4f[0][3])
10060                         continue;
10061
10062                 if (surfacevisible && !surfacevisible[decal->surfaceindex])
10063                         continue;
10064
10065                 // skip backfaces
10066                 if (decal->triangleindex < 0 && DotProduct(r_refdef.view.origin, decal->plane) < decal->plane[3])
10067                         continue;
10068
10069                 // update color values for fading decals
10070                 if (decal->lived >= cl_decals_time.value)
10071                         alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
10072                 else
10073                         alpha = 1.0f;
10074
10075                 c4f[ 0] = decal->color4f[0][0] * alpha;
10076                 c4f[ 1] = decal->color4f[0][1] * alpha;
10077                 c4f[ 2] = decal->color4f[0][2] * alpha;
10078                 c4f[ 3] = 1;
10079                 c4f[ 4] = decal->color4f[1][0] * alpha;
10080                 c4f[ 5] = decal->color4f[1][1] * alpha;
10081                 c4f[ 6] = decal->color4f[1][2] * alpha;
10082                 c4f[ 7] = 1;
10083                 c4f[ 8] = decal->color4f[2][0] * alpha;
10084                 c4f[ 9] = decal->color4f[2][1] * alpha;
10085                 c4f[10] = decal->color4f[2][2] * alpha;
10086                 c4f[11] = 1;
10087
10088                 t2f[0] = decal->texcoord2f[0][0];
10089                 t2f[1] = decal->texcoord2f[0][1];
10090                 t2f[2] = decal->texcoord2f[1][0];
10091                 t2f[3] = decal->texcoord2f[1][1];
10092                 t2f[4] = decal->texcoord2f[2][0];
10093                 t2f[5] = decal->texcoord2f[2][1];
10094
10095                 // update vertex positions for animated models
10096                 if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
10097                 {
10098                         e = rsurface.modelelement3i + 3*decal->triangleindex;
10099                         VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f);
10100                         VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3);
10101                         VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6);
10102                 }
10103                 else
10104                 {
10105                         VectorCopy(decal->vertex3f[0], v3f);
10106                         VectorCopy(decal->vertex3f[1], v3f + 3);
10107                         VectorCopy(decal->vertex3f[2], v3f + 6);
10108                 }
10109
10110                 if (r_refdef.fogenabled)
10111                 {
10112                         alpha = RSurf_FogVertex(v3f);
10113                         VectorScale(c4f, alpha, c4f);
10114                         alpha = RSurf_FogVertex(v3f + 3);
10115                         VectorScale(c4f + 4, alpha, c4f + 4);
10116                         alpha = RSurf_FogVertex(v3f + 6);
10117                         VectorScale(c4f + 8, alpha, c4f + 8);
10118                 }
10119
10120                 v3f += 9;
10121                 c4f += 12;
10122                 t2f += 6;
10123                 numtris++;
10124         }
10125
10126         if (numtris > 0)
10127         {
10128                 r_refdef.stats[r_stat_drawndecals] += numtris;
10129
10130                 // now render the decals all at once
10131                 // (this assumes they all use one particle font texture!)
10132                 RSurf_ActiveCustomEntity(&rsurface.matrix, &rsurface.inversematrix, rsurface.ent_flags, ent->shadertime, 1, 1, 1, 1, numdecals*3, decalsystem->vertex3f, decalsystem->texcoord2f, NULL, NULL, NULL, decalsystem->color4f, numtris, decalsystem->element3i, decalsystem->element3s, false, false);
10133 //              R_Mesh_ResetTextureState();
10134                 R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
10135                 GL_DepthMask(false);
10136                 GL_DepthRange(0, 1);
10137                 GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
10138                 GL_DepthTest(true);
10139                 GL_CullFace(GL_NONE);
10140                 GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
10141                 R_SetupShader_Generic(decalskinframe->base, NULL, GL_MODULATE, 1, false, false, false);
10142                 R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
10143         }
10144 }
10145
10146 static void R_DrawModelDecals(void)
10147 {
10148         int i, numdecals;
10149
10150         // fade faster when there are too many decals
10151         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
10152         for (i = 0;i < r_refdef.scene.numentities;i++)
10153                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
10154
10155         R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
10156         for (i = 0;i < r_refdef.scene.numentities;i++)
10157                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
10158                         R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
10159
10160         R_DecalSystem_ApplySplatEntitiesQueue();
10161
10162         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
10163         for (i = 0;i < r_refdef.scene.numentities;i++)
10164                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
10165
10166         r_refdef.stats[r_stat_totaldecals] += numdecals;
10167
10168         if (r_showsurfaces.integer)
10169                 return;
10170
10171         R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
10172
10173         for (i = 0;i < r_refdef.scene.numentities;i++)
10174         {
10175                 if (!r_refdef.viewcache.entityvisible[i])
10176                         continue;
10177                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
10178                         R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
10179         }
10180 }
10181
10182 extern cvar_t mod_collision_bih;
10183 static void R_DrawDebugModel(void)
10184 {
10185         entity_render_t *ent = rsurface.entity;
10186         int i, j, flagsmask;
10187         const msurface_t *surface;
10188         dp_model_t *model = ent->model;
10189
10190         if (!sv.active  && !cls.demoplayback && ent != r_refdef.scene.worldentity)
10191                 return;
10192
10193         if (r_showoverdraw.value > 0)
10194         {
10195                 float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
10196                 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
10197                 R_SetupShader_Generic_NoTexture(false, false);
10198                 GL_DepthTest(false);
10199                 GL_DepthMask(false);
10200                 GL_DepthRange(0, 1);
10201                 GL_BlendFunc(GL_ONE, GL_ONE);
10202                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
10203                 {
10204                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
10205                                 continue;
10206                         rsurface.texture = R_GetCurrentTexture(surface->texture);
10207                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
10208                         {
10209                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface);
10210                                 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
10211                                 if (!rsurface.texture->currentlayers->depthmask)
10212                                         GL_Color(c, 0, 0, 1.0f);
10213                                 else if (ent == r_refdef.scene.worldentity)
10214                                         GL_Color(c, c, c, 1.0f);
10215                                 else
10216                                         GL_Color(0, c, 0, 1.0f);
10217                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
10218                                 RSurf_DrawBatch();
10219                         }
10220                 }
10221                 rsurface.texture = NULL;
10222         }
10223
10224         flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
10225
10226 //      R_Mesh_ResetTextureState();
10227         R_SetupShader_Generic_NoTexture(false, false);
10228         GL_DepthRange(0, 1);
10229         GL_DepthTest(!r_showdisabledepthtest.integer);
10230         GL_DepthMask(false);
10231         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
10232
10233         if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs)
10234         {
10235                 int triangleindex;
10236                 int bihleafindex;
10237                 qboolean cullbox = false;
10238                 const q3mbrush_t *brush;
10239                 const bih_t *bih = &model->collision_bih;
10240                 const bih_leaf_t *bihleaf;
10241                 float vertex3f[3][3];
10242                 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
10243                 for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
10244                 {
10245                         if (cullbox && R_CullBox(bihleaf->mins, bihleaf->maxs))
10246                                 continue;
10247                         switch (bihleaf->type)
10248                         {
10249                         case BIH_BRUSH:
10250                                 brush = model->brush.data_brushes + bihleaf->itemindex;
10251                                 if (brush->colbrushf && brush->colbrushf->numtriangles)
10252                                 {
10253                                         GL_Color((bihleafindex & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 5) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 10) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, r_showcollisionbrushes.value);
10254                                         R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL);
10255                                         R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0);
10256                                 }
10257                                 break;
10258                         case BIH_COLLISIONTRIANGLE:
10259                                 triangleindex = bihleaf->itemindex;
10260                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
10261                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
10262                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
10263                                 GL_Color((bihleafindex & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 5) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 10) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, r_showcollisionbrushes.value);
10264                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
10265                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
10266                                 break;
10267                         case BIH_RENDERTRIANGLE:
10268                                 triangleindex = bihleaf->itemindex;
10269                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
10270                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
10271                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]);
10272                                 GL_Color((bihleafindex & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 5) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 10) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, r_showcollisionbrushes.value);
10273                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
10274                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
10275                                 break;
10276                         }
10277                 }
10278         }
10279
10280         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
10281
10282 #ifndef USE_GLES2
10283         if (r_showtris.value > 0 && qglPolygonMode)
10284         {
10285                 if (r_showdisabledepthtest.integer)
10286                 {
10287                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
10288                         GL_DepthMask(false);
10289                 }
10290                 else
10291                 {
10292                         GL_BlendFunc(GL_ONE, GL_ZERO);
10293                         GL_DepthMask(true);
10294                 }
10295                 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR
10296                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
10297                 {
10298                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
10299                                 continue;
10300                         rsurface.texture = R_GetCurrentTexture(surface->texture);
10301                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
10302                         {
10303                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
10304                                 if (!rsurface.texture->currentlayers->depthmask)
10305                                         GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value);
10306                                 else if (ent == r_refdef.scene.worldentity)
10307                                         GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
10308                                 else
10309                                         GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
10310                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
10311                                 RSurf_DrawBatch();
10312                         }
10313                 }
10314                 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);CHECKGLERROR
10315                 rsurface.texture = NULL;
10316         }
10317
10318 # if 0
10319         // FIXME!  implement r_shownormals with just triangles
10320         if (r_shownormals.value != 0 && qglBegin)
10321         {
10322                 int l, k;
10323                 vec3_t v;
10324                 if (r_showdisabledepthtest.integer)
10325                 {
10326                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
10327                         GL_DepthMask(false);
10328                 }
10329                 else
10330                 {
10331                         GL_BlendFunc(GL_ONE, GL_ZERO);
10332                         GL_DepthMask(true);
10333                 }
10334                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
10335                 {
10336                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
10337                                 continue;
10338                         rsurface.texture = R_GetCurrentTexture(surface->texture);
10339                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
10340                         {
10341                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
10342                                 qglBegin(GL_LINES);
10343                                 if (r_shownormals.value < 0 && rsurface.batchnormal3f)
10344                                 {
10345                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10346                                         {
10347                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10348                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10349                                                 qglVertex3f(v[0], v[1], v[2]);
10350                                                 VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10351                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10352                                                 qglVertex3f(v[0], v[1], v[2]);
10353                                         }
10354                                 }
10355                                 if (r_shownormals.value > 0 && rsurface.batchsvector3f)
10356                                 {
10357                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10358                                         {
10359                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10360                                                 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
10361                                                 qglVertex3f(v[0], v[1], v[2]);
10362                                                 VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
10363                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10364                                                 qglVertex3f(v[0], v[1], v[2]);
10365                                         }
10366                                 }
10367                                 if (r_shownormals.value > 0 && rsurface.batchtvector3f)
10368                                 {
10369                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10370                                         {
10371                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10372                                                 GL_Color(0, r_refdef.view.colorscale, 0, 1);
10373                                                 qglVertex3f(v[0], v[1], v[2]);
10374                                                 VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
10375                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10376                                                 qglVertex3f(v[0], v[1], v[2]);
10377                                         }
10378                                 }
10379                                 if (r_shownormals.value > 0 && rsurface.batchnormal3f)
10380                                 {
10381                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10382                                         {
10383                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10384                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10385                                                 qglVertex3f(v[0], v[1], v[2]);
10386                                                 VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10387                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10388                                                 qglVertex3f(v[0], v[1], v[2]);
10389                                         }
10390                                 }
10391                                 qglEnd();
10392                                 CHECKGLERROR
10393                         }
10394                 }
10395                 rsurface.texture = NULL;
10396         }
10397 # endif
10398 #endif
10399 }
10400
10401 int r_maxsurfacelist = 0;
10402 const msurface_t **r_surfacelist = NULL;
10403 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass)
10404 {
10405         int i, j, endj, flagsmask;
10406         dp_model_t *model = ent->model;
10407         msurface_t *surfaces;
10408         unsigned char *update;
10409         int numsurfacelist = 0;
10410         if (model == NULL)
10411                 return;
10412
10413         if (r_maxsurfacelist < model->num_surfaces)
10414         {
10415                 r_maxsurfacelist = model->num_surfaces;
10416                 if (r_surfacelist)
10417                         Mem_Free((msurface_t **)r_surfacelist);
10418                 r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
10419         }
10420
10421         if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
10422                 RSurf_ActiveModelEntity(ent, false, false, false);
10423         else if (prepass)
10424                 RSurf_ActiveModelEntity(ent, true, true, true);
10425         else if (depthonly)
10426                 RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
10427         else
10428                 RSurf_ActiveModelEntity(ent, true, true, false);
10429
10430         surfaces = model->data_surfaces;
10431         update = model->brushq1.lightmapupdateflags;
10432
10433         // update light styles
10434         if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0)
10435         {
10436                 model_brush_lightstyleinfo_t *style;
10437                 for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++)
10438                 {
10439                         if (style->value != r_refdef.scene.lightstylevalue[style->style])
10440                         {
10441                                 int *list = style->surfacelist;
10442                                 style->value = r_refdef.scene.lightstylevalue[style->style];
10443                                 for (j = 0;j < style->numsurfaces;j++)
10444                                         update[list[j]] = true;
10445                         }
10446                 }
10447         }
10448
10449         flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
10450
10451         if (debug)
10452         {
10453                 R_DrawDebugModel();
10454                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10455                 return;
10456         }
10457
10458         rsurface.lightmaptexture = NULL;
10459         rsurface.deluxemaptexture = NULL;
10460         rsurface.uselightmaptexture = false;
10461         rsurface.texture = NULL;
10462         rsurface.rtlight = NULL;
10463         numsurfacelist = 0;
10464         // add visible surfaces to draw list
10465         if (ent == r_refdef.scene.worldentity)
10466         {
10467                 // for the world entity, check surfacevisible
10468                 for (i = 0;i < model->nummodelsurfaces;i++)
10469                 {
10470                         j = model->sortedmodelsurfaces[i];
10471                         if (r_refdef.viewcache.world_surfacevisible[j])
10472                                 r_surfacelist[numsurfacelist++] = surfaces + j;
10473                 }
10474         }
10475         else
10476         {
10477                 // add all surfaces
10478                 for (i = 0; i < model->nummodelsurfaces; i++)
10479                         r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i];
10480         }
10481         // don't do anything if there were no surfaces
10482         if (!numsurfacelist)
10483         {
10484                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10485                 return;
10486         }
10487         // update lightmaps if needed
10488         if (update)
10489         {
10490                 int updated = 0;
10491                 for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
10492                 {
10493                         if (update[j])
10494                         {
10495                                 updated++;
10496                                 R_BuildLightMap(ent, surfaces + j);
10497                         }
10498                 }
10499         }
10500
10501         R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass);
10502
10503         // add to stats if desired
10504         if (r_speeds.integer && !skysurfaces && !depthonly)
10505         {
10506                 r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist;
10507                 for (j = 0;j < numsurfacelist;j++)
10508                         r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
10509         }
10510
10511         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10512 }
10513
10514 void R_DebugLine(vec3_t start, vec3_t end)
10515 {
10516         dp_model_t *mod = CL_Mesh_UI();
10517         msurface_t *surf;
10518         int e0, e1, e2, e3;
10519         float offsetx, offsety, x1, y1, x2, y2, width = 1.0f;
10520         float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f, alpha1 = 0.25f;
10521         float r2 = 1.0f, g2 = 1.0f, b2 = 0.0f, alpha2 = 0.25f;
10522         vec4_t w[2], s[2];
10523
10524         // transform to screen coords first
10525         Vector4Set(w[0], start[0], start[1], start[2], 1);
10526         Vector4Set(w[1], end[0], end[1], end[2], 1);
10527         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
10528         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
10529         x1 = s[0][0] * vid_conwidth.value / vid.width;
10530         y1 = (vid.height - s[0][1]) * vid_conheight.value / vid.height;
10531         x2 = s[1][0] * vid_conwidth.value / vid.width;
10532         y2 = (vid.height - s[1][1]) * vid_conheight.value / vid.height;
10533         //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
10534
10535         // add the line to the UI mesh for drawing later
10536
10537         // width is measured in real pixels
10538         if (fabs(x2 - x1) > fabs(y2 - y1))
10539         {
10540                 offsetx = 0;
10541                 offsety = 0.5f * width * vid_conheight.value / vid.height;
10542         }
10543         else
10544         {
10545                 offsetx = 0.5f * width * vid_conwidth.value / vid.width;
10546                 offsety = 0;
10547         }
10548         surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, "white", 0, 0, MATERIALFLAG_VERTEXCOLOR), true);
10549         e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10550         e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10551         e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10552         e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10553         Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
10554         Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
10555
10556 }
10557
10558
10559 void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass)
10560 {
10561         int q;
10562         static texture_t texture;
10563         static msurface_t surface;
10564         const msurface_t *surfacelist = &surface;
10565
10566         // fake enough texture and surface state to render this geometry
10567
10568         texture.update_lastrenderframe = -1; // regenerate this texture
10569         texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
10570         texture.basealpha = 1.0f;
10571         texture.currentskinframe = skinframe;
10572         texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
10573         texture.offsetmapping = OFFSETMAPPING_OFF;
10574         texture.offsetscale = 1;
10575         texture.specularscalemod = 1;
10576         texture.specularpowermod = 1;
10577         texture.transparentsort = TRANSPARENTSORT_DISTANCE;
10578         // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
10579         // JUST GREP FOR "specularscalemod = 1".
10580
10581         for (q = 0; q < 3; q++)
10582         {
10583                 texture.render_glowmod[q] = r_refdef.view.colorscale * r_hdr_glowintensity.value;
10584                 texture.render_modellight_lightdir[q] = q == 2;
10585                 texture.render_modellight_ambient[q] = r_refdef.view.colorscale * r_refdef.scene.ambientintensity;
10586                 texture.render_modellight_diffuse[q] = r_refdef.view.colorscale;
10587                 texture.render_modellight_specular[q] = r_refdef.view.colorscale;
10588                 texture.render_lightmap_ambient[q] = r_refdef.view.colorscale * r_refdef.scene.ambientintensity;
10589                 texture.render_lightmap_diffuse[q] = r_refdef.view.colorscale * r_refdef.scene.lightmapintensity;
10590                 texture.render_lightmap_specular[q] = r_refdef.view.colorscale;
10591                 texture.render_rtlight_diffuse[q] = r_refdef.view.colorscale;
10592                 texture.render_rtlight_specular[q] = r_refdef.view.colorscale;
10593         }
10594         texture.currentalpha = 1.0f;
10595
10596         surface.texture = &texture;
10597         surface.num_triangles = numtriangles;
10598         surface.num_firsttriangle = firsttriangle;
10599         surface.num_vertices = numvertices;
10600         surface.num_firstvertex = firstvertex;
10601
10602         // now render it
10603         rsurface.texture = R_GetCurrentTexture(surface.texture);
10604         rsurface.lightmaptexture = NULL;
10605         rsurface.deluxemaptexture = NULL;
10606         rsurface.uselightmaptexture = false;
10607         R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass);
10608 }
10609
10610 void R_DrawCustomSurface_Texture(texture_t *texture, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass)
10611 {
10612         static msurface_t surface;
10613         const msurface_t *surfacelist = &surface;
10614
10615         // fake enough texture and surface state to render this geometry
10616         surface.texture = texture;
10617         surface.num_triangles = numtriangles;
10618         surface.num_firsttriangle = firsttriangle;
10619         surface.num_vertices = numvertices;
10620         surface.num_firstvertex = firstvertex;
10621
10622         // now render it
10623         rsurface.texture = R_GetCurrentTexture(surface.texture);
10624         rsurface.lightmaptexture = NULL;
10625         rsurface.deluxemaptexture = NULL;
10626         rsurface.uselightmaptexture = false;
10627         R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass);
10628 }