]> git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rmain.c
Fix bugs with unloading of cachepic skinframes in QC menus - the reloading was broken...
[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         }
4549
4550         //rtwidth = viewfbo ? R_TextureWidth(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.width;
4551         rtheight = viewfbo ? R_TextureHeight(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.height;
4552
4553         if (!r_refdef.view.useperspective)
4554                 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);
4555         else if (vid.stencil && r_useinfinitefarclip.integer)
4556                 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);
4557         else
4558                 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);
4559         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4560         R_SetViewport(&r_refdef.view.viewport);
4561 }
4562
4563 void R_EntityMatrix(const matrix4x4_t *matrix)
4564 {
4565         if (gl_modelmatrixchanged || memcmp(matrix, &gl_modelmatrix, sizeof(matrix4x4_t)))
4566         {
4567                 gl_modelmatrixchanged = false;
4568                 gl_modelmatrix = *matrix;
4569                 Matrix4x4_Concat(&gl_modelviewmatrix, &gl_viewmatrix, &gl_modelmatrix);
4570                 Matrix4x4_Concat(&gl_modelviewprojectionmatrix, &gl_projectionmatrix, &gl_modelviewmatrix);
4571                 Matrix4x4_ToArrayFloatGL(&gl_modelviewmatrix, gl_modelview16f);
4572                 Matrix4x4_ToArrayFloatGL(&gl_modelviewprojectionmatrix, gl_modelviewprojection16f);
4573                 CHECKGLERROR
4574                 switch(vid.renderpath)
4575                 {
4576                 case RENDERPATH_GL20:
4577                 case RENDERPATH_GLES2:
4578                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
4579                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
4580                         break;
4581                 }
4582         }
4583 }
4584
4585 void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2)
4586 {
4587         r_viewport_t viewport;
4588
4589         CHECKGLERROR
4590
4591         // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
4592         R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, vid.height - viewheight - viewy, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
4593         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4594         R_SetViewport(&viewport);
4595         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
4596         GL_Color(1, 1, 1, 1);
4597         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4598         GL_BlendFunc(GL_ONE, GL_ZERO);
4599         GL_ScissorTest(false);
4600         GL_DepthMask(false);
4601         GL_DepthRange(0, 1);
4602         GL_DepthTest(false);
4603         GL_DepthFunc(GL_LEQUAL);
4604         R_EntityMatrix(&identitymatrix);
4605         R_Mesh_ResetTextureState();
4606         GL_PolygonOffset(0, 0);
4607         R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
4608         switch(vid.renderpath)
4609         {
4610         case RENDERPATH_GL20:
4611         case RENDERPATH_GLES2:
4612                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4613                 break;
4614         }
4615         GL_CullFace(GL_NONE);
4616
4617         CHECKGLERROR
4618 }
4619
4620 void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4621 {
4622         R_ResetViewRendering2D_Common(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight, 1.0f, 1.0f);
4623 }
4624
4625 void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4626 {
4627         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
4628         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4629         GL_Color(1, 1, 1, 1);
4630         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4631         GL_BlendFunc(GL_ONE, GL_ZERO);
4632         GL_ScissorTest(true);
4633         GL_DepthMask(true);
4634         GL_DepthRange(0, 1);
4635         GL_DepthTest(true);
4636         GL_DepthFunc(GL_LEQUAL);
4637         R_EntityMatrix(&identitymatrix);
4638         R_Mesh_ResetTextureState();
4639         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4640         R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
4641         switch(vid.renderpath)
4642         {
4643         case RENDERPATH_GL20:
4644         case RENDERPATH_GLES2:
4645                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4646                 break;
4647         }
4648         GL_CullFace(r_refdef.view.cullface_back);
4649 }
4650
4651 /*
4652 ================
4653 R_RenderView_UpdateViewVectors
4654 ================
4655 */
4656 void R_RenderView_UpdateViewVectors(void)
4657 {
4658         // break apart the view matrix into vectors for various purposes
4659         // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
4660         // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc
4661         Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
4662         VectorNegate(r_refdef.view.left, r_refdef.view.right);
4663         // make an inverted copy of the view matrix for tracking sprites
4664         Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
4665 }
4666
4667 void R_RenderTarget_FreeUnused(qboolean force)
4668 {
4669         int i, j, end;
4670         end = Mem_ExpandableArray_IndexRange(&r_fb.rendertargets);
4671         for (i = 0; i < end; i++)
4672         {
4673                 r_rendertarget_t *r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4674                 // free resources for rendertargets that have not been used for a while
4675                 // (note: this check is run after the frame render, so any targets used
4676                 // this frame will not be affected even at low framerates)
4677                 if (r && (realtime - r->lastusetime > 0.2 || force))
4678                 {
4679                         if (r->fbo)
4680                                 R_Mesh_DestroyFramebufferObject(r->fbo);
4681                         for (j = 0; j < sizeof(r->colortexture) / sizeof(r->colortexture[0]); j++)
4682                                 if (r->colortexture[j])
4683                                         R_FreeTexture(r->colortexture[j]);
4684                         if (r->depthtexture)
4685                                 R_FreeTexture(r->depthtexture);
4686                         Mem_ExpandableArray_FreeRecord(&r_fb.rendertargets, r);
4687                 }
4688         }
4689 }
4690
4691 static void R_CalcTexCoordsForView(float x, float y, float w, float h, float tw, float th, float *texcoord2f)
4692 {
4693         float iw = 1.0f / tw, ih = 1.0f / th, x1, y1, x2, y2;
4694         x1 = x * iw;
4695         x2 = (x + w) * iw;
4696         y1 = (th - y) * ih;
4697         y2 = (th - y - h) * ih;
4698         texcoord2f[0] = x1;
4699         texcoord2f[2] = x2;
4700         texcoord2f[4] = x2;
4701         texcoord2f[6] = x1;
4702         texcoord2f[1] = y1;
4703         texcoord2f[3] = y1;
4704         texcoord2f[5] = y2;
4705         texcoord2f[7] = y2;
4706 }
4707
4708 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)
4709 {
4710         int i, j, end;
4711         r_rendertarget_t *r = NULL;
4712         char vabuf[256];
4713         // first try to reuse an existing slot if possible
4714         end = Mem_ExpandableArray_IndexRange(&r_fb.rendertargets);
4715         for (i = 0; i < end; i++)
4716         {
4717                 r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4718                 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)
4719                         break;
4720         }
4721         if (i == end)
4722         {
4723                 // no unused exact match found, so we have to make one in the first unused slot
4724                 r = (r_rendertarget_t *)Mem_ExpandableArray_AllocRecord(&r_fb.rendertargets);
4725                 r->texturewidth = texturewidth;
4726                 r->textureheight = textureheight;
4727                 r->colortextype[0] = colortextype0;
4728                 r->colortextype[1] = colortextype1;
4729                 r->colortextype[2] = colortextype2;
4730                 r->colortextype[3] = colortextype3;
4731                 r->depthtextype = depthtextype;
4732                 r->depthisrenderbuffer = depthisrenderbuffer;
4733                 for (j = 0; j < 4; j++)
4734                         if (r->colortextype[j])
4735                                 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);
4736                 if (r->depthtextype)
4737                 {
4738                         if (r->depthisrenderbuffer)
4739                                 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);
4740                         else
4741                                 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);
4742                 }
4743                 r->fbo = R_Mesh_CreateFramebufferObject(r->depthtexture, r->colortexture[0], r->colortexture[1], r->colortexture[2], r->colortexture[3]);
4744         }
4745         r_refdef.stats[r_stat_rendertargets_used]++;
4746         r_refdef.stats[r_stat_rendertargets_pixels] += r->texturewidth * r->textureheight;
4747         r->lastusetime = realtime;
4748         R_CalcTexCoordsForView(0, 0, r->texturewidth, r->textureheight, r->texturewidth, r->textureheight, r->texcoord2f);
4749         return r;
4750 }
4751
4752 static void R_Water_StartFrame(void)
4753 {
4754         int waterwidth, waterheight;
4755
4756         if (vid.width > (int)vid.maxtexturesize_2d || vid.height > (int)vid.maxtexturesize_2d)
4757                 return;
4758
4759         // set waterwidth and waterheight to the water resolution that will be
4760         // used (often less than the screen resolution for faster rendering)
4761         waterwidth = (int)bound(1, r_refdef.view.width * r_water_resolutionmultiplier.value, r_refdef.view.width);
4762         waterheight = (int)bound(1, r_refdef.view.height * r_water_resolutionmultiplier.value, r_refdef.view.height);
4763         R_GetScaledViewSize(waterwidth, waterheight, &waterwidth, &waterheight);
4764
4765         if (!r_water.integer || r_showsurfaces.integer)
4766                 waterwidth = waterheight = 0;
4767
4768         // set up variables that will be used in shader setup
4769         r_fb.water.waterwidth = waterwidth;
4770         r_fb.water.waterheight = waterheight;
4771         r_fb.water.texturewidth = waterwidth;
4772         r_fb.water.textureheight = waterheight;
4773         r_fb.water.camerawidth = waterwidth;
4774         r_fb.water.cameraheight = waterheight;
4775         r_fb.water.screenscale[0] = 0.5f;
4776         r_fb.water.screenscale[1] = 0.5f;
4777         r_fb.water.screencenter[0] = 0.5f;
4778         r_fb.water.screencenter[1] = 0.5f;
4779         r_fb.water.enabled = waterwidth != 0;
4780
4781         r_fb.water.maxwaterplanes = MAX_WATERPLANES;
4782         r_fb.water.numwaterplanes = 0;
4783 }
4784
4785 void R_Water_AddWaterPlane(msurface_t *surface, int entno)
4786 {
4787         int planeindex, bestplaneindex, vertexindex;
4788         vec3_t mins, maxs, normal, center, v, n;
4789         vec_t planescore, bestplanescore;
4790         mplane_t plane;
4791         r_waterstate_waterplane_t *p;
4792         texture_t *t = R_GetCurrentTexture(surface->texture);
4793
4794         rsurface.texture = t;
4795         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, 1, ((const msurface_t **)&surface));
4796         // if the model has no normals, it's probably off-screen and they were not generated, so don't add it anyway
4797         if (!rsurface.batchnormal3f || rsurface.batchnumvertices < 1)
4798                 return;
4799         // average the vertex normals, find the surface bounds (after deformvertexes)
4800         Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f, v);
4801         Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f, n);
4802         VectorCopy(n, normal);
4803         VectorCopy(v, mins);
4804         VectorCopy(v, maxs);
4805         for (vertexindex = 1;vertexindex < rsurface.batchnumvertices;vertexindex++)
4806         {
4807                 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f + vertexindex*3, v);
4808                 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f + vertexindex*3, n);
4809                 VectorAdd(normal, n, normal);
4810                 mins[0] = min(mins[0], v[0]);
4811                 mins[1] = min(mins[1], v[1]);
4812                 mins[2] = min(mins[2], v[2]);
4813                 maxs[0] = max(maxs[0], v[0]);
4814                 maxs[1] = max(maxs[1], v[1]);
4815                 maxs[2] = max(maxs[2], v[2]);
4816         }
4817         VectorNormalize(normal);
4818         VectorMAM(0.5f, mins, 0.5f, maxs, center);
4819
4820         VectorCopy(normal, plane.normal);
4821         VectorNormalize(plane.normal);
4822         plane.dist = DotProduct(center, plane.normal);
4823         PlaneClassify(&plane);
4824         if (PlaneDiff(r_refdef.view.origin, &plane) < 0)
4825         {
4826                 // skip backfaces (except if nocullface is set)
4827 //              if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE))
4828 //                      return;
4829                 VectorNegate(plane.normal, plane.normal);
4830                 plane.dist *= -1;
4831                 PlaneClassify(&plane);
4832         }
4833
4834
4835         // find a matching plane if there is one
4836         bestplaneindex = -1;
4837         bestplanescore = 1048576.0f;
4838         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4839         {
4840                 if(p->camera_entity == t->camera_entity)
4841                 {
4842                         planescore = 1.0f - DotProduct(plane.normal, p->plane.normal) + fabs(plane.dist - p->plane.dist) * 0.001f;
4843                         if (bestplaneindex < 0 || bestplanescore > planescore)
4844                         {
4845                                 bestplaneindex = planeindex;
4846                                 bestplanescore = planescore;
4847                         }
4848                 }
4849         }
4850         planeindex = bestplaneindex;
4851
4852         // if this surface does not fit any known plane rendered this frame, add one
4853         if (planeindex < 0 || bestplanescore > 0.001f)
4854         {
4855                 if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
4856                 {
4857                         // store the new plane
4858                         planeindex = r_fb.water.numwaterplanes++;
4859                         p = r_fb.water.waterplanes + planeindex;
4860                         p->plane = plane;
4861                         // clear materialflags and pvs
4862                         p->materialflags = 0;
4863                         p->pvsvalid = false;
4864                         p->camera_entity = t->camera_entity;
4865                         VectorCopy(mins, p->mins);
4866                         VectorCopy(maxs, p->maxs);
4867                 }
4868                 else
4869                 {
4870                         // We're totally screwed.
4871                         return;
4872                 }
4873         }
4874         else
4875         {
4876                 // merge mins/maxs when we're adding this surface to the plane
4877                 p = r_fb.water.waterplanes + planeindex;
4878                 p->mins[0] = min(p->mins[0], mins[0]);
4879                 p->mins[1] = min(p->mins[1], mins[1]);
4880                 p->mins[2] = min(p->mins[2], mins[2]);
4881                 p->maxs[0] = max(p->maxs[0], maxs[0]);
4882                 p->maxs[1] = max(p->maxs[1], maxs[1]);
4883                 p->maxs[2] = max(p->maxs[2], maxs[2]);
4884         }
4885         // merge this surface's materialflags into the waterplane
4886         p->materialflags |= t->currentmaterialflags;
4887         if(!(p->materialflags & MATERIALFLAG_CAMERA))
4888         {
4889                 // merge this surface's PVS into the waterplane
4890                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
4891                  && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
4892                 {
4893                         r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
4894                         p->pvsvalid = true;
4895                 }
4896         }
4897 }
4898
4899 extern cvar_t r_drawparticles;
4900 extern cvar_t r_drawdecals;
4901
4902 static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int viewx, int viewy, int viewwidth, int viewheight)
4903 {
4904         int myscissor[4];
4905         r_refdef_view_t originalview;
4906         r_refdef_view_t myview;
4907         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;
4908         r_waterstate_waterplane_t *p;
4909         vec3_t visorigin;
4910         r_rendertarget_t *rt;
4911
4912         originalview = r_refdef.view;
4913
4914         // lowquality hack, temporarily shut down some cvars and restore afterwards
4915         qualityreduction = r_water_lowquality.integer;
4916         if (qualityreduction > 0)
4917         {
4918                 if (qualityreduction >= 1)
4919                 {
4920                         old_r_shadows = r_shadows.integer;
4921                         old_r_worldrtlight = r_shadow_realtime_world.integer;
4922                         old_r_dlight = r_shadow_realtime_dlight.integer;
4923                         Cvar_SetValueQuick(&r_shadows, 0);
4924                         Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
4925                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, 0);
4926                 }
4927                 if (qualityreduction >= 2)
4928                 {
4929                         old_r_dynamic = r_dynamic.integer;
4930                         old_r_particles = r_drawparticles.integer;
4931                         old_r_decals = r_drawdecals.integer;
4932                         Cvar_SetValueQuick(&r_dynamic, 0);
4933                         Cvar_SetValueQuick(&r_drawparticles, 0);
4934                         Cvar_SetValueQuick(&r_drawdecals, 0);
4935                 }
4936         }
4937
4938         for (planeindex = 0, p = r_fb.water.waterplanes; planeindex < r_fb.water.numwaterplanes; planeindex++, p++)
4939         {
4940                 p->rt_reflection = NULL;
4941                 p->rt_refraction = NULL;
4942                 p->rt_camera = NULL;
4943         }
4944
4945         // render views
4946         r_refdef.view = originalview;
4947         r_refdef.view.showdebug = false;
4948         r_refdef.view.width = r_fb.water.waterwidth;
4949         r_refdef.view.height = r_fb.water.waterheight;
4950         r_refdef.view.useclipplane = true;
4951         myview = r_refdef.view;
4952         r_fb.water.renderingscene = true;
4953         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4954         {
4955                 if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
4956                         continue;
4957
4958                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
4959                 {
4960                         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);
4961                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4962                                 goto error;
4963                         r_refdef.view = myview;
4964                         Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
4965                         Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
4966                         if(r_water_scissormode.integer)
4967                         {
4968                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4969                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4970                                 {
4971                                         p->rt_reflection = NULL;
4972                                         p->rt_refraction = NULL;
4973                                         p->rt_camera = NULL;
4974                                         continue;
4975                                 }
4976                         }
4977
4978                         r_refdef.view.clipplane = p->plane;
4979                         // reflected view origin may be in solid, so don't cull with it
4980                         r_refdef.view.usevieworiginculling = false;
4981                         // reverse the cullface settings for this render
4982                         r_refdef.view.cullface_front = GL_FRONT;
4983                         r_refdef.view.cullface_back = GL_BACK;
4984                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4985                         {
4986                                 r_refdef.view.usecustompvs = true;
4987                                 if (p->pvsvalid)
4988                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4989                                 else
4990                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4991                         }
4992
4993                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 2) && !chase_active.integer);
4994                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4995                         GL_ScissorTest(false);
4996                         R_ClearScreen(r_refdef.fogenabled);
4997                         GL_ScissorTest(true);
4998                         if(r_water_scissormode.integer & 2)
4999                                 R_View_UpdateWithScissor(myscissor);
5000                         else
5001                                 R_View_Update();
5002                         R_AnimCache_CacheVisibleEntities();
5003                         if(r_water_scissormode.integer & 1)
5004                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
5005                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5006
5007                         r_fb.water.hideplayer = false;
5008                         p->rt_reflection = rt;
5009                 }
5010
5011                 // render the normal view scene and copy into texture
5012                 // (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)
5013                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
5014                 {
5015                         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);
5016                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
5017                                 goto error;
5018                         r_refdef.view = myview;
5019                         if(r_water_scissormode.integer)
5020                         {
5021                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
5022                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
5023                                 {
5024                                         p->rt_reflection = NULL;
5025                                         p->rt_refraction = NULL;
5026                                         p->rt_camera = NULL;
5027                                         continue;
5028                                 }
5029                         }
5030
5031                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
5032
5033                         r_refdef.view.clipplane = p->plane;
5034                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5035                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5036
5037                         if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity)
5038                         {
5039                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5040                                 r_fb.water.hideplayer = false; // we don't want to hide the player model from these ones
5041                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5042                                 R_RenderView_UpdateViewVectors();
5043                                 if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5044                                 {
5045                                         r_refdef.view.usecustompvs = true;
5046                                         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);
5047                                 }
5048                         }
5049
5050                         PlaneClassify(&r_refdef.view.clipplane);
5051
5052                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5053                         GL_ScissorTest(false);
5054                         R_ClearScreen(r_refdef.fogenabled);
5055                         GL_ScissorTest(true);
5056                         if(r_water_scissormode.integer & 2)
5057                                 R_View_UpdateWithScissor(myscissor);
5058                         else
5059                                 R_View_Update();
5060                         R_AnimCache_CacheVisibleEntities();
5061                         if(r_water_scissormode.integer & 1)
5062                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
5063                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5064
5065                         r_fb.water.hideplayer = false;
5066                         p->rt_refraction = rt;
5067                 }
5068                 else if (p->materialflags & MATERIALFLAG_CAMERA)
5069                 {
5070                         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);
5071                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
5072                                 goto error;
5073                         r_refdef.view = myview;
5074
5075                         r_refdef.view.clipplane = p->plane;
5076                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5077                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5078
5079                         r_refdef.view.width = r_fb.water.camerawidth;
5080                         r_refdef.view.height = r_fb.water.cameraheight;
5081                         r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0);
5082                         r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0);
5083                         r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView
5084                         r_refdef.view.ortho_y = 90; // abused as angle by VM_CL_R_SetView
5085
5086                         if(p->camera_entity)
5087                         {
5088                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5089                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5090                         }
5091
5092                         // note: all of the view is used for displaying... so
5093                         // there is no use in scissoring
5094
5095                         // reverse the cullface settings for this render
5096                         r_refdef.view.cullface_front = GL_FRONT;
5097                         r_refdef.view.cullface_back = GL_BACK;
5098                         // also reverse the view matrix
5099                         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
5100                         R_RenderView_UpdateViewVectors();
5101                         if(p->camera_entity && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5102                         {
5103                                 r_refdef.view.usecustompvs = true;
5104                                 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);
5105                         }
5106                         
5107                         // camera needs no clipplane
5108                         r_refdef.view.useclipplane = false;
5109                         // TODO: is the camera origin always valid?  if so we don't need to clear this
5110                         r_refdef.view.usevieworiginculling = false;
5111
5112                         PlaneClassify(&r_refdef.view.clipplane);
5113
5114                         r_fb.water.hideplayer = false;
5115
5116                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5117                         GL_ScissorTest(false);
5118                         R_ClearScreen(r_refdef.fogenabled);
5119                         GL_ScissorTest(true);
5120                         R_View_Update();
5121                         R_AnimCache_CacheVisibleEntities();
5122                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5123
5124                         r_fb.water.hideplayer = false;
5125                         p->rt_camera = rt;
5126                 }
5127
5128         }
5129         r_fb.water.renderingscene = false;
5130         r_refdef.view = originalview;
5131         R_ResetViewRendering3D(fbo, depthtexture, colortexture, viewx, viewy, viewwidth, viewheight);
5132         R_View_Update();
5133         R_AnimCache_CacheVisibleEntities();
5134         goto finish;
5135 error:
5136         r_refdef.view = originalview;
5137         r_fb.water.renderingscene = false;
5138         Cvar_SetValueQuick(&r_water, 0);
5139         Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed!  Turned off r_water.\n");
5140 finish:
5141         // lowquality hack, restore cvars
5142         if (qualityreduction > 0)
5143         {
5144                 if (qualityreduction >= 1)
5145                 {
5146                         Cvar_SetValueQuick(&r_shadows, old_r_shadows);
5147                         Cvar_SetValueQuick(&r_shadow_realtime_world, old_r_worldrtlight);
5148                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, old_r_dlight);
5149                 }
5150                 if (qualityreduction >= 2)
5151                 {
5152                         Cvar_SetValueQuick(&r_dynamic, old_r_dynamic);
5153                         Cvar_SetValueQuick(&r_drawparticles, old_r_particles);
5154                         Cvar_SetValueQuick(&r_drawdecals, old_r_decals);
5155                 }
5156         }
5157 }
5158
5159 static void R_Bloom_StartFrame(void)
5160 {
5161         int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight;
5162         int viewwidth, viewheight;
5163         textype_t textype = TEXTYPE_COLORBUFFER;
5164
5165         // clear the pointers to rendertargets from last frame as they're stale
5166         r_fb.rt_screen = NULL;
5167         r_fb.rt_bloom = NULL;
5168
5169         switch (vid.renderpath)
5170         {
5171         case RENDERPATH_GL20:
5172                 r_fb.usedepthtextures = r_usedepthtextures.integer != 0;
5173                 if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
5174                 if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
5175                 // for simplicity, bloom requires FBO render to texture, which basically all video drivers support now
5176                 if (!vid.support.ext_framebuffer_object)
5177                         return;
5178                 break;
5179         case RENDERPATH_GLES2:
5180                 r_fb.usedepthtextures = false;
5181                 break;
5182         }
5183
5184         if (r_viewscale_fpsscaling.integer)
5185         {
5186                 double actualframetime;
5187                 double targetframetime;
5188                 double adjust;
5189                 actualframetime = r_refdef.lastdrawscreentime;
5190                 targetframetime = (1.0 / r_viewscale_fpsscaling_target.value);
5191                 adjust = (targetframetime - actualframetime) * r_viewscale_fpsscaling_multiply.value;
5192                 adjust = bound(-r_viewscale_fpsscaling_stepmax.value, adjust, r_viewscale_fpsscaling_stepmax.value);
5193                 if (r_viewscale_fpsscaling_stepsize.value > 0)
5194                         adjust = (int)(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5195                 viewscalefpsadjusted += adjust;
5196                 viewscalefpsadjusted = bound(r_viewscale_fpsscaling_min.value, viewscalefpsadjusted, 1.0f);
5197         }
5198         else
5199                 viewscalefpsadjusted = 1.0f;
5200
5201         R_GetScaledViewSize(r_refdef.view.width, r_refdef.view.height, &viewwidth, &viewheight);
5202
5203         // set bloomwidth and bloomheight to the bloom resolution that will be
5204         // used (often less than the screen resolution for faster rendering)
5205         r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, vid.width);
5206         r_fb.bloomheight = r_fb.bloomwidth * vid.height / vid.width;
5207         r_fb.bloomheight = bound(1, r_fb.bloomheight, vid.height);
5208         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d);
5209         r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d);
5210
5211         // calculate desired texture sizes
5212         screentexturewidth = viewwidth;
5213         screentextureheight = viewheight;
5214         bloomtexturewidth = r_fb.bloomwidth;
5215         bloomtextureheight = r_fb.bloomheight;
5216
5217         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))
5218         {
5219                 Cvar_SetValueQuick(&r_bloom, 0);
5220                 Cvar_SetValueQuick(&r_motionblur, 0);
5221                 Cvar_SetValueQuick(&r_damageblur, 0);
5222         }
5223
5224         // allocate motionblur ghost texture if needed - this is the only persistent texture and is only useful on the main view
5225         if (r_refdef.view.ismain && (r_fb.screentexturewidth != screentexturewidth || r_fb.screentextureheight != screentextureheight || r_fb.textype != textype))
5226         {
5227                 if (r_fb.ghosttexture)
5228                         R_FreeTexture(r_fb.ghosttexture);
5229                 r_fb.ghosttexture = NULL;
5230
5231                 r_fb.screentexturewidth = screentexturewidth;
5232                 r_fb.screentextureheight = screentextureheight;
5233                 r_fb.textype = textype;
5234
5235                 if (r_fb.screentexturewidth && r_fb.screentextureheight)
5236                 {
5237                         if (r_motionblur.value > 0 || r_damageblur.value > 0)
5238                                 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);
5239                         r_fb.ghosttexture_valid = false;
5240                 }
5241         }
5242
5243         if (r_bloom.integer)
5244         {
5245                 // bloom texture is a different resolution
5246                 r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, r_refdef.view.width);
5247                 r_fb.bloomheight = r_fb.bloomwidth * r_refdef.view.height / r_refdef.view.width;
5248                 r_fb.bloomheight = bound(1, r_fb.bloomheight, r_refdef.view.height);
5249         }
5250         else
5251                 r_fb.bloomwidth = r_fb.bloomheight = 0;
5252
5253         r_fb.rt_screen = R_RenderTarget_Get(screentexturewidth, screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5254
5255         r_refdef.view.clear = true;
5256 }
5257
5258 static void R_Bloom_MakeTexture(void)
5259 {
5260         int x, range, dir;
5261         float xoffset, yoffset, r, brighten;
5262         float colorscale = r_bloom_colorscale.value;
5263         r_viewport_t bloomviewport;
5264         r_rendertarget_t *prev, *cur;
5265         textype_t textype = r_fb.rt_screen->colortextype[0];
5266
5267         r_refdef.stats[r_stat_bloom]++;
5268
5269         R_Viewport_InitOrtho(&bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
5270
5271         // scale down screen texture to the bloom texture size
5272         CHECKGLERROR
5273         prev = r_fb.rt_screen;
5274         cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5275         R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5276         R_SetViewport(&bloomviewport);
5277         GL_CullFace(GL_NONE);
5278         GL_DepthTest(false);
5279         GL_BlendFunc(GL_ONE, GL_ZERO);
5280         GL_Color(colorscale, colorscale, colorscale, 1);
5281         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5282         // TODO: do boxfilter scale-down in shader?
5283         R_SetupShader_Generic(prev->colortexture[0], NULL, GL_MODULATE, 1, false, true, true);
5284         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5285         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5286         // we now have a properly scaled bloom image
5287
5288         // multiply bloom image by itself as many times as desired to darken it
5289         // TODO: if people actually use this it could be done more quickly in the previous shader pass
5290         for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
5291         {
5292                 prev = cur;
5293                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5294                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5295                 x *= 2;
5296                 r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1
5297                 if(x <= 2)
5298                         GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 128);
5299                 GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
5300                 GL_Color(1,1,1,1); // no fix factor supported here
5301                 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5302                 R_SetupShader_Generic(prev->colortexture[0], NULL, GL_MODULATE, 1, false, true, false);
5303                 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5304                 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5305         }
5306
5307         range = r_bloom_blur.integer * r_fb.bloomwidth / 320;
5308         brighten = r_bloom_brighten.value;
5309         brighten = sqrt(brighten);
5310         if(range >= 1)
5311                 brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
5312
5313         for (dir = 0;dir < 2;dir++)
5314         {
5315                 prev = cur;
5316                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5317                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5318                 // blend on at multiple vertical offsets to achieve a vertical blur
5319                 // TODO: do offset blends using GLSL
5320                 // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
5321                 GL_BlendFunc(GL_ONE, GL_ZERO);
5322                 R_SetupShader_Generic(prev->colortexture[0], NULL, GL_MODULATE, 1, false, true, false);
5323                 for (x = -range;x <= range;x++)
5324                 {
5325                         if (!dir){xoffset = 0;yoffset = x;}
5326                         else {xoffset = x;yoffset = 0;}
5327                         xoffset /= (float)prev->texturewidth;
5328                         yoffset /= (float)prev->textureheight;
5329                         // compute a texcoord array with the specified x and y offset
5330                         r_fb.offsettexcoord2f[0] = xoffset+prev->texcoord2f[0];
5331                         r_fb.offsettexcoord2f[1] = yoffset+prev->texcoord2f[1];
5332                         r_fb.offsettexcoord2f[2] = xoffset+prev->texcoord2f[2];
5333                         r_fb.offsettexcoord2f[3] = yoffset+prev->texcoord2f[3];
5334                         r_fb.offsettexcoord2f[4] = xoffset+prev->texcoord2f[4];
5335                         r_fb.offsettexcoord2f[5] = yoffset+prev->texcoord2f[5];
5336                         r_fb.offsettexcoord2f[6] = xoffset+prev->texcoord2f[6];
5337                         r_fb.offsettexcoord2f[7] = yoffset+prev->texcoord2f[7];
5338                         // this r value looks like a 'dot' particle, fading sharply to
5339                         // black at the edges
5340                         // (probably not realistic but looks good enough)
5341                         //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
5342                         //r = brighten/(range*2+1);
5343                         r = brighten / (range * 2 + 1);
5344                         if(range >= 1)
5345                                 r *= (1 - x*x/(float)((range+1)*(range+1)));
5346                         if (r <= 0)
5347                                 continue;
5348                         GL_Color(r, r, r, 1);
5349                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f);
5350                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5351                         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5352                         GL_BlendFunc(GL_ONE, GL_ONE);
5353                 }
5354         }
5355
5356         // now we have the bloom image, so keep track of it
5357         r_fb.rt_bloom = cur;
5358 }
5359
5360 static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5361 {
5362         dpuint64 permutation;
5363         float uservecs[4][4];
5364         rtexture_t *viewtexture;
5365         rtexture_t *bloomtexture;
5366
5367         R_EntityMatrix(&identitymatrix);
5368
5369         if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
5370         {
5371                 // declare variables
5372                 float blur_factor, blur_mouseaccel, blur_velocity;
5373                 static float blur_average; 
5374                 static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
5375
5376                 // set a goal for the factoring
5377                 blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value) 
5378                         / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
5379                 blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value) 
5380                         / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
5381                 blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value) 
5382                         + (blur_mouseaccel * r_motionblur_mousefactor.value));
5383
5384                 // from the goal, pick an averaged value between goal and last value
5385                 cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
5386                 blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
5387
5388                 // enforce minimum amount of blur 
5389                 blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
5390
5391                 //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
5392
5393                 // calculate values into a standard alpha
5394                 cl.motionbluralpha = 1 - exp(-
5395                                 (
5396                                         (r_motionblur.value * blur_factor / 80)
5397                                         +
5398                                         (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
5399                                 )
5400                                 /
5401                                 max(0.0001, cl.time - cl.oldtime) // fps independent
5402                                 );
5403
5404                 // randomization for the blur value to combat persistent ghosting
5405                 cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
5406                 cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
5407
5408                 // apply the blur
5409                 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5410                 if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
5411                 {
5412                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5413                         GL_Color(1, 1, 1, cl.motionbluralpha);
5414                         R_CalcTexCoordsForView(0, 0, viewwidth, viewheight, viewwidth, viewheight, r_fb.ghosttexcoord2f);
5415                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.ghosttexcoord2f);
5416                         R_SetupShader_Generic(r_fb.ghosttexture, NULL, GL_MODULATE, 1, false, true, true);
5417                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5418                         r_refdef.stats[r_stat_bloom_drawpixels] += viewwidth * viewheight;
5419                 }
5420
5421                 // updates old view angles for next pass
5422                 VectorCopy(cl.viewangles, blur_oldangles);
5423
5424                 // copy view into the ghost texture
5425                 R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, viewx, viewy, viewwidth, viewheight);
5426                 r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight;
5427                 r_fb.ghosttexture_valid = true;
5428         }
5429
5430         if (r_fb.bloomwidth)
5431         {
5432                 // make the bloom texture
5433                 R_Bloom_MakeTexture();
5434         }
5435
5436 #if _MSC_VER >= 1400
5437 #define sscanf sscanf_s
5438 #endif
5439         memset(uservecs, 0, sizeof(uservecs));
5440         if (r_glsl_postprocess_uservec1_enable.integer)
5441                 sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
5442         if (r_glsl_postprocess_uservec2_enable.integer)
5443                 sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
5444         if (r_glsl_postprocess_uservec3_enable.integer)
5445                 sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
5446         if (r_glsl_postprocess_uservec4_enable.integer)
5447                 sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
5448
5449         // render to the screen fbo
5450         R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5451         GL_Color(1, 1, 1, 1);
5452         GL_BlendFunc(GL_ONE, GL_ZERO);
5453
5454         viewtexture = r_fb.rt_screen->colortexture[0];
5455         bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL;
5456
5457         if (r_rendertarget_debug.integer >= 0)
5458         {
5459                 r_rendertarget_t *rt = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, r_rendertarget_debug.integer);
5460                 if (rt && rt->colortexture[0])
5461                 {
5462                         viewtexture = rt->colortexture[0];
5463                         bloomtexture = NULL;
5464                 }
5465         }
5466
5467         R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.rt_screen->texcoord2f, bloomtexture ? r_fb.rt_bloom->texcoord2f : NULL);
5468         switch(vid.renderpath)
5469         {
5470         case RENDERPATH_GL20:
5471         case RENDERPATH_GLES2:
5472                 permutation =
5473                         (r_fb.bloomwidth ? SHADERPERMUTATION_BLOOM : 0)
5474                         | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
5475                         | (!vid_gammatables_trivial ? SHADERPERMUTATION_GAMMARAMPS : 0)
5476                         | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
5477                         | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
5478                 R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation);
5479                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First     , viewtexture);
5480                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second    , bloomtexture);
5481                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps       );
5482                 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]);
5483                 if (r_glsl_permutation->loc_PixelSize               >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize         , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
5484                 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]);
5485                 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]);
5486                 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]);
5487                 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]);
5488                 if (r_glsl_permutation->loc_Saturation              >= 0) qglUniform1f(r_glsl_permutation->loc_Saturation        , r_glsl_saturation.value);
5489                 if (r_glsl_permutation->loc_PixelToScreenTexCoord   >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
5490                 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);
5491                 break;
5492         }
5493         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5494         r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height;
5495 }
5496
5497 matrix4x4_t r_waterscrollmatrix;
5498
5499 void R_UpdateFog(void)
5500 {
5501         // Nehahra fog
5502         if (gamemode == GAME_NEHAHRA)
5503         {
5504                 if (gl_fogenable.integer)
5505                 {
5506                         r_refdef.oldgl_fogenable = true;
5507                         r_refdef.fog_density = gl_fogdensity.value;
5508                         r_refdef.fog_red = gl_fogred.value;
5509                         r_refdef.fog_green = gl_foggreen.value;
5510                         r_refdef.fog_blue = gl_fogblue.value;
5511                         r_refdef.fog_alpha = 1;
5512                         r_refdef.fog_start = 0;
5513                         r_refdef.fog_end = gl_skyclip.value;
5514                         r_refdef.fog_height = 1<<30;
5515                         r_refdef.fog_fadedepth = 128;
5516                 }
5517                 else if (r_refdef.oldgl_fogenable)
5518                 {
5519                         r_refdef.oldgl_fogenable = false;
5520                         r_refdef.fog_density = 0;
5521                         r_refdef.fog_red = 0;
5522                         r_refdef.fog_green = 0;
5523                         r_refdef.fog_blue = 0;
5524                         r_refdef.fog_alpha = 0;
5525                         r_refdef.fog_start = 0;
5526                         r_refdef.fog_end = 0;
5527                         r_refdef.fog_height = 1<<30;
5528                         r_refdef.fog_fadedepth = 128;
5529                 }
5530         }
5531
5532         // fog parms
5533         r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1);
5534         r_refdef.fog_start = max(0, r_refdef.fog_start);
5535         r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end);
5536
5537         if (r_refdef.fog_density && r_drawfog.integer)
5538         {
5539                 r_refdef.fogenabled = true;
5540                 // this is the point where the fog reaches 0.9986 alpha, which we
5541                 // consider a good enough cutoff point for the texture
5542                 // (0.9986 * 256 == 255.6)
5543                 if (r_fog_exp2.integer)
5544                         r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start;
5545                 else
5546                         r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start;
5547                 r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end);
5548                 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
5549                 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
5550                 if (strcmp(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename))
5551                         R_BuildFogHeightTexture();
5552                 // fog color was already set
5553                 // update the fog texture
5554                 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)
5555                         R_BuildFogTexture();
5556                 r_refdef.fog_height_texcoordscale = 1.0f / max(0.125f, r_refdef.fog_fadedepth);
5557                 r_refdef.fog_height_tablescale = r_refdef.fog_height_tablesize * r_refdef.fog_height_texcoordscale;
5558         }
5559         else
5560                 r_refdef.fogenabled = false;
5561
5562         // fog color
5563         if (r_refdef.fog_density)
5564         {
5565                 r_refdef.fogcolor[0] = r_refdef.fog_red;
5566                 r_refdef.fogcolor[1] = r_refdef.fog_green;
5567                 r_refdef.fogcolor[2] = r_refdef.fog_blue;
5568
5569                 Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height);
5570                 r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3];
5571                 r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0;
5572                 r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth);
5573
5574                 {
5575                         vec3_t fogvec;
5576                         VectorCopy(r_refdef.fogcolor, fogvec);
5577                         //   color.rgb *= ContrastBoost * SceneBrightness;
5578                         VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
5579                         r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
5580                         r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f);
5581                         r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f);
5582                 }
5583         }
5584 }
5585
5586 void R_UpdateVariables(void)
5587 {
5588         R_Textures_Frame();
5589
5590         r_refdef.scene.ambientintensity = r_ambient.value * (1.0f / 64.0f);
5591
5592         r_refdef.farclip = r_farclip_base.value;
5593         if (r_refdef.scene.worldmodel)
5594                 r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2;
5595         r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
5596
5597         if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
5598                 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
5599         r_refdef.polygonfactor = 0;
5600         r_refdef.polygonoffset = 0;
5601         r_refdef.shadowpolygonfactor = r_refdef.polygonfactor + r_shadow_polygonfactor.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
5602         r_refdef.shadowpolygonoffset = r_refdef.polygonoffset + r_shadow_polygonoffset.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
5603
5604         r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
5605         r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil;
5606         r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer;
5607         r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil;
5608         r_refdef.scene.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
5609         if (FAKELIGHT_ENABLED)
5610         {
5611                 r_refdef.scene.lightmapintensity *= r_fakelight_intensity.value;
5612         }
5613         else if (r_refdef.scene.worldmodel)
5614         {
5615                 r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
5616         }
5617         if (r_showsurfaces.integer)
5618         {
5619                 r_refdef.scene.rtworld = false;
5620                 r_refdef.scene.rtworldshadows = false;
5621                 r_refdef.scene.rtdlight = false;
5622                 r_refdef.scene.rtdlightshadows = false;
5623                 r_refdef.scene.lightmapintensity = 0;
5624         }
5625
5626         r_gpuskeletal = false;
5627         switch(vid.renderpath)
5628         {
5629         case RENDERPATH_GL20:
5630                 r_gpuskeletal = vid.support.arb_uniform_buffer_object && r_glsl_skeletal.integer && !r_showsurfaces.integer; // FIXME add r_showsurfaces support to GLSL skeletal!
5631         case RENDERPATH_GLES2:
5632                 if(!vid_gammatables_trivial)
5633                 {
5634                         if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
5635                         {
5636                                 // build GLSL gamma texture
5637 #define RAMPWIDTH 256
5638                                 unsigned short ramp[RAMPWIDTH * 3];
5639                                 unsigned char rampbgr[RAMPWIDTH][4];
5640                                 int i;
5641
5642                                 r_texture_gammaramps_serial = vid_gammatables_serial;
5643
5644                                 VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
5645                                 for(i = 0; i < RAMPWIDTH; ++i)
5646                                 {
5647                                         rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5648                                         rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5649                                         rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
5650                                         rampbgr[i][3] = 0;
5651                                 }
5652                                 if (r_texture_gammaramps)
5653                                 {
5654                                         R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1);
5655                                 }
5656                                 else
5657                                 {
5658                                         r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
5659                                 }
5660                         }
5661                 }
5662                 else
5663                 {
5664                         // remove GLSL gamma texture
5665                 }
5666                 break;
5667         }
5668 }
5669
5670 static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT;
5671 static r_refdef_scene_t r_scenes_store[ RST_COUNT ];
5672 /*
5673 ================
5674 R_SelectScene
5675 ================
5676 */
5677 void R_SelectScene( r_refdef_scene_type_t scenetype ) {
5678         if( scenetype != r_currentscenetype ) {
5679                 // store the old scenetype
5680                 r_scenes_store[ r_currentscenetype ] = r_refdef.scene;
5681                 r_currentscenetype = scenetype;
5682                 // move in the new scene
5683                 r_refdef.scene = r_scenes_store[ r_currentscenetype ];
5684         }
5685 }
5686
5687 /*
5688 ================
5689 R_GetScenePointer
5690 ================
5691 */
5692 r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype )
5693 {
5694         // of course, we could also add a qboolean that provides a lock state and a ReleaseScenePointer function..
5695         if( scenetype == r_currentscenetype ) {
5696                 return &r_refdef.scene;
5697         } else {
5698                 return &r_scenes_store[ scenetype ];
5699         }
5700 }
5701
5702 static int R_SortEntities_Compare(const void *ap, const void *bp)
5703 {
5704         const entity_render_t *a = *(const entity_render_t **)ap;
5705         const entity_render_t *b = *(const entity_render_t **)bp;
5706
5707         // 1. compare model
5708         if(a->model < b->model)
5709                 return -1;
5710         if(a->model > b->model)
5711                 return +1;
5712
5713         // 2. compare skin
5714         // TODO possibly calculate the REAL skinnum here first using
5715         // skinscenes?
5716         if(a->skinnum < b->skinnum)
5717                 return -1;
5718         if(a->skinnum > b->skinnum)
5719                 return +1;
5720
5721         // everything we compared is equal
5722         return 0;
5723 }
5724 static void R_SortEntities(void)
5725 {
5726         // below or equal 2 ents, sorting never gains anything
5727         if(r_refdef.scene.numentities <= 2)
5728                 return;
5729         // sort
5730         qsort(r_refdef.scene.entities, r_refdef.scene.numentities, sizeof(*r_refdef.scene.entities), R_SortEntities_Compare);
5731 }
5732
5733 /*
5734 ================
5735 R_RenderView
5736 ================
5737 */
5738 extern cvar_t r_shadow_bouncegrid;
5739 extern cvar_t v_isometric;
5740 extern void V_MakeViewIsometric(void);
5741 void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5742 {
5743         matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
5744         int viewfbo = 0;
5745         rtexture_t *viewdepthtexture = NULL;
5746         rtexture_t *viewcolortexture = NULL;
5747         int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
5748
5749         // finish any 2D rendering that was queued
5750         DrawQ_Finish();
5751
5752         if (r_timereport_active)
5753                 R_TimeReport("start");
5754         r_textureframe++; // used only by R_GetCurrentTexture
5755         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5756
5757         if(R_CompileShader_CheckStaticParms())
5758                 R_GLSL_Restart_f();
5759
5760         if (!r_drawentities.integer)
5761                 r_refdef.scene.numentities = 0;
5762         else if (r_sortentities.integer)
5763                 R_SortEntities();
5764
5765         R_AnimCache_ClearCache();
5766
5767         /* adjust for stereo display */
5768         if(R_Stereo_Active())
5769         {
5770                 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);
5771                 Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);
5772         }
5773
5774         if (r_refdef.view.isoverlay)
5775         {
5776                 // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
5777                 R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
5778                 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
5779                 R_TimeReport("depthclear");
5780
5781                 r_refdef.view.showdebug = false;
5782
5783                 r_fb.water.enabled = false;
5784                 r_fb.water.numwaterplanes = 0;
5785
5786                 R_RenderScene(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5787
5788                 r_refdef.view.matrix = originalmatrix;
5789
5790                 CHECKGLERROR
5791                 return;
5792         }
5793
5794         if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/)
5795         {
5796                 r_refdef.view.matrix = originalmatrix;
5797                 return;
5798         }
5799
5800         r_refdef.view.usevieworiginculling = !r_trippy.value && r_refdef.view.useperspective;
5801         if (v_isometric.integer && r_refdef.view.ismain)
5802                 V_MakeViewIsometric();
5803
5804         r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value;
5805
5806         if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D)
5807                 // in sRGB fallback, behave similar to true sRGB: convert this
5808                 // value from linear to sRGB
5809                 r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale);
5810
5811         R_RenderView_UpdateViewVectors();
5812
5813         R_Shadow_UpdateWorldLightSelection();
5814
5815         // this will set up r_fb.rt_screen
5816         R_Bloom_StartFrame();
5817
5818         // apply bloom brightness offset
5819         if(r_fb.rt_bloom)
5820                 r_refdef.view.colorscale *= r_bloom_scenebrightness.value;
5821
5822         // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
5823         if (r_fb.rt_screen)
5824         {
5825                 viewfbo = r_fb.rt_screen->fbo;
5826                 viewdepthtexture = r_fb.rt_screen->depthtexture;
5827                 viewcolortexture = r_fb.rt_screen->colortexture[0];
5828                 viewx = 0;
5829                 viewy = 0;
5830                 viewwidth = width;
5831                 viewheight = height;
5832         }
5833
5834         R_Water_StartFrame();
5835
5836         CHECKGLERROR
5837         if (r_timereport_active)
5838                 R_TimeReport("viewsetup");
5839
5840         R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5841
5842         // clear the whole fbo every frame - otherwise the driver will consider
5843         // it to be an inter-frame texture and stall in multi-gpu configurations
5844         if (r_fb.rt_screen)
5845                 GL_ScissorTest(false);
5846         R_ClearScreen(r_refdef.fogenabled);
5847         if (r_timereport_active)
5848                 R_TimeReport("viewclear");
5849
5850         r_refdef.view.clear = true;
5851
5852         r_refdef.view.showdebug = true;
5853
5854         R_View_Update();
5855         if (r_timereport_active)
5856                 R_TimeReport("visibility");
5857
5858         R_AnimCache_CacheVisibleEntities();
5859         if (r_timereport_active)
5860                 R_TimeReport("animcache");
5861
5862         R_Shadow_UpdateBounceGridTexture();
5863         if (r_timereport_active && r_shadow_bouncegrid.integer)
5864                 R_TimeReport("bouncegrid");
5865
5866         r_fb.water.numwaterplanes = 0;
5867         if (r_fb.water.enabled)
5868                 R_RenderWaterPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5869
5870         // for the actual view render we use scissoring a fair amount, so scissor
5871         // test needs to be on
5872         if (r_fb.rt_screen)
5873                 GL_ScissorTest(true);
5874         GL_Scissor(viewx, viewy, viewwidth, viewheight);
5875         R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5876         r_fb.water.numwaterplanes = 0;
5877
5878         // postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring
5879         GL_ScissorTest(false);
5880
5881         R_BlendView(fbo, depthtexture, colortexture, x, y, width, height);
5882         if (r_timereport_active)
5883                 R_TimeReport("blendview");
5884
5885         r_refdef.view.matrix = originalmatrix;
5886
5887         CHECKGLERROR
5888
5889         // go back to 2d rendering
5890         DrawQ_Start();
5891 }
5892
5893 void R_RenderWaterPlanes(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5894 {
5895         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
5896         {
5897                 r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity);
5898                 if (r_timereport_active)
5899                         R_TimeReport("waterworld");
5900         }
5901
5902         // don't let sound skip if going slow
5903         if (r_refdef.scene.extraupdate)
5904                 S_ExtraUpdate ();
5905
5906         R_DrawModelsAddWaterPlanes();
5907         if (r_timereport_active)
5908                 R_TimeReport("watermodels");
5909
5910         if (r_fb.water.numwaterplanes)
5911         {
5912                 R_Water_ProcessPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5913                 if (r_timereport_active)
5914                         R_TimeReport("waterscenes");
5915         }
5916 }
5917
5918 extern cvar_t cl_locs_show;
5919 static void R_DrawLocs(void);
5920 static void R_DrawEntityBBoxes(prvm_prog_t *prog);
5921 static void R_DrawModelDecals(void);
5922 extern cvar_t cl_decals_newsystem;
5923 extern qboolean r_shadow_usingdeferredprepass;
5924 extern int r_shadow_shadowmapatlas_modelshadows_size;
5925 void R_RenderScene(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5926 {
5927         qboolean shadowmapping = false;
5928
5929         if (r_timereport_active)
5930                 R_TimeReport("beginscene");
5931
5932         r_refdef.stats[r_stat_renders]++;
5933
5934         R_UpdateFog();
5935
5936         // don't let sound skip if going slow
5937         if (r_refdef.scene.extraupdate)
5938                 S_ExtraUpdate ();
5939
5940         R_MeshQueue_BeginScene();
5941
5942         R_SkyStartFrame();
5943
5944         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);
5945
5946         if (r_timereport_active)
5947                 R_TimeReport("skystartframe");
5948
5949         if (cl.csqc_vidvars.drawworld)
5950         {
5951                 // don't let sound skip if going slow
5952                 if (r_refdef.scene.extraupdate)
5953                         S_ExtraUpdate ();
5954
5955                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawSky)
5956                 {
5957                         r_refdef.scene.worldmodel->DrawSky(r_refdef.scene.worldentity);
5958                         if (r_timereport_active)
5959                                 R_TimeReport("worldsky");
5960                 }
5961
5962                 if (R_DrawBrushModelsSky() && r_timereport_active)
5963                         R_TimeReport("bmodelsky");
5964
5965                 if (skyrendermasked && skyrenderlater)
5966                 {
5967                         // we have to force off the water clipping plane while rendering sky
5968                         R_SetupView(false, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5969                         R_Sky();
5970                         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5971                         if (r_timereport_active)
5972                                 R_TimeReport("sky");
5973                 }
5974         }
5975
5976         // save the framebuffer info for R_Shadow_RenderMode_Reset during this view render
5977         r_shadow_viewfbo = viewfbo;
5978         r_shadow_viewdepthtexture = viewdepthtexture;
5979         r_shadow_viewcolortexture = viewcolortexture;
5980         r_shadow_viewx = viewx;
5981         r_shadow_viewy = viewy;
5982         r_shadow_viewwidth = viewwidth;
5983         r_shadow_viewheight = viewheight;
5984
5985         R_Shadow_PrepareModelShadows();
5986         R_Shadow_PrepareLights();
5987         if (r_timereport_active)
5988                 R_TimeReport("preparelights");
5989
5990         // render all the shadowmaps that will be used for this view
5991         shadowmapping = R_Shadow_ShadowMappingEnabled();
5992         if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
5993         {
5994                 R_Shadow_DrawShadowMaps();
5995                 if (r_timereport_active)
5996                         R_TimeReport("shadowmaps");
5997         }
5998
5999         // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
6000         if (r_shadow_usingdeferredprepass)
6001                 R_Shadow_DrawPrepass();
6002
6003         // now we begin the forward pass of the view render
6004         if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
6005         {
6006                 r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
6007                 if (r_timereport_active)
6008                         R_TimeReport("worlddepth");
6009         }
6010         if (r_depthfirst.integer >= 2)
6011         {
6012                 R_DrawModelsDepth();
6013                 if (r_timereport_active)
6014                         R_TimeReport("modeldepth");
6015         }
6016
6017         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
6018         {
6019                 r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
6020                 if (r_timereport_active)
6021                         R_TimeReport("world");
6022         }
6023
6024         // don't let sound skip if going slow
6025         if (r_refdef.scene.extraupdate)
6026                 S_ExtraUpdate ();
6027
6028         R_DrawModels();
6029         if (r_timereport_active)
6030                 R_TimeReport("models");
6031
6032         // don't let sound skip if going slow
6033         if (r_refdef.scene.extraupdate)
6034                 S_ExtraUpdate ();
6035
6036         if ((r_shadows.integer == 1 || (r_shadows.integer > 0 && !shadowmapping)) && !r_shadows_drawafterrtlighting.integer && r_refdef.scene.lightmapintensity > 0)
6037         {
6038                 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
6039                 R_Shadow_DrawModelShadows();
6040                 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
6041                 // don't let sound skip if going slow
6042                 if (r_refdef.scene.extraupdate)
6043                         S_ExtraUpdate ();
6044         }
6045
6046         if (!r_shadow_usingdeferredprepass)
6047         {
6048                 R_Shadow_DrawLights();
6049                 if (r_timereport_active)
6050                         R_TimeReport("rtlights");
6051         }
6052
6053         // don't let sound skip if going slow
6054         if (r_refdef.scene.extraupdate)
6055                 S_ExtraUpdate ();
6056
6057         if ((r_shadows.integer == 1 || (r_shadows.integer > 0 && !shadowmapping)) && r_shadows_drawafterrtlighting.integer && r_refdef.scene.lightmapintensity > 0)
6058         {
6059                 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
6060                 R_Shadow_DrawModelShadows();
6061                 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
6062                 // don't let sound skip if going slow
6063                 if (r_refdef.scene.extraupdate)
6064                         S_ExtraUpdate ();
6065         }
6066
6067         if (cl.csqc_vidvars.drawworld)
6068         {
6069                 if (cl_decals_newsystem.integer)
6070                 {
6071                         R_DrawModelDecals();
6072                         if (r_timereport_active)
6073                                 R_TimeReport("modeldecals");
6074                 }
6075                 else
6076                 {
6077                         R_DrawDecals();
6078                         if (r_timereport_active)
6079                                 R_TimeReport("decals");
6080                 }
6081
6082                 R_DrawParticles();
6083                 if (r_timereport_active)
6084                         R_TimeReport("particles");
6085
6086                 R_DrawExplosions();
6087                 if (r_timereport_active)
6088                         R_TimeReport("explosions");
6089         }
6090
6091         if (r_refdef.view.showdebug)
6092         {
6093                 if (cl_locs_show.integer)
6094                 {
6095                         R_DrawLocs();
6096                         if (r_timereport_active)
6097                                 R_TimeReport("showlocs");
6098                 }
6099
6100                 if (r_drawportals.integer)
6101                 {
6102                         R_DrawPortals();
6103                         if (r_timereport_active)
6104                                 R_TimeReport("portals");
6105                 }
6106
6107                 if (r_showbboxes_client.value > 0)
6108                 {
6109                         R_DrawEntityBBoxes(CLVM_prog);
6110                         if (r_timereport_active)
6111                                 R_TimeReport("clbboxes");
6112                 }
6113                 if (r_showbboxes.value > 0)
6114                 {
6115                         R_DrawEntityBBoxes(SVVM_prog);
6116                         if (r_timereport_active)
6117                                 R_TimeReport("svbboxes");
6118                 }
6119         }
6120
6121         if (r_transparent.integer)
6122         {
6123                 R_MeshQueue_RenderTransparent();
6124                 if (r_timereport_active)
6125                         R_TimeReport("drawtrans");
6126         }
6127
6128         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))
6129         {
6130                 r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity);
6131                 if (r_timereport_active)
6132                         R_TimeReport("worlddebug");
6133                 R_DrawModelsDebug();
6134                 if (r_timereport_active)
6135                         R_TimeReport("modeldebug");
6136         }
6137
6138         if (cl.csqc_vidvars.drawworld)
6139         {
6140                 R_Shadow_DrawCoronas();
6141                 if (r_timereport_active)
6142                         R_TimeReport("coronas");
6143         }
6144
6145         // don't let sound skip if going slow
6146         if (r_refdef.scene.extraupdate)
6147                 S_ExtraUpdate ();
6148 }
6149
6150 static const unsigned short bboxelements[36] =
6151 {
6152         5, 1, 3, 5, 3, 7,
6153         6, 2, 0, 6, 0, 4,
6154         7, 3, 2, 7, 2, 6,
6155         4, 0, 1, 4, 1, 5,
6156         4, 5, 7, 4, 7, 6,
6157         1, 0, 2, 1, 2, 3,
6158 };
6159
6160 #define BBOXEDGES 13
6161 static const float bboxedges[BBOXEDGES][6] = 
6162 {
6163         // whole box
6164         { 0, 0, 0, 1, 1, 1 },
6165         // bottom edges
6166         { 0, 0, 0, 0, 1, 0 },
6167         { 0, 0, 0, 1, 0, 0 },
6168         { 0, 1, 0, 1, 1, 0 },
6169         { 1, 0, 0, 1, 1, 0 },
6170         // top edges
6171         { 0, 0, 1, 0, 1, 1 },
6172         { 0, 0, 1, 1, 0, 1 },
6173         { 0, 1, 1, 1, 1, 1 },
6174         { 1, 0, 1, 1, 1, 1 },
6175         // vertical edges
6176         { 0, 0, 0, 0, 0, 1 },
6177         { 1, 0, 0, 1, 0, 1 },
6178         { 0, 1, 0, 0, 1, 1 },
6179         { 1, 1, 0, 1, 1, 1 },
6180 };
6181
6182 static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
6183 {
6184         int numvertices = BBOXEDGES * 8;
6185         float vertex3f[BBOXEDGES * 8 * 3], color4f[BBOXEDGES * 8 * 4];
6186         int numtriangles = BBOXEDGES * 12;
6187         unsigned short elements[BBOXEDGES * 36];
6188         int i, edge;
6189         float *v, *c, f1, f2, edgemins[3], edgemaxs[3];
6190
6191         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6192
6193         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6194         GL_DepthMask(false);
6195         GL_DepthRange(0, 1);
6196         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
6197
6198         for (edge = 0; edge < BBOXEDGES; edge++)
6199         {
6200                 for (i = 0; i < 3; i++)
6201                 {
6202                         edgemins[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][i] - 0.25f;
6203                         edgemaxs[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][3 + i] + 0.25f;
6204                 }
6205                 vertex3f[edge * 24 + 0] = edgemins[0]; vertex3f[edge * 24 + 1] = edgemins[1]; vertex3f[edge * 24 + 2] = edgemins[2];
6206                 vertex3f[edge * 24 + 3] = edgemaxs[0]; vertex3f[edge * 24 + 4] = edgemins[1]; vertex3f[edge * 24 + 5] = edgemins[2];
6207                 vertex3f[edge * 24 + 6] = edgemins[0]; vertex3f[edge * 24 + 7] = edgemaxs[1]; vertex3f[edge * 24 + 8] = edgemins[2];
6208                 vertex3f[edge * 24 + 9] = edgemaxs[0]; vertex3f[edge * 24 + 10] = edgemaxs[1]; vertex3f[edge * 24 + 11] = edgemins[2];
6209                 vertex3f[edge * 24 + 12] = edgemins[0]; vertex3f[edge * 24 + 13] = edgemins[1]; vertex3f[edge * 24 + 14] = edgemaxs[2];
6210                 vertex3f[edge * 24 + 15] = edgemaxs[0]; vertex3f[edge * 24 + 16] = edgemins[1]; vertex3f[edge * 24 + 17] = edgemaxs[2];
6211                 vertex3f[edge * 24 + 18] = edgemins[0]; vertex3f[edge * 24 + 19] = edgemaxs[1]; vertex3f[edge * 24 + 20] = edgemaxs[2];
6212                 vertex3f[edge * 24 + 21] = edgemaxs[0]; vertex3f[edge * 24 + 22] = edgemaxs[1]; vertex3f[edge * 24 + 23] = edgemaxs[2];
6213                 for (i = 0; i < 36; i++)
6214                         elements[edge * 36 + i] = edge * 8 + bboxelements[i];
6215         }
6216         R_FillColors(color4f, numvertices, cr, cg, cb, ca);
6217         if (r_refdef.fogenabled)
6218         {
6219                 for (i = 0, v = vertex3f, c = color4f; i < numvertices; i++, v += 3, c += 4)
6220                 {
6221                         f1 = RSurf_FogVertex(v);
6222                         f2 = 1 - f1;
6223                         c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
6224                         c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
6225                         c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
6226                 }
6227         }
6228         R_Mesh_PrepareVertices_Generic_Arrays(numvertices, vertex3f, color4f, NULL);
6229         R_Mesh_ResetTextureState();
6230         R_SetupShader_Generic_NoTexture(false, false);
6231         R_Mesh_Draw(0, numvertices, 0, numtriangles, NULL, NULL, 0, elements, NULL, 0);
6232 }
6233
6234 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6235 {
6236         // hacky overloading of the parameters
6237         prvm_prog_t *prog = (prvm_prog_t *)rtlight;
6238         int i;
6239         float color[4];
6240         prvm_edict_t *edict;
6241
6242         GL_CullFace(GL_NONE);
6243         R_SetupShader_Generic_NoTexture(false, false);
6244
6245         for (i = 0;i < numsurfaces;i++)
6246         {
6247                 edict = PRVM_EDICT_NUM(surfacelist[i]);
6248                 switch ((int)PRVM_serveredictfloat(edict, solid))
6249                 {
6250                         case SOLID_NOT:      Vector4Set(color, 1, 1, 1, 0.05);break;
6251                         case SOLID_TRIGGER:  Vector4Set(color, 1, 0, 1, 0.10);break;
6252                         case SOLID_BBOX:     Vector4Set(color, 0, 1, 0, 0.10);break;
6253                         case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
6254                         case SOLID_BSP:      Vector4Set(color, 0, 0, 1, 0.05);break;
6255                         case SOLID_CORPSE:   Vector4Set(color, 1, 0.5, 0, 0.05);break;
6256                         default:             Vector4Set(color, 0, 0, 0, 0.50);break;
6257                 }
6258                 if (prog == CLVM_prog)
6259                         color[3] *= r_showbboxes_client.value;
6260                 else
6261                         color[3] *= r_showbboxes.value;
6262                 color[3] = bound(0, color[3], 1);
6263                 GL_DepthTest(!r_showdisabledepthtest.integer);
6264                 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
6265         }
6266 }
6267
6268 static void R_DrawEntityBBoxes(prvm_prog_t *prog)
6269 {
6270         int i;
6271         prvm_edict_t *edict;
6272         vec3_t center;
6273
6274         if (prog == NULL)
6275                 return;
6276
6277         for (i = 0; i < prog->num_edicts; i++)
6278         {
6279                 edict = PRVM_EDICT_NUM(i);
6280                 if (edict->priv.server->free)
6281                         continue;
6282                 // exclude the following for now, as they don't live in world coordinate space and can't be solid:
6283                 if (PRVM_serveredictedict(edict, tag_entity) != 0)
6284                         continue;
6285                 if (PRVM_serveredictedict(edict, viewmodelforclient) != 0)
6286                         continue;
6287                 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
6288                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)prog);
6289         }
6290 }
6291
6292 static const int nomodelelement3i[24] =
6293 {
6294         5, 2, 0,
6295         5, 1, 2,
6296         5, 0, 3,
6297         5, 3, 1,
6298         0, 2, 4,
6299         2, 1, 4,
6300         3, 0, 4,
6301         1, 3, 4
6302 };
6303
6304 static const unsigned short nomodelelement3s[24] =
6305 {
6306         5, 2, 0,
6307         5, 1, 2,
6308         5, 0, 3,
6309         5, 3, 1,
6310         0, 2, 4,
6311         2, 1, 4,
6312         3, 0, 4,
6313         1, 3, 4
6314 };
6315
6316 static const float nomodelvertex3f[6*3] =
6317 {
6318         -16,   0,   0,
6319          16,   0,   0,
6320           0, -16,   0,
6321           0,  16,   0,
6322           0,   0, -16,
6323           0,   0,  16
6324 };
6325
6326 static const float nomodelcolor4f[6*4] =
6327 {
6328         0.0f, 0.0f, 0.5f, 1.0f,
6329         0.0f, 0.0f, 0.5f, 1.0f,
6330         0.0f, 0.5f, 0.0f, 1.0f,
6331         0.0f, 0.5f, 0.0f, 1.0f,
6332         0.5f, 0.0f, 0.0f, 1.0f,
6333         0.5f, 0.0f, 0.0f, 1.0f
6334 };
6335
6336 static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6337 {
6338         int i;
6339         float f1, f2, *c;
6340         float color4f[6*4];
6341
6342         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);
6343
6344         // this is only called once per entity so numsurfaces is always 1, and
6345         // surfacelist is always {0}, so this code does not handle batches
6346
6347         if (rsurface.ent_flags & RENDER_ADDITIVE)
6348         {
6349                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
6350                 GL_DepthMask(false);
6351         }
6352         else if (ent->alpha < 1)
6353         {
6354                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6355                 GL_DepthMask(false);
6356         }
6357         else
6358         {
6359                 GL_BlendFunc(GL_ONE, GL_ZERO);
6360                 GL_DepthMask(true);
6361         }
6362         GL_DepthRange(0, (rsurface.ent_flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
6363         GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
6364         GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
6365         GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
6366         memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
6367         for (i = 0, c = color4f;i < 6;i++, c += 4)
6368         {
6369                 c[0] *= ent->render_fullbright[0] * r_refdef.view.colorscale;
6370                 c[1] *= ent->render_fullbright[1] * r_refdef.view.colorscale;
6371                 c[2] *= ent->render_fullbright[2] * r_refdef.view.colorscale;
6372                 c[3] *= ent->alpha;
6373         }
6374         if (r_refdef.fogenabled)
6375         {
6376                 for (i = 0, c = color4f;i < 6;i++, c += 4)
6377                 {
6378                         f1 = RSurf_FogVertex(nomodelvertex3f + 3*i);
6379                         f2 = 1 - f1;
6380                         c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
6381                         c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
6382                         c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
6383                 }
6384         }
6385 //      R_Mesh_ResetTextureState();
6386         R_SetupShader_Generic_NoTexture(false, false);
6387         R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
6388         R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
6389 }
6390
6391 void R_DrawNoModel(entity_render_t *ent)
6392 {
6393         vec3_t org;
6394         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
6395         if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1))
6396                 R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
6397         else
6398                 R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
6399 }
6400
6401 void R_CalcBeam_Vertex3f (float *vert, const float *org1, const float *org2, float width)
6402 {
6403         vec3_t right1, right2, diff, normal;
6404
6405         VectorSubtract (org2, org1, normal);
6406
6407         // calculate 'right' vector for start
6408         VectorSubtract (r_refdef.view.origin, org1, diff);
6409         CrossProduct (normal, diff, right1);
6410         VectorNormalize (right1);
6411
6412         // calculate 'right' vector for end
6413         VectorSubtract (r_refdef.view.origin, org2, diff);
6414         CrossProduct (normal, diff, right2);
6415         VectorNormalize (right2);
6416
6417         vert[ 0] = org1[0] + width * right1[0];
6418         vert[ 1] = org1[1] + width * right1[1];
6419         vert[ 2] = org1[2] + width * right1[2];
6420         vert[ 3] = org1[0] - width * right1[0];
6421         vert[ 4] = org1[1] - width * right1[1];
6422         vert[ 5] = org1[2] - width * right1[2];
6423         vert[ 6] = org2[0] - width * right2[0];
6424         vert[ 7] = org2[1] - width * right2[1];
6425         vert[ 8] = org2[2] - width * right2[2];
6426         vert[ 9] = org2[0] + width * right2[0];
6427         vert[10] = org2[1] + width * right2[1];
6428         vert[11] = org2[2] + width * right2[2];
6429 }
6430
6431 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)
6432 {
6433         vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
6434         vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
6435         vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
6436         vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
6437         vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
6438         vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
6439         vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
6440         vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
6441         vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
6442         vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
6443         vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
6444         vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
6445 }
6446
6447 static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
6448 {
6449         int i;
6450         float *vertex3f;
6451         float v[3];
6452         VectorSet(v, x, y, z);
6453         for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
6454                 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
6455                         break;
6456         if (i == mesh->numvertices)
6457         {
6458                 if (mesh->numvertices < mesh->maxvertices)
6459                 {
6460                         VectorCopy(v, vertex3f);
6461                         mesh->numvertices++;
6462                 }
6463                 return mesh->numvertices;
6464         }
6465         else
6466                 return i;
6467 }
6468
6469 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
6470 {
6471         int i;
6472         int *e, element[3];
6473         element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6474         element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6475         e = mesh->element3i + mesh->numtriangles * 3;
6476         for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
6477         {
6478                 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
6479                 if (mesh->numtriangles < mesh->maxtriangles)
6480                 {
6481                         *e++ = element[0];
6482                         *e++ = element[1];
6483                         *e++ = element[2];
6484                         mesh->numtriangles++;
6485                 }
6486                 element[1] = element[2];
6487         }
6488 }
6489
6490 static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
6491 {
6492         int i;
6493         int *e, element[3];
6494         element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6495         element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6496         e = mesh->element3i + mesh->numtriangles * 3;
6497         for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
6498         {
6499                 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
6500                 if (mesh->numtriangles < mesh->maxtriangles)
6501                 {
6502                         *e++ = element[0];
6503                         *e++ = element[1];
6504                         *e++ = element[2];
6505                         mesh->numtriangles++;
6506                 }
6507                 element[1] = element[2];
6508         }
6509 }
6510
6511 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
6512 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
6513 {
6514         int planenum, planenum2;
6515         int w;
6516         int tempnumpoints;
6517         mplane_t *plane, *plane2;
6518         double maxdist;
6519         double temppoints[2][256*3];
6520         // figure out how large a bounding box we need to properly compute this brush
6521         maxdist = 0;
6522         for (w = 0;w < numplanes;w++)
6523                 maxdist = max(maxdist, fabs(planes[w].dist));
6524         // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
6525         maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
6526         for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
6527         {
6528                 w = 0;
6529                 tempnumpoints = 4;
6530                 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
6531                 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
6532                 {
6533                         if (planenum2 == planenum)
6534                                 continue;
6535                         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);
6536                         w = !w;
6537                 }
6538                 if (tempnumpoints < 3)
6539                         continue;
6540                 // generate elements forming a triangle fan for this polygon
6541                 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
6542         }
6543 }
6544
6545 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)
6546 {
6547         texturelayer_t *layer;
6548         layer = t->currentlayers + t->currentnumlayers++;
6549         layer->type = type;
6550         layer->depthmask = depthmask;
6551         layer->blendfunc1 = blendfunc1;
6552         layer->blendfunc2 = blendfunc2;
6553         layer->texture = texture;
6554         layer->texmatrix = *matrix;
6555         layer->color[0] = r;
6556         layer->color[1] = g;
6557         layer->color[2] = b;
6558         layer->color[3] = a;
6559 }
6560
6561 static qboolean R_TestQ3WaveFunc(q3wavefunc_t func, const float *parms)
6562 {
6563         if(parms[0] == 0 && parms[1] == 0)
6564                 return false;
6565         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6566                 if(rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)] == 0)
6567                         return false;
6568         return true;
6569 }
6570
6571 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
6572 {
6573         double index, f;
6574         index = parms[2] + rsurface.shadertime * parms[3];
6575         index -= floor(index);
6576         switch (func & ((1 << Q3WAVEFUNC_USER_SHIFT) - 1))
6577         {
6578         default:
6579         case Q3WAVEFUNC_NONE:
6580         case Q3WAVEFUNC_NOISE:
6581         case Q3WAVEFUNC_COUNT:
6582                 f = 0;
6583                 break;
6584         case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
6585         case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
6586         case Q3WAVEFUNC_SAWTOOTH: f = index;break;
6587         case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
6588         case Q3WAVEFUNC_TRIANGLE:
6589                 index *= 4;
6590                 f = index - floor(index);
6591                 if (index < 1)
6592                 {
6593                         // f = f;
6594                 }
6595                 else if (index < 2)
6596                         f = 1 - f;
6597                 else if (index < 3)
6598                         f = -f;
6599                 else
6600                         f = -(1 - f);
6601                 break;
6602         }
6603         f = parms[0] + parms[1] * f;
6604         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6605                 f *= rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)];
6606         return (float) f;
6607 }
6608
6609 static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
6610 {
6611         int w, h, idx;
6612         float shadertime;
6613         float f;
6614         float offsetd[2];
6615         float tcmat[12];
6616         matrix4x4_t matrix, temp;
6617         // if shadertime exceeds about 9 hours (32768 seconds), just wrap it,
6618         // it's better to have one huge fixup every 9 hours than gradual
6619         // degradation over time which looks consistently bad after many hours.
6620         //
6621         // tcmod scroll in particular suffers from this degradation which can't be
6622         // effectively worked around even with floor() tricks because we don't
6623         // know if tcmod scroll is the last tcmod being applied, and for clampmap
6624         // a workaround involving floor() would be incorrect anyway...
6625         shadertime = rsurface.shadertime;
6626         if (shadertime >= 32768.0f)
6627                 shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f;
6628         switch(tcmod->tcmod)
6629         {
6630                 case Q3TCMOD_COUNT:
6631                 case Q3TCMOD_NONE:
6632                         if (currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6633                                 matrix = r_waterscrollmatrix;
6634                         else
6635                                 matrix = identitymatrix;
6636                         break;
6637                 case Q3TCMOD_ENTITYTRANSLATE:
6638                         // this is used in Q3 to allow the gamecode to control texcoord
6639                         // scrolling on the entity, which is not supported in darkplaces yet.
6640                         Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
6641                         break;
6642                 case Q3TCMOD_ROTATE:
6643                         Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
6644                         Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
6645                         Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
6646                         break;
6647                 case Q3TCMOD_SCALE:
6648                         Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
6649                         break;
6650                 case Q3TCMOD_SCROLL:
6651                         // this particular tcmod is a "bug for bug" compatible one with regards to
6652                         // Quake3, the wrapping is unnecessary with our shadetime fix but quake3
6653                         // specifically did the wrapping and so we must mimic that...
6654                         offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
6655                         offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
6656                         Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
6657                         break;
6658                 case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
6659                         w = (int) tcmod->parms[0];
6660                         h = (int) tcmod->parms[1];
6661                         f = rsurface.shadertime / (tcmod->parms[2] * w * h);
6662                         f = f - floor(f);
6663                         idx = (int) floor(f * w * h);
6664                         Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
6665                         break;
6666                 case Q3TCMOD_STRETCH:
6667                         f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
6668                         Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
6669                         break;
6670                 case Q3TCMOD_TRANSFORM:
6671                         VectorSet(tcmat +  0, tcmod->parms[0], tcmod->parms[1], 0);
6672                         VectorSet(tcmat +  3, tcmod->parms[2], tcmod->parms[3], 0);
6673                         VectorSet(tcmat +  6, 0                   , 0                , 1);
6674                         VectorSet(tcmat +  9, tcmod->parms[4], tcmod->parms[5], 0);
6675                         Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
6676                         break;
6677                 case Q3TCMOD_TURBULENT:
6678                         // this is handled in the RSurf_PrepareVertices function
6679                         matrix = identitymatrix;
6680                         break;
6681         }
6682         temp = *texmatrix;
6683         Matrix4x4_Concat(texmatrix, &matrix, &temp);
6684 }
6685
6686 static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
6687 {
6688         int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP;
6689         char name[MAX_QPATH];
6690         skinframe_t *skinframe;
6691         unsigned char pixels[296*194];
6692         strlcpy(cache->name, skinname, sizeof(cache->name));
6693         dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name);
6694         if (developer_loading.integer)
6695                 Con_Printf("loading %s\n", name);
6696         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
6697         if (!skinframe || !skinframe->base)
6698         {
6699                 unsigned char *f;
6700                 fs_offset_t filesize;
6701                 skinframe = NULL;
6702                 f = FS_LoadFile(name, tempmempool, true, &filesize);
6703                 if (f)
6704                 {
6705                         if (LoadPCX_QWSkin(f, (int)filesize, pixels, 296, 194))
6706                                 skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
6707                         Mem_Free(f);
6708                 }
6709         }
6710         cache->skinframe = skinframe;
6711 }
6712
6713 texture_t *R_GetCurrentTexture(texture_t *t)
6714 {
6715         int i, q;
6716         const entity_render_t *ent = rsurface.entity;
6717         dp_model_t *model = ent->model; // when calling this, ent must not be NULL
6718         q3shaderinfo_layer_tcmod_t *tcmod;
6719         float specularscale = 0.0f;
6720
6721         if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate)
6722                 return t->currentframe;
6723         t->update_lastrenderframe = r_textureframe;
6724         t->update_lastrenderentity = (void *)ent;
6725
6726         if(ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS)
6727                 t->camera_entity = ent->entitynumber;
6728         else
6729                 t->camera_entity = 0;
6730
6731         // switch to an alternate material if this is a q1bsp animated material
6732         {
6733                 texture_t *texture = t;
6734                 int s = rsurface.ent_skinnum;
6735                 if ((unsigned int)s >= (unsigned int)model->numskins)
6736                         s = 0;
6737                 if (model->skinscenes)
6738                 {
6739                         if (model->skinscenes[s].framecount > 1)
6740                                 s = model->skinscenes[s].firstframe + (unsigned int) (rsurface.shadertime * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
6741                         else
6742                                 s = model->skinscenes[s].firstframe;
6743                 }
6744                 if (s > 0)
6745                         t = t + s * model->num_surfaces;
6746                 if (t->animated)
6747                 {
6748                         // use an alternate animation if the entity's frame is not 0,
6749                         // and only if the texture has an alternate animation
6750                         if (t->animated == 2) // q2bsp
6751                                 t = t->anim_frames[0][ent->framegroupblend[0].frame % t->anim_total[0]];
6752                         else if (rsurface.ent_alttextures && t->anim_total[1])
6753                                 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
6754                         else
6755                                 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
6756                 }
6757                 texture->currentframe = t;
6758         }
6759
6760         // update currentskinframe to be a qw skin or animation frame
6761         if (rsurface.ent_qwskin >= 0)
6762         {
6763                 i = rsurface.ent_qwskin;
6764                 if (!r_qwskincache || r_qwskincache_size != cl.maxclients)
6765                 {
6766                         r_qwskincache_size = cl.maxclients;
6767                         if (r_qwskincache)
6768                                 Mem_Free(r_qwskincache);
6769                         r_qwskincache = (r_qwskincache_t *)Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size);
6770                 }
6771                 if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
6772                         R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
6773                 t->currentskinframe = r_qwskincache[i].skinframe;
6774                 if (t->materialshaderpass && t->currentskinframe == NULL)
6775                         t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6776         }
6777         else if (t->materialshaderpass && t->materialshaderpass->numframes >= 2)
6778                 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6779         if (t->backgroundshaderpass && t->backgroundshaderpass->numframes >= 2)
6780                 t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
6781
6782         t->currentmaterialflags = t->basematerialflags;
6783         t->currentalpha = rsurface.entity->alpha * t->basealpha;
6784         if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_novis.integer || r_trippy.integer))
6785                 t->currentalpha *= r_wateralpha.value;
6786         if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay)
6787                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later
6788         if(!r_fb.water.enabled || r_refdef.view.isoverlay)
6789                 t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA);
6790
6791         // decide on which type of lighting to use for this surface
6792         if (rsurface.entity->render_modellight_forced)
6793                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6794         if (rsurface.entity->render_rtlight_disabled)
6795                 t->currentmaterialflags |= MATERIALFLAG_NORTLIGHT;
6796         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND && !(R_BlendFuncFlags(t->customblendfunc[0], t->customblendfunc[1]) & BLENDFUNC_ALLOWS_COLORMOD))
6797         {
6798                 // some CUSTOMBLEND blendfuncs are too weird, we have to ignore colormod and view colorscale
6799                 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_NORTLIGHT;
6800                 for (q = 0; q < 3; q++)
6801                 {
6802                         t->render_glowmod[q] = rsurface.entity->glowmod[q];
6803                         t->render_modellight_lightdir[q] = q == 2;
6804                         t->render_modellight_ambient[q] = 1;
6805                         t->render_modellight_diffuse[q] = 0;
6806                         t->render_modellight_specular[q] = 0;
6807                         t->render_lightmap_ambient[q] = 0;
6808                         t->render_lightmap_diffuse[q] = 0;
6809                         t->render_lightmap_specular[q] = 0;
6810                         t->render_rtlight_diffuse[q] = 0;
6811                         t->render_rtlight_specular[q] = 0;
6812                 }
6813         }
6814         else if ((t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !(rsurface.ent_flags & RENDER_LIGHT))
6815         {
6816                 // fullbright is basically MATERIALFLAG_MODELLIGHT but with ambient locked to 1,1,1 and no shading
6817                 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_NORTLIGHT | MATERIALFLAG_MODELLIGHT;
6818                 for (q = 0; q < 3; q++)
6819                 {
6820                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6821                         t->render_modellight_ambient[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6822                         t->render_modellight_lightdir[q] = q == 2;
6823                         t->render_modellight_diffuse[q] = 0;
6824                         t->render_modellight_specular[q] = 0;
6825                         t->render_lightmap_ambient[q] = 0;
6826                         t->render_lightmap_diffuse[q] = 0;
6827                         t->render_lightmap_specular[q] = 0;
6828                         t->render_rtlight_diffuse[q] = 0;
6829                         t->render_rtlight_specular[q] = 0;
6830                 }
6831         }
6832         else if (FAKELIGHT_ENABLED)
6833         {
6834                 // no modellight if using fakelight for the map
6835                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_NORTLIGHT) & ~(MATERIALFLAG_MODELLIGHT);
6836                 for (q = 0; q < 3; q++)
6837                 {
6838                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6839                         t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6840                         t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6841                         t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6842                         t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6843                         t->render_lightmap_ambient[q] = 0;
6844                         t->render_lightmap_diffuse[q] = 0;
6845                         t->render_lightmap_specular[q] = 0;
6846                         t->render_rtlight_diffuse[q] = 0;
6847                         t->render_rtlight_specular[q] = 0;
6848                 }
6849         }
6850         else if ((rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT)) || rsurface.modeltexcoordlightmap2f == NULL)
6851         {
6852                 // ambient + single direction light (modellight)
6853                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6854                 for (q = 0; q < 3; q++)
6855                 {
6856                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6857                         t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6858                         t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6859                         t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6860                         t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6861                         t->render_lightmap_ambient[q] = 0;
6862                         t->render_lightmap_diffuse[q] = 0;
6863                         t->render_lightmap_specular[q] = 0;
6864                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6865                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6866                 }
6867         }
6868         else
6869         {
6870                 // lightmap - 2x diffuse and specular brightness because bsp files have 0-2 colors as 0-1
6871                 for (q = 0; q < 3; q++)
6872                 {
6873                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6874                         t->render_modellight_lightdir[q] = q == 2;
6875                         t->render_modellight_ambient[q] = 0;
6876                         t->render_modellight_diffuse[q] = 0;
6877                         t->render_modellight_specular[q] = 0;
6878                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6879                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6880                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6881                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6882                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6883                 }
6884         }
6885
6886         if (t->currentmaterialflags & MATERIALFLAG_VERTEXCOLOR)
6887         {
6888                 // since MATERIALFLAG_VERTEXCOLOR uses the lightmapcolor4f vertex
6889                 // attribute, we punt it to the lightmap path and hope for the best,
6890                 // but lighting doesn't work.
6891                 //
6892                 // FIXME: this is fine for effects but CSQC polygons should be subject
6893                 // to lighting.
6894                 t->currentmaterialflags &= ~MATERIALFLAG_MODELLIGHT;
6895                 for (q = 0; q < 3; q++)
6896                 {
6897                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6898                         t->render_modellight_lightdir[q] = q == 2;
6899                         t->render_modellight_ambient[q] = 0;
6900                         t->render_modellight_diffuse[q] = 0;
6901                         t->render_modellight_specular[q] = 0;
6902                         t->render_lightmap_ambient[q] = 0;
6903                         t->render_lightmap_diffuse[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6904                         t->render_lightmap_specular[q] = 0;
6905                         t->render_rtlight_diffuse[q] = 0;
6906                         t->render_rtlight_specular[q] = 0;
6907                 }
6908         }
6909
6910         for (q = 0; q < 3; q++)
6911         {
6912                 t->render_colormap_pants[q] = rsurface.entity->colormap_pantscolor[q];
6913                 t->render_colormap_shirt[q] = rsurface.entity->colormap_shirtcolor[q];
6914         }
6915
6916         if (rsurface.ent_flags & RENDER_ADDITIVE)
6917                 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6918         else if (t->currentalpha < 1)
6919                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6920         // LordHavoc: prevent bugs where code checks add or alpha at higher priority than customblend by clearing these flags
6921         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6922                 t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA);
6923         if (rsurface.ent_flags & RENDER_DOUBLESIDED)
6924                 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
6925         if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
6926                 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
6927         if (t->backgroundshaderpass)
6928                 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
6929         if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
6930         {
6931                 if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA))
6932                         t->currentmaterialflags &= ~MATERIALFLAG_BLENDED;
6933         }
6934         else
6935                 t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA);
6936         if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)))
6937         {
6938                 // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on
6939                 t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST;
6940         }
6941         if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
6942                 t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
6943
6944         // there is no tcmod
6945         if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6946         {
6947                 t->currenttexmatrix = r_waterscrollmatrix;
6948                 t->currentbackgroundtexmatrix = r_waterscrollmatrix;
6949         }
6950         else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE))
6951         {
6952                 Matrix4x4_CreateIdentity(&t->currenttexmatrix);
6953                 Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
6954         }
6955
6956         if (t->materialshaderpass)
6957                 for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
6958                         R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
6959
6960         t->colormapping = VectorLength2(t->render_colormap_pants) + VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f);
6961         if (t->currentskinframe->qpixels)
6962                 R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
6963         t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
6964         if (!t->basetexture)
6965                 t->basetexture = r_texture_notexture;
6966         t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
6967         t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
6968         t->nmaptexture = t->currentskinframe->nmap;
6969         if (!t->nmaptexture)
6970                 t->nmaptexture = r_texture_blanknormalmap;
6971         t->glosstexture = r_texture_black;
6972         t->glowtexture = t->currentskinframe->glow;
6973         t->fogtexture = t->currentskinframe->fog;
6974         t->reflectmasktexture = t->currentskinframe->reflect;
6975         if (t->backgroundshaderpass)
6976         {
6977                 for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
6978                         R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
6979                 t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
6980                 t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
6981                 t->backgroundglosstexture = r_texture_black;
6982                 t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
6983                 if (!t->backgroundnmaptexture)
6984                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6985                 // make sure that if glow is going to be used, both textures are not NULL
6986                 if (!t->backgroundglowtexture && t->glowtexture)
6987                         t->backgroundglowtexture = r_texture_black;
6988                 if (!t->glowtexture && t->backgroundglowtexture)
6989                         t->glowtexture = r_texture_black;
6990         }
6991         else
6992         {
6993                 t->backgroundbasetexture = r_texture_white;
6994                 t->backgroundnmaptexture = r_texture_blanknormalmap;
6995                 t->backgroundglosstexture = r_texture_black;
6996                 t->backgroundglowtexture = NULL;
6997         }
6998         t->specularpower = r_shadow_glossexponent.value;
6999         // TODO: store reference values for these in the texture?
7000         if (r_shadow_gloss.integer > 0)
7001         {
7002                 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
7003                 {
7004                         if (r_shadow_glossintensity.value > 0)
7005                         {
7006                                 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
7007                                 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
7008                                 specularscale = r_shadow_glossintensity.value;
7009                         }
7010                 }
7011                 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
7012                 {
7013                         t->glosstexture = r_texture_white;
7014                         t->backgroundglosstexture = r_texture_white;
7015                         specularscale = r_shadow_gloss2intensity.value;
7016                         t->specularpower = r_shadow_gloss2exponent.value;
7017                 }
7018         }
7019         specularscale *= t->specularscalemod;
7020         t->specularpower *= t->specularpowermod;
7021
7022         // lightmaps mode looks bad with dlights using actual texturing, so turn
7023         // off the colormap and glossmap, but leave the normalmap on as it still
7024         // accurately represents the shading involved
7025         if (gl_lightmaps.integer)
7026         {
7027                 t->basetexture = r_texture_grey128;
7028                 t->pantstexture = r_texture_black;
7029                 t->shirttexture = r_texture_black;
7030                 if (gl_lightmaps.integer < 2)
7031                         t->nmaptexture = r_texture_blanknormalmap;
7032                 t->glosstexture = r_texture_black;
7033                 t->glowtexture = NULL;
7034                 t->fogtexture = NULL;
7035                 t->reflectmasktexture = NULL;
7036                 t->backgroundbasetexture = NULL;
7037                 if (gl_lightmaps.integer < 2)
7038                         t->backgroundnmaptexture = r_texture_blanknormalmap;
7039                 t->backgroundglosstexture = r_texture_black;
7040                 t->backgroundglowtexture = NULL;
7041                 specularscale = 0;
7042                 t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
7043         }
7044
7045         if (specularscale != 1.0f)
7046         {
7047                 for (q = 0; q < 3; q++)
7048                 {
7049                         t->render_modellight_specular[q] *= specularscale;
7050                         t->render_lightmap_specular[q] *= specularscale;
7051                         t->render_rtlight_specular[q] *= specularscale;
7052                 }
7053         }
7054
7055         t->currentnumlayers = 0;
7056         if (t->currentmaterialflags & MATERIALFLAG_WALL)
7057         {
7058                 int blendfunc1, blendfunc2;
7059                 qboolean depthmask;
7060                 if (t->currentmaterialflags & MATERIALFLAG_ADD)
7061                 {
7062                         blendfunc1 = GL_SRC_ALPHA;
7063                         blendfunc2 = GL_ONE;
7064                 }
7065                 else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
7066                 {
7067                         blendfunc1 = GL_SRC_ALPHA;
7068                         blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
7069                 }
7070                 else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
7071                 {
7072                         blendfunc1 = t->customblendfunc[0];
7073                         blendfunc2 = t->customblendfunc[1];
7074                 }
7075                 else
7076                 {
7077                         blendfunc1 = GL_ONE;
7078                         blendfunc2 = GL_ZERO;
7079                 }
7080                 depthmask = !(t->currentmaterialflags & MATERIALFLAG_BLENDED);
7081                 if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
7082                 {
7083                         // basic lit geometry
7084                         R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE, t->basetexture, &t->currenttexmatrix, 2, 2, 2, t->currentalpha);
7085                         // add pants/shirt if needed
7086                         if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7087                                 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);
7088                         if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7089                                 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);
7090                 }
7091                 else
7092                 {
7093                         // basic lit geometry
7094                         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);
7095                         // add pants/shirt if needed
7096                         if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7097                                 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);
7098                         if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7099                                 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);
7100                         // now add ambient passes if needed
7101                         if (VectorLength2(t->render_lightmap_ambient) >= (1.0f/1048576.0f))
7102                         {
7103                                 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);
7104                                 if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7105                                         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);
7106                                 if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7107                                         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);
7108                         }
7109                 }
7110                 if (t->glowtexture != NULL && !gl_lightmaps.integer)
7111                         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);
7112                 if (r_refdef.fogenabled && !(t->currentmaterialflags & MATERIALFLAG_ADD))
7113                 {
7114                         // if this is opaque use alpha blend which will darken the earlier
7115                         // passes cheaply.
7116                         //
7117                         // if this is an alpha blended material, all the earlier passes
7118                         // were darkened by fog already, so we only need to add the fog
7119                         // color ontop through the fog mask texture
7120                         //
7121                         // if this is an additive blended material, all the earlier passes
7122                         // were darkened by fog already, and we should not add fog color
7123                         // (because the background was not darkened, there is no fog color
7124                         // that was lost behind it).
7125                         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);
7126                 }
7127         }
7128
7129         return t;
7130 }
7131
7132 rsurfacestate_t rsurface;
7133
7134 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass)
7135 {
7136         dp_model_t *model = ent->model;
7137         //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
7138         //      return;
7139         rsurface.entity = (entity_render_t *)ent;
7140         rsurface.skeleton = ent->skeleton;
7141         memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
7142         rsurface.ent_skinnum = ent->skinnum;
7143         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;
7144         rsurface.ent_flags = ent->flags;
7145         if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
7146                 rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
7147         rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
7148         rsurface.matrix = ent->matrix;
7149         rsurface.inversematrix = ent->inversematrix;
7150         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7151         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7152         R_EntityMatrix(&rsurface.matrix);
7153         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7154         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7155         rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist * rsurface.inversematrixscale;
7156         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7157         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7158         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7159         memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
7160         rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
7161         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7162         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7163         if (ent->model->brush.submodel && !prepass)
7164         {
7165                 rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
7166                 rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
7167         }
7168         // if the animcache code decided it should use the shader path, skip the deform step
7169         rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4;
7170         rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer;
7171         rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset;
7172         rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size;
7173         rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0;
7174         if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4)
7175         {
7176                 if (ent->animcache_vertex3f)
7177                 {
7178                         r_refdef.stats[r_stat_batch_entitycache_count]++;
7179                         r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
7180                         r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
7181                         r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
7182                         rsurface.modelvertex3f = ent->animcache_vertex3f;
7183                         rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer;
7184                         rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset;
7185                         rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
7186                         rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL;
7187                         rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0;
7188                         rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
7189                         rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL;
7190                         rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0;
7191                         rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
7192                         rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL;
7193                         rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0;
7194                         rsurface.modelvertexmesh = ent->animcache_vertexmesh;
7195                         rsurface.modelvertexmesh_vertexbuffer = ent->animcache_vertexmesh_vertexbuffer;
7196                         rsurface.modelvertexmesh_bufferoffset = ent->animcache_vertexmesh_bufferoffset;
7197                 }
7198                 else if (wanttangents)
7199                 {
7200                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7201                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7202                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7203                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7204                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7205                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7206                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7207                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7208                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f);
7209                         rsurface.modelvertexmesh = NULL;
7210                         rsurface.modelvertexmesh_vertexbuffer = NULL;
7211                         rsurface.modelvertexmesh_bufferoffset = 0;
7212                         rsurface.modelvertex3f_vertexbuffer = NULL;
7213                         rsurface.modelvertex3f_bufferoffset = 0;
7214                         rsurface.modelvertex3f_vertexbuffer = 0;
7215                         rsurface.modelvertex3f_bufferoffset = 0;
7216                         rsurface.modelsvector3f_vertexbuffer = 0;
7217                         rsurface.modelsvector3f_bufferoffset = 0;
7218                         rsurface.modeltvector3f_vertexbuffer = 0;
7219                         rsurface.modeltvector3f_bufferoffset = 0;
7220                         rsurface.modelnormal3f_vertexbuffer = 0;
7221                         rsurface.modelnormal3f_bufferoffset = 0;
7222                 }
7223                 else if (wantnormals)
7224                 {
7225                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7226                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7227                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7228                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7229                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7230                         rsurface.modelsvector3f = NULL;
7231                         rsurface.modeltvector3f = NULL;
7232                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7233                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL);
7234                         rsurface.modelvertexmesh = NULL;
7235                         rsurface.modelvertexmesh_vertexbuffer = NULL;
7236                         rsurface.modelvertexmesh_bufferoffset = 0;
7237                         rsurface.modelvertex3f_vertexbuffer = NULL;
7238                         rsurface.modelvertex3f_bufferoffset = 0;
7239                         rsurface.modelvertex3f_vertexbuffer = 0;
7240                         rsurface.modelvertex3f_bufferoffset = 0;
7241                         rsurface.modelsvector3f_vertexbuffer = 0;
7242                         rsurface.modelsvector3f_bufferoffset = 0;
7243                         rsurface.modeltvector3f_vertexbuffer = 0;
7244                         rsurface.modeltvector3f_bufferoffset = 0;
7245                         rsurface.modelnormal3f_vertexbuffer = 0;
7246                         rsurface.modelnormal3f_bufferoffset = 0;
7247                 }
7248                 else
7249                 {
7250                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7251                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7252                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7253                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7254                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7255                         rsurface.modelsvector3f = NULL;
7256                         rsurface.modeltvector3f = NULL;
7257                         rsurface.modelnormal3f = NULL;
7258                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL);
7259                         rsurface.modelvertexmesh = NULL;
7260                         rsurface.modelvertexmesh_vertexbuffer = NULL;
7261                         rsurface.modelvertexmesh_bufferoffset = 0;
7262                         rsurface.modelvertex3f_vertexbuffer = NULL;
7263                         rsurface.modelvertex3f_bufferoffset = 0;
7264                         rsurface.modelvertex3f_vertexbuffer = 0;
7265                         rsurface.modelvertex3f_bufferoffset = 0;
7266                         rsurface.modelsvector3f_vertexbuffer = 0;
7267                         rsurface.modelsvector3f_bufferoffset = 0;
7268                         rsurface.modeltvector3f_vertexbuffer = 0;
7269                         rsurface.modeltvector3f_bufferoffset = 0;
7270                         rsurface.modelnormal3f_vertexbuffer = 0;
7271                         rsurface.modelnormal3f_bufferoffset = 0;
7272                 }
7273                 rsurface.modelgeneratedvertex = true;
7274         }
7275         else
7276         {
7277                 if (rsurface.entityskeletaltransform3x4)
7278                 {
7279                         r_refdef.stats[r_stat_batch_entityskeletal_count]++;
7280                         r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
7281                         r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
7282                         r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
7283                 }
7284                 else
7285                 {
7286                         r_refdef.stats[r_stat_batch_entitystatic_count]++;
7287                         r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
7288                         r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
7289                         r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
7290                 }
7291                 rsurface.modelvertex3f  = model->surfmesh.data_vertex3f;
7292                 rsurface.modelvertex3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7293                 rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f;
7294                 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
7295                 rsurface.modelsvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7296                 rsurface.modelsvector3f_bufferoffset = model->surfmesh.vbooffset_svector3f;
7297                 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
7298                 rsurface.modeltvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7299                 rsurface.modeltvector3f_bufferoffset = model->surfmesh.vbooffset_tvector3f;
7300                 rsurface.modelnormal3f  = model->surfmesh.data_normal3f;
7301                 rsurface.modelnormal3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7302                 rsurface.modelnormal3f_bufferoffset = model->surfmesh.vbooffset_normal3f;
7303                 rsurface.modelvertexmesh = model->surfmesh.data_vertexmesh;
7304                 rsurface.modelvertexmesh_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7305                 rsurface.modelvertexmesh_bufferoffset = model->surfmesh.vbooffset_vertex3f;
7306                 rsurface.modelgeneratedvertex = false;
7307         }
7308         rsurface.modellightmapcolor4f  = model->surfmesh.data_lightmapcolor4f;
7309         rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7310         rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.vbooffset_lightmapcolor4f;
7311         rsurface.modeltexcoordtexture2f  = model->surfmesh.data_texcoordtexture2f;
7312         rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7313         rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.vbooffset_texcoordtexture2f;
7314         rsurface.modeltexcoordlightmap2f  = model->surfmesh.data_texcoordlightmap2f;
7315         rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7316         rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f;
7317         rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
7318         rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7319         rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.vbooffset_skeletalindex4ub;
7320         rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
7321         rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7322         rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.vbooffset_skeletalweight4ub;
7323         rsurface.modelelement3i = model->surfmesh.data_element3i;
7324         rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
7325         rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
7326         rsurface.modelelement3s = model->surfmesh.data_element3s;
7327         rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
7328         rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
7329         rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
7330         rsurface.modelnumvertices = model->surfmesh.num_vertices;
7331         rsurface.modelnumtriangles = model->surfmesh.num_triangles;
7332         rsurface.modelsurfaces = model->data_surfaces;
7333         rsurface.batchgeneratedvertex = false;
7334         rsurface.batchfirstvertex = 0;
7335         rsurface.batchnumvertices = 0;
7336         rsurface.batchfirsttriangle = 0;
7337         rsurface.batchnumtriangles = 0;
7338         rsurface.batchvertex3f  = NULL;
7339         rsurface.batchvertex3f_vertexbuffer = NULL;
7340         rsurface.batchvertex3f_bufferoffset = 0;
7341         rsurface.batchsvector3f = NULL;
7342         rsurface.batchsvector3f_vertexbuffer = NULL;
7343         rsurface.batchsvector3f_bufferoffset = 0;
7344         rsurface.batchtvector3f = NULL;
7345         rsurface.batchtvector3f_vertexbuffer = NULL;
7346         rsurface.batchtvector3f_bufferoffset = 0;
7347         rsurface.batchnormal3f  = NULL;
7348         rsurface.batchnormal3f_vertexbuffer = NULL;
7349         rsurface.batchnormal3f_bufferoffset = 0;
7350         rsurface.batchlightmapcolor4f = NULL;
7351         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7352         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7353         rsurface.batchtexcoordtexture2f = NULL;
7354         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7355         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7356         rsurface.batchtexcoordlightmap2f = NULL;
7357         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7358         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7359         rsurface.batchskeletalindex4ub = NULL;
7360         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7361         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7362         rsurface.batchskeletalweight4ub = NULL;
7363         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7364         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7365         rsurface.batchvertexmesh = NULL;
7366         rsurface.batchvertexmesh_vertexbuffer = NULL;
7367         rsurface.batchvertexmesh_bufferoffset = 0;
7368         rsurface.batchelement3i = NULL;
7369         rsurface.batchelement3i_indexbuffer = NULL;
7370         rsurface.batchelement3i_bufferoffset = 0;
7371         rsurface.batchelement3s = NULL;
7372         rsurface.batchelement3s_indexbuffer = NULL;
7373         rsurface.batchelement3s_bufferoffset = 0;
7374         rsurface.forcecurrenttextureupdate = false;
7375 }
7376
7377 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)
7378 {
7379         rsurface.entity = r_refdef.scene.worldentity;
7380         rsurface.skeleton = NULL;
7381         rsurface.ent_skinnum = 0;
7382         rsurface.ent_qwskin = -1;
7383         rsurface.ent_flags = entflags;
7384         rsurface.shadertime = r_refdef.scene.time - shadertime;
7385         rsurface.modelnumvertices = numvertices;
7386         rsurface.modelnumtriangles = numtriangles;
7387         rsurface.matrix = *matrix;
7388         rsurface.inversematrix = *inversematrix;
7389         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7390         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7391         R_EntityMatrix(&rsurface.matrix);
7392         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7393         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7394         rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
7395         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7396         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7397         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7398         memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
7399         rsurface.frameblend[0].lerp = 1;
7400         rsurface.ent_alttextures = false;
7401         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7402         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7403         rsurface.entityskeletaltransform3x4 = NULL;
7404         rsurface.entityskeletaltransform3x4buffer = NULL;
7405         rsurface.entityskeletaltransform3x4offset = 0;
7406         rsurface.entityskeletaltransform3x4size = 0;
7407         rsurface.entityskeletalnumtransforms = 0;
7408         r_refdef.stats[r_stat_batch_entitycustom_count]++;
7409         r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
7410         r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
7411         r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
7412         if (wanttangents)
7413         {
7414                 rsurface.modelvertex3f = (float *)vertex3f;
7415                 rsurface.modelsvector3f = svector3f ? (float *)svector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7416                 rsurface.modeltvector3f = tvector3f ? (float *)tvector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7417                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7418         }
7419         else if (wantnormals)
7420         {
7421                 rsurface.modelvertex3f = (float *)vertex3f;
7422                 rsurface.modelsvector3f = NULL;
7423                 rsurface.modeltvector3f = NULL;
7424                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7425         }
7426         else
7427         {
7428                 rsurface.modelvertex3f = (float *)vertex3f;
7429                 rsurface.modelsvector3f = NULL;
7430                 rsurface.modeltvector3f = NULL;
7431                 rsurface.modelnormal3f = NULL;
7432         }
7433         rsurface.modelvertexmesh = NULL;
7434         rsurface.modelvertexmesh_vertexbuffer = NULL;
7435         rsurface.modelvertexmesh_bufferoffset = 0;
7436         rsurface.modelvertex3f_vertexbuffer = 0;
7437         rsurface.modelvertex3f_bufferoffset = 0;
7438         rsurface.modelsvector3f_vertexbuffer = 0;
7439         rsurface.modelsvector3f_bufferoffset = 0;
7440         rsurface.modeltvector3f_vertexbuffer = 0;
7441         rsurface.modeltvector3f_bufferoffset = 0;
7442         rsurface.modelnormal3f_vertexbuffer = 0;
7443         rsurface.modelnormal3f_bufferoffset = 0;
7444         rsurface.modelgeneratedvertex = true;
7445         rsurface.modellightmapcolor4f  = (float *)color4f;
7446         rsurface.modellightmapcolor4f_vertexbuffer = 0;
7447         rsurface.modellightmapcolor4f_bufferoffset = 0;
7448         rsurface.modeltexcoordtexture2f  = (float *)texcoord2f;
7449         rsurface.modeltexcoordtexture2f_vertexbuffer = 0;
7450         rsurface.modeltexcoordtexture2f_bufferoffset = 0;
7451         rsurface.modeltexcoordlightmap2f  = NULL;
7452         rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
7453         rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
7454         rsurface.modelskeletalindex4ub = NULL;
7455         rsurface.modelskeletalindex4ub_vertexbuffer = NULL;
7456         rsurface.modelskeletalindex4ub_bufferoffset = 0;
7457         rsurface.modelskeletalweight4ub = NULL;
7458         rsurface.modelskeletalweight4ub_vertexbuffer = NULL;
7459         rsurface.modelskeletalweight4ub_bufferoffset = 0;
7460         rsurface.modelelement3i = (int *)element3i;
7461         rsurface.modelelement3i_indexbuffer = NULL;
7462         rsurface.modelelement3i_bufferoffset = 0;
7463         rsurface.modelelement3s = (unsigned short *)element3s;
7464         rsurface.modelelement3s_indexbuffer = NULL;
7465         rsurface.modelelement3s_bufferoffset = 0;
7466         rsurface.modellightmapoffsets = NULL;
7467         rsurface.modelsurfaces = NULL;
7468         rsurface.batchgeneratedvertex = false;
7469         rsurface.batchfirstvertex = 0;
7470         rsurface.batchnumvertices = 0;
7471         rsurface.batchfirsttriangle = 0;
7472         rsurface.batchnumtriangles = 0;
7473         rsurface.batchvertex3f  = NULL;
7474         rsurface.batchvertex3f_vertexbuffer = NULL;
7475         rsurface.batchvertex3f_bufferoffset = 0;
7476         rsurface.batchsvector3f = NULL;
7477         rsurface.batchsvector3f_vertexbuffer = NULL;
7478         rsurface.batchsvector3f_bufferoffset = 0;
7479         rsurface.batchtvector3f = NULL;
7480         rsurface.batchtvector3f_vertexbuffer = NULL;
7481         rsurface.batchtvector3f_bufferoffset = 0;
7482         rsurface.batchnormal3f  = NULL;
7483         rsurface.batchnormal3f_vertexbuffer = NULL;
7484         rsurface.batchnormal3f_bufferoffset = 0;
7485         rsurface.batchlightmapcolor4f = NULL;
7486         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7487         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7488         rsurface.batchtexcoordtexture2f = NULL;
7489         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7490         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7491         rsurface.batchtexcoordlightmap2f = NULL;
7492         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7493         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7494         rsurface.batchskeletalindex4ub = NULL;
7495         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7496         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7497         rsurface.batchskeletalweight4ub = NULL;
7498         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7499         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7500         rsurface.batchvertexmesh = NULL;
7501         rsurface.batchvertexmesh_vertexbuffer = NULL;
7502         rsurface.batchvertexmesh_bufferoffset = 0;
7503         rsurface.batchelement3i = NULL;
7504         rsurface.batchelement3i_indexbuffer = NULL;
7505         rsurface.batchelement3i_bufferoffset = 0;
7506         rsurface.batchelement3s = NULL;
7507         rsurface.batchelement3s_indexbuffer = NULL;
7508         rsurface.batchelement3s_bufferoffset = 0;
7509         rsurface.forcecurrenttextureupdate = true;
7510
7511         if (rsurface.modelnumvertices && rsurface.modelelement3i)
7512         {
7513                 if ((wantnormals || wanttangents) && !normal3f)
7514                 {
7515                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7516                         Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
7517                 }
7518                 if (wanttangents && !svector3f)
7519                 {
7520                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7521                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7522                         Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.modelsvector3f, rsurface.modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
7523                 }
7524         }
7525 }
7526
7527 float RSurf_FogPoint(const float *v)
7528 {
7529         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7530         float FogPlaneViewDist = r_refdef.fogplaneviewdist;
7531         float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3];
7532         float FogHeightFade = r_refdef.fogheightfade;
7533         float fogfrac;
7534         unsigned int fogmasktableindex;
7535         if (r_refdef.fogplaneviewabove)
7536                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7537         else
7538                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7539         fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier);
7540         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7541 }
7542
7543 float RSurf_FogVertex(const float *v)
7544 {
7545         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7546         float FogPlaneViewDist = rsurface.fogplaneviewdist;
7547         float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3];
7548         float FogHeightFade = rsurface.fogheightfade;
7549         float fogfrac;
7550         unsigned int fogmasktableindex;
7551         if (r_refdef.fogplaneviewabove)
7552                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7553         else
7554                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7555         fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.fogmasktabledistmultiplier);
7556         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7557 }
7558
7559 static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
7560 {
7561         int i;
7562         for (i = 0;i < numelements;i++)
7563                 outelement3i[i] = inelement3i[i] + adjust;
7564 }
7565
7566 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
7567 extern cvar_t gl_vbo;
7568 void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist)
7569 {
7570         int deformindex;
7571         int firsttriangle;
7572         int numtriangles;
7573         int firstvertex;
7574         int endvertex;
7575         int numvertices;
7576         int surfacefirsttriangle;
7577         int surfacenumtriangles;
7578         int surfacefirstvertex;
7579         int surfaceendvertex;
7580         int surfacenumvertices;
7581         int batchnumsurfaces = texturenumsurfaces;
7582         int batchnumvertices;
7583         int batchnumtriangles;
7584         int needsupdate;
7585         int i, j;
7586         qboolean gaps;
7587         qboolean dynamicvertex;
7588         float amplitude;
7589         float animpos;
7590         float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
7591         float waveparms[4];
7592         unsigned char *ub;
7593         q3shaderinfo_deform_t *deform;
7594         const msurface_t *surface, *firstsurface;
7595         r_vertexmesh_t *vertexmesh;
7596         if (!texturenumsurfaces)
7597                 return;
7598         // find vertex range of this surface batch
7599         gaps = false;
7600         firstsurface = texturesurfacelist[0];
7601         firsttriangle = firstsurface->num_firsttriangle;
7602         batchnumvertices = 0;
7603         batchnumtriangles = 0;
7604         firstvertex = endvertex = firstsurface->num_firstvertex;
7605         for (i = 0;i < texturenumsurfaces;i++)
7606         {
7607                 surface = texturesurfacelist[i];
7608                 if (surface != firstsurface + i)
7609                         gaps = true;
7610                 surfacefirstvertex = surface->num_firstvertex;
7611                 surfaceendvertex = surfacefirstvertex + surface->num_vertices;
7612                 surfacenumvertices = surface->num_vertices;
7613                 surfacenumtriangles = surface->num_triangles;
7614                 if (firstvertex > surfacefirstvertex)
7615                         firstvertex = surfacefirstvertex;
7616                 if (endvertex < surfaceendvertex)
7617                         endvertex = surfaceendvertex;
7618                 batchnumvertices += surfacenumvertices;
7619                 batchnumtriangles += surfacenumtriangles;
7620         }
7621
7622         r_refdef.stats[r_stat_batch_batches]++;
7623         if (gaps)
7624                 r_refdef.stats[r_stat_batch_withgaps]++;
7625         r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces;
7626         r_refdef.stats[r_stat_batch_vertices] += batchnumvertices;
7627         r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles;
7628
7629         // we now know the vertex range used, and if there are any gaps in it
7630         rsurface.batchfirstvertex = firstvertex;
7631         rsurface.batchnumvertices = endvertex - firstvertex;
7632         rsurface.batchfirsttriangle = firsttriangle;
7633         rsurface.batchnumtriangles = batchnumtriangles;
7634
7635         // this variable holds flags for which properties have been updated that
7636         // may require regenerating vertexmesh array...
7637         needsupdate = 0;
7638
7639         // check if any dynamic vertex processing must occur
7640         dynamicvertex = false;
7641
7642         // a cvar to force the dynamic vertex path to be taken, for debugging
7643         if (r_batch_debugdynamicvertexpath.integer)
7644         {
7645                 if (!dynamicvertex)
7646                 {
7647                         r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1;
7648                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces;
7649                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices;
7650                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles;
7651                 }
7652                 dynamicvertex = true;
7653         }
7654
7655         // if there is a chance of animated vertex colors, it's a dynamic batch
7656         if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_ARRAY_VERTEXCOLOR)) && texturesurfacelist[0]->lightmapinfo)
7657         {
7658                 if (!dynamicvertex)
7659                 {
7660                         r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1;
7661                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces;
7662                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices;
7663                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles;
7664                 }
7665                 dynamicvertex = true;
7666                 needsupdate |= BATCHNEED_VERTEXMESH_VERTEXCOLOR;
7667         }
7668
7669         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
7670         {
7671                 switch (deform->deform)
7672                 {
7673                 default:
7674                 case Q3DEFORM_PROJECTIONSHADOW:
7675                 case Q3DEFORM_TEXT0:
7676                 case Q3DEFORM_TEXT1:
7677                 case Q3DEFORM_TEXT2:
7678                 case Q3DEFORM_TEXT3:
7679                 case Q3DEFORM_TEXT4:
7680                 case Q3DEFORM_TEXT5:
7681                 case Q3DEFORM_TEXT6:
7682                 case Q3DEFORM_TEXT7:
7683                 case Q3DEFORM_NONE:
7684                         break;
7685                 case Q3DEFORM_AUTOSPRITE:
7686                         if (!dynamicvertex)
7687                         {
7688                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1;
7689                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces;
7690                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices;
7691                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles;
7692                         }
7693                         dynamicvertex = true;
7694                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD;
7695                         needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7696                         break;
7697                 case Q3DEFORM_AUTOSPRITE2:
7698                         if (!dynamicvertex)
7699                         {
7700                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1;
7701                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces;
7702                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices;
7703                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles;
7704                         }
7705                         dynamicvertex = true;
7706                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7707                         needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7708                         break;
7709                 case Q3DEFORM_NORMAL:
7710                         if (!dynamicvertex)
7711                         {
7712                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1;
7713                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces;
7714                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices;
7715                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles;
7716                         }
7717                         dynamicvertex = true;
7718                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7719                         needsupdate |= BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7720                         break;
7721                 case Q3DEFORM_WAVE:
7722                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7723                                 break; // if wavefunc is a nop, ignore this transform
7724                         if (!dynamicvertex)
7725                         {
7726                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_wave] += 1;
7727                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces;
7728                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices;
7729                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles;
7730                         }
7731                         dynamicvertex = true;
7732                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7733                         needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7734                         break;
7735                 case Q3DEFORM_BULGE:
7736                         if (!dynamicvertex)
7737                         {
7738                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1;
7739                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces;
7740                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices;
7741                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles;
7742                         }
7743                         dynamicvertex = true;
7744                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7745                         needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7746                         break;
7747                 case Q3DEFORM_MOVE:
7748                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7749                                 break; // if wavefunc is a nop, ignore this transform
7750                         if (!dynamicvertex)
7751                         {
7752                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1;
7753                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces;
7754                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices;
7755                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles;
7756                         }
7757                         dynamicvertex = true;
7758                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7759                         needsupdate |= BATCHNEED_VERTEXMESH_VERTEX;
7760                         break;
7761                 }
7762         }
7763         if (rsurface.texture->materialshaderpass)
7764         {
7765                 switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
7766                 {
7767                 default:
7768                 case Q3TCGEN_TEXTURE:
7769                         break;
7770                 case Q3TCGEN_LIGHTMAP:
7771                         if (!dynamicvertex)
7772                         {
7773                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
7774                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
7775                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
7776                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
7777                         }
7778                         dynamicvertex = true;
7779                         batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7780                         needsupdate |= BATCHNEED_VERTEXMESH_LIGHTMAP;
7781                         break;
7782                 case Q3TCGEN_VECTOR:
7783                         if (!dynamicvertex)
7784                         {
7785                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
7786                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
7787                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
7788                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
7789                         }
7790                         dynamicvertex = true;
7791                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7792                         needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
7793                         break;
7794                 case Q3TCGEN_ENVIRONMENT:
7795                         if (!dynamicvertex)
7796                         {
7797                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
7798                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
7799                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
7800                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
7801                         }
7802                         dynamicvertex = true;
7803                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
7804                         needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
7805                         break;
7806                 }
7807                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
7808                 {
7809                         if (!dynamicvertex)
7810                         {
7811                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
7812                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
7813                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
7814                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
7815                         }
7816                         dynamicvertex = true;
7817                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7818                         needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
7819                 }
7820         }
7821
7822         if (!rsurface.modelvertexmesh && (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)))
7823         {
7824                 if (!dynamicvertex)
7825                 {
7826                         r_refdef.stats[r_stat_batch_dynamic_batches_because_interleavedarrays] += 1;
7827                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_interleavedarrays] += batchnumsurfaces;
7828                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_interleavedarrays] += batchnumvertices;
7829                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_interleavedarrays] += batchnumtriangles;
7830                 }
7831                 dynamicvertex = true;
7832                 needsupdate |= (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP));
7833         }
7834
7835         // when the model data has no vertex buffer (dynamic mesh), we need to
7836         // eliminate gaps
7837         if (vid.useinterleavedarrays && !rsurface.modelvertexmesh_vertexbuffer)
7838                 batchneed |= BATCHNEED_NOGAPS;
7839
7840         // the caller can specify BATCHNEED_NOGAPS to force a batch with
7841         // firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex),
7842         // we ensure this by treating the vertex batch as dynamic...
7843         if ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0))
7844         {
7845                 if (!dynamicvertex)
7846                 {
7847                         r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1;
7848                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces;
7849                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices;
7850                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles;
7851                 }
7852                 dynamicvertex = true;
7853         }
7854
7855         if (dynamicvertex)
7856         {
7857                 // when copying, we need to consider the regeneration of vertexmesh, any dependencies it may have must be set...
7858                 if (batchneed & BATCHNEED_VERTEXMESH_VERTEX)      batchneed |= BATCHNEED_ARRAY_VERTEX;
7859                 if (batchneed & BATCHNEED_VERTEXMESH_NORMAL)      batchneed |= BATCHNEED_ARRAY_NORMAL;
7860                 if (batchneed & BATCHNEED_VERTEXMESH_VECTOR)      batchneed |= BATCHNEED_ARRAY_VECTOR;
7861                 if (batchneed & BATCHNEED_VERTEXMESH_VERTEXCOLOR) batchneed |= BATCHNEED_ARRAY_VERTEXCOLOR;
7862                 if (batchneed & BATCHNEED_VERTEXMESH_TEXCOORD)    batchneed |= BATCHNEED_ARRAY_TEXCOORD;
7863                 if (batchneed & BATCHNEED_VERTEXMESH_LIGHTMAP)    batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7864                 if (batchneed & BATCHNEED_VERTEXMESH_SKELETAL)    batchneed |= BATCHNEED_ARRAY_SKELETAL;
7865         }
7866
7867         // if needsupdate, we have to do a dynamic vertex batch for sure
7868         if (needsupdate & batchneed)
7869         {
7870                 if (!dynamicvertex)
7871                 {
7872                         r_refdef.stats[r_stat_batch_dynamic_batches_because_derived] += 1;
7873                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_derived] += batchnumsurfaces;
7874                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_derived] += batchnumvertices;
7875                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_derived] += batchnumtriangles;
7876                 }
7877                 dynamicvertex = true;
7878         }
7879
7880         // see if we need to build vertexmesh from arrays
7881         if (!rsurface.modelvertexmesh && (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)))
7882         {
7883                 if (!dynamicvertex)
7884                 {
7885                         r_refdef.stats[r_stat_batch_dynamic_batches_because_interleavedarrays] += 1;
7886                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_interleavedarrays] += batchnumsurfaces;
7887                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_interleavedarrays] += batchnumvertices;
7888                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_interleavedarrays] += batchnumtriangles;
7889                 }
7890                 dynamicvertex = true;
7891         }
7892
7893         // if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data
7894         if (dynamicvertex && rsurface.entityskeletaltransform3x4)
7895                 batchneed |= BATCHNEED_ARRAY_SKELETAL;
7896
7897         rsurface.batchvertex3f = rsurface.modelvertex3f;
7898         rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer;
7899         rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
7900         rsurface.batchsvector3f = rsurface.modelsvector3f;
7901         rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer;
7902         rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
7903         rsurface.batchtvector3f = rsurface.modeltvector3f;
7904         rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer;
7905         rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
7906         rsurface.batchnormal3f = rsurface.modelnormal3f;
7907         rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer;
7908         rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
7909         rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f;
7910         rsurface.batchlightmapcolor4f_vertexbuffer  = rsurface.modellightmapcolor4f_vertexbuffer;
7911         rsurface.batchlightmapcolor4f_bufferoffset  = rsurface.modellightmapcolor4f_bufferoffset;
7912         rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f;
7913         rsurface.batchtexcoordtexture2f_vertexbuffer  = rsurface.modeltexcoordtexture2f_vertexbuffer;
7914         rsurface.batchtexcoordtexture2f_bufferoffset  = rsurface.modeltexcoordtexture2f_bufferoffset;
7915         rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
7916         rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer;
7917         rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
7918         rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub;
7919         rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer;
7920         rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset;
7921         rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub;
7922         rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer;
7923         rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset;
7924         rsurface.batchvertexmesh = rsurface.modelvertexmesh;
7925         rsurface.batchvertexmesh_vertexbuffer = rsurface.modelvertexmesh_vertexbuffer;
7926         rsurface.batchvertexmesh_bufferoffset = rsurface.modelvertexmesh_bufferoffset;
7927         rsurface.batchelement3i = rsurface.modelelement3i;
7928         rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer;
7929         rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset;
7930         rsurface.batchelement3s = rsurface.modelelement3s;
7931         rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer;
7932         rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset;
7933         rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4;
7934         rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer;
7935         rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset;
7936         rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size;
7937         rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms;
7938
7939         // if any dynamic vertex processing has to occur in software, we copy the
7940         // entire surface list together before processing to rebase the vertices
7941         // to start at 0 (otherwise we waste a lot of room in a vertex buffer).
7942         //
7943         // if any gaps exist and we do not have a static vertex buffer, we have to
7944         // copy the surface list together to avoid wasting upload bandwidth on the
7945         // vertices in the gaps.
7946         //
7947         // if gaps exist and we have a static vertex buffer, we can choose whether
7948         // to combine the index buffer ranges into one dynamic index buffer or
7949         // simply issue multiple glDrawElements calls (BATCHNEED_ALLOWMULTIDRAW).
7950         //
7951         // in many cases the batch is reduced to one draw call.
7952
7953         rsurface.batchmultidraw = false;
7954         rsurface.batchmultidrawnumsurfaces = 0;
7955         rsurface.batchmultidrawsurfacelist = NULL;
7956
7957         if (!dynamicvertex)
7958         {
7959                 // static vertex data, just set pointers...
7960                 rsurface.batchgeneratedvertex = false;
7961                 // if there are gaps, we want to build a combined index buffer,
7962                 // otherwise use the original static buffer with an appropriate offset
7963                 if (gaps)
7964                 {
7965                         r_refdef.stats[r_stat_batch_copytriangles_batches] += 1;
7966                         r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces;
7967                         r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices;
7968                         r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles;
7969                         if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer)
7970                         {
7971                                 rsurface.batchmultidraw = true;
7972                                 rsurface.batchmultidrawnumsurfaces = texturenumsurfaces;
7973                                 rsurface.batchmultidrawsurfacelist = texturesurfacelist;
7974                                 return;
7975                         }
7976                         // build a new triangle elements array for this batch
7977                         rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7978                         rsurface.batchfirsttriangle = 0;
7979                         numtriangles = 0;
7980                         for (i = 0;i < texturenumsurfaces;i++)
7981                         {
7982                                 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7983                                 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7984                                 memcpy(rsurface.batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3]));
7985                                 numtriangles += surfacenumtriangles;
7986                         }
7987                         rsurface.batchelement3i_indexbuffer = NULL;
7988                         rsurface.batchelement3i_bufferoffset = 0;
7989                         rsurface.batchelement3s = NULL;
7990                         rsurface.batchelement3s_indexbuffer = NULL;
7991                         rsurface.batchelement3s_bufferoffset = 0;
7992                         if (endvertex <= 65536)
7993                         {
7994                                 // make a 16bit (unsigned short) index array if possible
7995                                 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7996                                 for (i = 0;i < numtriangles*3;i++)
7997                                         rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7998                         }
7999                         // upload buffer data for the copytriangles batch
8000                         if (((r_batch_dynamicbuffer.integer || gl_vbo_dynamicindex.integer) && vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo)
8001                         {
8002                                 if (rsurface.batchelement3s)
8003                                         rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
8004                                 else if (rsurface.batchelement3i)
8005                                         rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
8006                         }
8007                 }
8008                 else
8009                 {
8010                         r_refdef.stats[r_stat_batch_fast_batches] += 1;
8011                         r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces;
8012                         r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices;
8013                         r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles;
8014                 }
8015                 return;
8016         }
8017
8018         // something needs software processing, do it for real...
8019         // we only directly handle separate array data in this case and then
8020         // generate interleaved data if needed...
8021         rsurface.batchgeneratedvertex = true;
8022         r_refdef.stats[r_stat_batch_dynamic_batches] += 1;
8023         r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces;
8024         r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices;
8025         r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles;
8026
8027         // now copy the vertex data into a combined array and make an index array
8028         // (this is what Quake3 does all the time)
8029         // we also apply any skeletal animation here that would have been done in
8030         // the vertex shader, because most of the dynamic vertex animation cases
8031         // need actual vertex positions and normals
8032         //if (dynamicvertex)
8033         {
8034                 rsurface.batchvertexmesh = NULL;
8035                 rsurface.batchvertexmesh_vertexbuffer = NULL;
8036                 rsurface.batchvertexmesh_bufferoffset = 0;
8037                 rsurface.batchvertex3f = NULL;
8038                 rsurface.batchvertex3f_vertexbuffer = NULL;
8039                 rsurface.batchvertex3f_bufferoffset = 0;
8040                 rsurface.batchsvector3f = NULL;
8041                 rsurface.batchsvector3f_vertexbuffer = NULL;
8042                 rsurface.batchsvector3f_bufferoffset = 0;
8043                 rsurface.batchtvector3f = NULL;
8044                 rsurface.batchtvector3f_vertexbuffer = NULL;
8045                 rsurface.batchtvector3f_bufferoffset = 0;
8046                 rsurface.batchnormal3f = NULL;
8047                 rsurface.batchnormal3f_vertexbuffer = NULL;
8048                 rsurface.batchnormal3f_bufferoffset = 0;
8049                 rsurface.batchlightmapcolor4f = NULL;
8050                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8051                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8052                 rsurface.batchtexcoordtexture2f = NULL;
8053                 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8054                 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8055                 rsurface.batchtexcoordlightmap2f = NULL;
8056                 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
8057                 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
8058                 rsurface.batchskeletalindex4ub = NULL;
8059                 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
8060                 rsurface.batchskeletalindex4ub_bufferoffset = 0;
8061                 rsurface.batchskeletalweight4ub = NULL;
8062                 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
8063                 rsurface.batchskeletalweight4ub_bufferoffset = 0;
8064                 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
8065                 rsurface.batchelement3i_indexbuffer = NULL;
8066                 rsurface.batchelement3i_bufferoffset = 0;
8067                 rsurface.batchelement3s = NULL;
8068                 rsurface.batchelement3s_indexbuffer = NULL;
8069                 rsurface.batchelement3s_bufferoffset = 0;
8070                 rsurface.batchskeletaltransform3x4buffer = NULL;
8071                 rsurface.batchskeletaltransform3x4offset = 0;
8072                 rsurface.batchskeletaltransform3x4size = 0;
8073                 // we'll only be setting up certain arrays as needed
8074                 if (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP))
8075                         rsurface.batchvertexmesh = (r_vertexmesh_t *)R_FrameData_Alloc(batchnumvertices * sizeof(r_vertexmesh_t));
8076                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
8077                         rsurface.batchvertex3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8078                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
8079                         rsurface.batchnormal3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8080                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
8081                 {
8082                         rsurface.batchsvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8083                         rsurface.batchtvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8084                 }
8085                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
8086                         rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8087                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
8088                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8089                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
8090                         rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8091                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
8092                 {
8093                         rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
8094                         rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
8095                 }
8096                 numvertices = 0;
8097                 numtriangles = 0;
8098                 for (i = 0;i < texturenumsurfaces;i++)
8099                 {
8100                         surfacefirstvertex = texturesurfacelist[i]->num_firstvertex;
8101                         surfacenumvertices = texturesurfacelist[i]->num_vertices;
8102                         surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
8103                         surfacenumtriangles = texturesurfacelist[i]->num_triangles;
8104                         // copy only the data requested
8105                         if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)) && rsurface.modelvertexmesh)
8106                                 memcpy(rsurface.batchvertexmesh + numvertices, rsurface.modelvertexmesh + surfacefirstvertex, surfacenumvertices * sizeof(rsurface.batchvertexmesh[0]));
8107                         if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
8108                         {
8109                                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
8110                                 {
8111                                         if (rsurface.batchvertex3f)
8112                                                 memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8113                                         else
8114                                                 memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8115                                 }
8116                                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
8117                                 {
8118                                         if (rsurface.modelnormal3f)
8119                                                 memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8120                                         else
8121                                                 memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8122                                 }
8123                                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
8124                                 {
8125                                         if (rsurface.modelsvector3f)
8126                                         {
8127                                                 memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8128                                                 memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8129                                         }
8130                                         else
8131                                         {
8132                                                 memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8133                                                 memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8134                                         }
8135                                 }
8136                                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
8137                                 {
8138                                         if (rsurface.modellightmapcolor4f)
8139                                                 memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
8140                                         else
8141                                                 memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4]));
8142                                 }
8143                                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
8144                                 {
8145                                         if (rsurface.modeltexcoordtexture2f)
8146                                                 memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
8147                                         else
8148                                                 memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
8149                                 }
8150                                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
8151                                 {
8152                                         if (rsurface.modeltexcoordlightmap2f)
8153                                                 memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
8154                                         else
8155                                                 memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
8156                                 }
8157                                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
8158                                 {
8159                                         if (rsurface.modelskeletalindex4ub)
8160                                         {
8161                                                 memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
8162                                                 memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
8163                                         }
8164                                         else
8165                                         {
8166                                                 memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
8167                                                 memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
8168                                                 ub = rsurface.batchskeletalweight4ub + 4*numvertices;
8169                                                 for (j = 0;j < surfacenumvertices;j++)
8170                                                         ub[j*4] = 255;
8171                                         }
8172                                 }
8173                         }
8174                         RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
8175                         numvertices += surfacenumvertices;
8176                         numtriangles += surfacenumtriangles;
8177                 }
8178
8179                 // generate a 16bit index array as well if possible
8180                 // (in general, dynamic batches fit)
8181                 if (numvertices <= 65536)
8182                 {
8183                         rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
8184                         for (i = 0;i < numtriangles*3;i++)
8185                                 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
8186                 }
8187
8188                 // since we've copied everything, the batch now starts at 0
8189                 rsurface.batchfirstvertex = 0;
8190                 rsurface.batchnumvertices = batchnumvertices;
8191                 rsurface.batchfirsttriangle = 0;
8192                 rsurface.batchnumtriangles = batchnumtriangles;
8193         }
8194
8195         // apply skeletal animation that would have been done in the vertex shader
8196         if (rsurface.batchskeletaltransform3x4)
8197         {
8198                 const unsigned char *si;
8199                 const unsigned char *sw;
8200                 const float *t[4];
8201                 const float *b = rsurface.batchskeletaltransform3x4;
8202                 float *vp, *vs, *vt, *vn;
8203                 float w[4];
8204                 float m[3][4], n[3][4];
8205                 float tp[3], ts[3], tt[3], tn[3];
8206                 r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1;
8207                 r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces;
8208                 r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices;
8209                 r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles;
8210                 si = rsurface.batchskeletalindex4ub;
8211                 sw = rsurface.batchskeletalweight4ub;
8212                 vp = rsurface.batchvertex3f;
8213                 vs = rsurface.batchsvector3f;
8214                 vt = rsurface.batchtvector3f;
8215                 vn = rsurface.batchnormal3f;
8216                 memset(m[0], 0, sizeof(m));
8217                 memset(n[0], 0, sizeof(n));
8218                 for (i = 0;i < batchnumvertices;i++)
8219                 {
8220                         t[0] = b + si[0]*12;
8221                         if (sw[0] == 255)
8222                         {
8223                                 // common case - only one matrix
8224                                 m[0][0] = t[0][ 0];
8225                                 m[0][1] = t[0][ 1];
8226                                 m[0][2] = t[0][ 2];
8227                                 m[0][3] = t[0][ 3];
8228                                 m[1][0] = t[0][ 4];
8229                                 m[1][1] = t[0][ 5];
8230                                 m[1][2] = t[0][ 6];
8231                                 m[1][3] = t[0][ 7];
8232                                 m[2][0] = t[0][ 8];
8233                                 m[2][1] = t[0][ 9];
8234                                 m[2][2] = t[0][10];
8235                                 m[2][3] = t[0][11];
8236                         }
8237                         else if (sw[2] + sw[3])
8238                         {
8239                                 // blend 4 matrices
8240                                 t[1] = b + si[1]*12;
8241                                 t[2] = b + si[2]*12;
8242                                 t[3] = b + si[3]*12;
8243                                 w[0] = sw[0] * (1.0f / 255.0f);
8244                                 w[1] = sw[1] * (1.0f / 255.0f);
8245                                 w[2] = sw[2] * (1.0f / 255.0f);
8246                                 w[3] = sw[3] * (1.0f / 255.0f);
8247                                 // blend the matrices
8248                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3];
8249                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3];
8250                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3];
8251                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3];
8252                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3];
8253                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3];
8254                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3];
8255                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3];
8256                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3];
8257                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3];
8258                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3];
8259                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3];
8260                         }
8261                         else
8262                         {
8263                                 // blend 2 matrices
8264                                 t[1] = b + si[1]*12;
8265                                 w[0] = sw[0] * (1.0f / 255.0f);
8266                                 w[1] = sw[1] * (1.0f / 255.0f);
8267                                 // blend the matrices
8268                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1];
8269                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1];
8270                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1];
8271                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1];
8272                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1];
8273                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1];
8274                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1];
8275                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1];
8276                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1];
8277                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1];
8278                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1];
8279                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1];
8280                         }
8281                         si += 4;
8282                         sw += 4;
8283                         // modify the vertex
8284                         VectorCopy(vp, tp);
8285                         vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3];
8286                         vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3];
8287                         vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3];
8288                         vp += 3;
8289                         if (vn)
8290                         {
8291                                 // the normal transformation matrix is a set of cross products...
8292                                 CrossProduct(m[1], m[2], n[0]);
8293                                 CrossProduct(m[2], m[0], n[1]);
8294                                 CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m)
8295                                 VectorCopy(vn, tn);
8296                                 vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2];
8297                                 vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2];
8298                                 vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2];
8299                                 VectorNormalize(vn);
8300                                 vn += 3;
8301                                 if (vs)
8302                                 {
8303                                         VectorCopy(vs, ts);
8304                                         vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2];
8305                                         vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2];
8306                                         vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2];
8307                                         VectorNormalize(vs);
8308                                         vs += 3;
8309                                         VectorCopy(vt, tt);
8310                                         vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2];
8311                                         vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2];
8312                                         vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2];
8313                                         VectorNormalize(vt);
8314                                         vt += 3;
8315                                 }
8316                         }
8317                 }
8318                 rsurface.batchskeletaltransform3x4 = NULL;
8319                 rsurface.batchskeletalnumtransforms = 0;
8320         }
8321
8322         // q1bsp surfaces rendered in vertex color mode have to have colors
8323         // calculated based on lightstyles
8324         if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_ARRAY_VERTEXCOLOR)) && texturesurfacelist[0]->lightmapinfo)
8325         {
8326                 // generate color arrays for the surfaces in this list
8327                 int c[4];
8328                 int scale;
8329                 int size3;
8330                 const int *offsets;
8331                 const unsigned char *lm;
8332                 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8333                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8334                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8335                 numvertices = 0;
8336                 for (i = 0;i < texturenumsurfaces;i++)
8337                 {
8338                         surface = texturesurfacelist[i];
8339                         offsets = rsurface.modellightmapoffsets + surface->num_firstvertex;
8340                         surfacenumvertices = surface->num_vertices;
8341                         if (surface->lightmapinfo->samples)
8342                         {
8343                                 for (j = 0;j < surfacenumvertices;j++)
8344                                 {
8345                                         lm = surface->lightmapinfo->samples + offsets[j];
8346                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]];
8347                                         VectorScale(lm, scale, c);
8348                                         if (surface->lightmapinfo->styles[1] != 255)
8349                                         {
8350                                                 size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
8351                                                 lm += size3;
8352                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]];
8353                                                 VectorMA(c, scale, lm, c);
8354                                                 if (surface->lightmapinfo->styles[2] != 255)
8355                                                 {
8356                                                         lm += size3;
8357                                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]];
8358                                                         VectorMA(c, scale, lm, c);
8359                                                         if (surface->lightmapinfo->styles[3] != 255)
8360                                                         {
8361                                                                 lm += size3;
8362                                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]];
8363                                                                 VectorMA(c, scale, lm, c);
8364                                                         }
8365                                                 }
8366                                         }
8367                                         c[0] >>= 7;
8368                                         c[1] >>= 7;
8369                                         c[2] >>= 7;
8370                                         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);
8371                                         numvertices++;
8372                                 }
8373                         }
8374                         else
8375                         {
8376                                 for (j = 0;j < surfacenumvertices;j++)
8377                                 {
8378                                         Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1);
8379                                         numvertices++;
8380                                 }
8381                         }
8382                 }
8383         }
8384
8385         // if vertices are deformed (sprite flares and things in maps, possibly
8386         // water waves, bulges and other deformations), modify the copied vertices
8387         // in place
8388         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
8389         {
8390                 float scale;
8391                 switch (deform->deform)
8392                 {
8393                 default:
8394                 case Q3DEFORM_PROJECTIONSHADOW:
8395                 case Q3DEFORM_TEXT0:
8396                 case Q3DEFORM_TEXT1:
8397                 case Q3DEFORM_TEXT2:
8398                 case Q3DEFORM_TEXT3:
8399                 case Q3DEFORM_TEXT4:
8400                 case Q3DEFORM_TEXT5:
8401                 case Q3DEFORM_TEXT6:
8402                 case Q3DEFORM_TEXT7:
8403                 case Q3DEFORM_NONE:
8404                         break;
8405                 case Q3DEFORM_AUTOSPRITE:
8406                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8407                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8408                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8409                         VectorNormalize(newforward);
8410                         VectorNormalize(newright);
8411                         VectorNormalize(newup);
8412 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8413 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8414 //                      rsurface.batchvertex3f_bufferoffset = 0;
8415 //                      rsurface.batchsvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f);
8416 //                      rsurface.batchsvector3f_vertexbuffer = NULL;
8417 //                      rsurface.batchsvector3f_bufferoffset = 0;
8418 //                      rsurface.batchtvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f);
8419 //                      rsurface.batchtvector3f_vertexbuffer = NULL;
8420 //                      rsurface.batchtvector3f_bufferoffset = 0;
8421 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8422 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8423 //                      rsurface.batchnormal3f_bufferoffset = 0;
8424                         // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1)
8425                         if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex))
8426                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8427                         if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex))
8428                                 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);
8429                         // a single autosprite surface can contain multiple sprites...
8430                         for (j = 0;j < batchnumvertices - 3;j += 4)
8431                         {
8432                                 VectorClear(center);
8433                                 for (i = 0;i < 4;i++)
8434                                         VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8435                                 VectorScale(center, 0.25f, center);
8436                                 VectorCopy(rsurface.batchnormal3f + 3*j, forward);
8437                                 VectorCopy(rsurface.batchsvector3f + 3*j, right);
8438                                 VectorCopy(rsurface.batchtvector3f + 3*j, up);
8439                                 for (i = 0;i < 4;i++)
8440                                 {
8441                                         VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v);
8442                                         VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.batchvertex3f + 3*(j+i));
8443                                 }
8444                         }
8445                         // if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check
8446                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8447                         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);
8448                         break;
8449                 case Q3DEFORM_AUTOSPRITE2:
8450                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8451                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8452                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8453                         VectorNormalize(newforward);
8454                         VectorNormalize(newright);
8455                         VectorNormalize(newup);
8456 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8457 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8458 //                      rsurface.batchvertex3f_bufferoffset = 0;
8459                         {
8460                                 const float *v1, *v2;
8461                                 vec3_t start, end;
8462                                 float f, l;
8463                                 struct
8464                                 {
8465                                         float length2;
8466                                         const float *v1;
8467                                         const float *v2;
8468                                 }
8469                                 shortest[2];
8470                                 memset(shortest, 0, sizeof(shortest));
8471                                 // a single autosprite surface can contain multiple sprites...
8472                                 for (j = 0;j < batchnumvertices - 3;j += 4)
8473                                 {
8474                                         VectorClear(center);
8475                                         for (i = 0;i < 4;i++)
8476                                                 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8477                                         VectorScale(center, 0.25f, center);
8478                                         // find the two shortest edges, then use them to define the
8479                                         // axis vectors for rotating around the central axis
8480                                         for (i = 0;i < 6;i++)
8481                                         {
8482                                                 v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]);
8483                                                 v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]);
8484                                                 l = VectorDistance2(v1, v2);
8485                                                 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
8486                                                 if (v1[2] != v2[2])
8487                                                         l += (1.0f / 1024.0f);
8488                                                 if (shortest[0].length2 > l || i == 0)
8489                                                 {
8490                                                         shortest[1] = shortest[0];
8491                                                         shortest[0].length2 = l;
8492                                                         shortest[0].v1 = v1;
8493                                                         shortest[0].v2 = v2;
8494                                                 }
8495                                                 else if (shortest[1].length2 > l || i == 1)
8496                                                 {
8497                                                         shortest[1].length2 = l;
8498                                                         shortest[1].v1 = v1;
8499                                                         shortest[1].v2 = v2;
8500                                                 }
8501                                         }
8502                                         VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
8503                                         VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
8504                                         // this calculates the right vector from the shortest edge
8505                                         // and the up vector from the edge midpoints
8506                                         VectorSubtract(shortest[0].v1, shortest[0].v2, right);
8507                                         VectorNormalize(right);
8508                                         VectorSubtract(end, start, up);
8509                                         VectorNormalize(up);
8510                                         // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
8511                                         VectorSubtract(rsurface.localvieworigin, center, forward);
8512                                         //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
8513                                         VectorNegate(forward, forward);
8514                                         VectorReflect(forward, 0, up, forward);
8515                                         VectorNormalize(forward);
8516                                         CrossProduct(up, forward, newright);
8517                                         VectorNormalize(newright);
8518                                         // rotate the quad around the up axis vector, this is made
8519                                         // especially easy by the fact we know the quad is flat,
8520                                         // so we only have to subtract the center position and
8521                                         // measure distance along the right vector, and then
8522                                         // multiply that by the newright vector and add back the
8523                                         // center position
8524                                         // we also need to subtract the old position to undo the
8525                                         // displacement from the center, which we do with a
8526                                         // DotProduct, the subtraction/addition of center is also
8527                                         // optimized into DotProducts here
8528                                         l = DotProduct(right, center);
8529                                         for (i = 0;i < 4;i++)
8530                                         {
8531                                                 v1 = rsurface.batchvertex3f + 3*(j+i);
8532                                                 f = DotProduct(right, v1) - l;
8533                                                 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.batchvertex3f + 3*(j+i));
8534                                         }
8535                                 }
8536                         }
8537                         if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL
8538                         {
8539 //                              rsurface.batchnormal3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8540 //                              rsurface.batchnormal3f_vertexbuffer = NULL;
8541 //                              rsurface.batchnormal3f_bufferoffset = 0;
8542                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8543                         }
8544                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8545                         {
8546 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8547 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8548 //                              rsurface.batchsvector3f_bufferoffset = 0;
8549 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8550 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8551 //                              rsurface.batchtvector3f_bufferoffset = 0;
8552                                 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);
8553                         }
8554                         break;
8555                 case Q3DEFORM_NORMAL:
8556                         // deform the normals to make reflections wavey
8557                         rsurface.batchnormal3f = (float *)R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8558                         rsurface.batchnormal3f_vertexbuffer = NULL;
8559                         rsurface.batchnormal3f_bufferoffset = 0;
8560                         for (j = 0;j < batchnumvertices;j++)
8561                         {
8562                                 float vertex[3];
8563                                 float *normal = rsurface.batchnormal3f + 3*j;
8564                                 VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
8565                                 normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f(      vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8566                                 normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8567                                 normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8568                                 VectorNormalize(normal);
8569                         }
8570                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8571                         {
8572 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8573 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8574 //                              rsurface.batchsvector3f_bufferoffset = 0;
8575 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8576 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8577 //                              rsurface.batchtvector3f_bufferoffset = 0;
8578                                 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);
8579                         }
8580                         break;
8581                 case Q3DEFORM_WAVE:
8582                         // deform vertex array to make wavey water and flags and such
8583                         waveparms[0] = deform->waveparms[0];
8584                         waveparms[1] = deform->waveparms[1];
8585                         waveparms[2] = deform->waveparms[2];
8586                         waveparms[3] = deform->waveparms[3];
8587                         if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms))
8588                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8589                         // this is how a divisor of vertex influence on deformation
8590                         animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
8591                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8592 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8593 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8594 //                      rsurface.batchvertex3f_bufferoffset = 0;
8595 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8596 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8597 //                      rsurface.batchnormal3f_bufferoffset = 0;
8598                         for (j = 0;j < batchnumvertices;j++)
8599                         {
8600                                 // if the wavefunc depends on time, evaluate it per-vertex
8601                                 if (waveparms[3])
8602                                 {
8603                                         waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos;
8604                                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8605                                 }
8606                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8607                         }
8608                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8609                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8610                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8611                         {
8612 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8613 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8614 //                              rsurface.batchsvector3f_bufferoffset = 0;
8615 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8616 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8617 //                              rsurface.batchtvector3f_bufferoffset = 0;
8618                                 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);
8619                         }
8620                         break;
8621                 case Q3DEFORM_BULGE:
8622                         // deform vertex array to make the surface have moving bulges
8623 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8624 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8625 //                      rsurface.batchvertex3f_bufferoffset = 0;
8626 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8627 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8628 //                      rsurface.batchnormal3f_bufferoffset = 0;
8629                         for (j = 0;j < batchnumvertices;j++)
8630                         {
8631                                 scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1];
8632                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8633                         }
8634                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8635                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8636                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8637                         {
8638 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8639 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8640 //                              rsurface.batchsvector3f_bufferoffset = 0;
8641 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8642 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8643 //                              rsurface.batchtvector3f_bufferoffset = 0;
8644                                 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);
8645                         }
8646                         break;
8647                 case Q3DEFORM_MOVE:
8648                         // deform vertex array
8649                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
8650                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8651                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
8652                         VectorScale(deform->parms, scale, waveparms);
8653 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8654 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8655 //                      rsurface.batchvertex3f_bufferoffset = 0;
8656                         for (j = 0;j < batchnumvertices;j++)
8657                                 VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.batchvertex3f + 3*j);
8658                         break;
8659                 }
8660         }
8661
8662         if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
8663         {
8664         // generate texcoords based on the chosen texcoord source
8665                 switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
8666                 {
8667                 default:
8668                 case Q3TCGEN_TEXTURE:
8669                         break;
8670                 case Q3TCGEN_LIGHTMAP:
8671         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8672         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8673         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8674                         if (rsurface.batchtexcoordlightmap2f)
8675                                 memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
8676                         break;
8677                 case Q3TCGEN_VECTOR:
8678         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8679         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8680         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8681                         for (j = 0;j < batchnumvertices;j++)
8682                         {
8683                                 rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
8684                                 rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
8685                         }
8686                         break;
8687                 case Q3TCGEN_ENVIRONMENT:
8688                         // make environment reflections using a spheremap
8689                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8690                         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8691                         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8692                         for (j = 0;j < batchnumvertices;j++)
8693                         {
8694                                 // identical to Q3A's method, but executed in worldspace so
8695                                 // carried models can be shiny too
8696
8697                                 float viewer[3], d, reflected[3], worldreflected[3];
8698
8699                                 VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
8700                                 // VectorNormalize(viewer);
8701
8702                                 d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
8703
8704                                 reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
8705                                 reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
8706                                 reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
8707                                 // note: this is proportinal to viewer, so we can normalize later
8708
8709                                 Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
8710                                 VectorNormalize(worldreflected);
8711
8712                                 // note: this sphere map only uses world x and z!
8713                                 // so positive and negative y will LOOK THE SAME.
8714                                 rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
8715                                 rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
8716                         }
8717                         break;
8718                 }
8719                 // the only tcmod that needs software vertex processing is turbulent, so
8720                 // check for it here and apply the changes if needed
8721                 // and we only support that as the first one
8722                 // (handling a mixture of turbulent and other tcmods would be problematic
8723                 //  without punting it entirely to a software path)
8724                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
8725                 {
8726                         amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
8727                         animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
8728         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8729         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8730         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8731                         for (j = 0;j < batchnumvertices;j++)
8732                         {
8733                                 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);
8734                                 rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1]                                ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8735                         }
8736                 }
8737         }
8738
8739         if (needsupdate & batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP))
8740         {
8741                 // convert the modified arrays to vertex structs
8742 //              rsurface.batchvertexmesh = R_FrameData_Alloc(batchnumvertices * sizeof(r_vertexmesh_t));
8743 //              rsurface.batchvertexmesh_vertexbuffer = NULL;
8744 //              rsurface.batchvertexmesh_bufferoffset = 0;
8745                 if (batchneed & BATCHNEED_VERTEXMESH_VERTEX)
8746                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8747                                 VectorCopy(rsurface.batchvertex3f + 3*j, vertexmesh->vertex3f);
8748                 if (batchneed & BATCHNEED_VERTEXMESH_NORMAL)
8749                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8750                                 VectorCopy(rsurface.batchnormal3f + 3*j, vertexmesh->normal3f);
8751                 if (batchneed & BATCHNEED_VERTEXMESH_VECTOR)
8752                 {
8753                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8754                         {
8755                                 VectorCopy(rsurface.batchsvector3f + 3*j, vertexmesh->svector3f);
8756                                 VectorCopy(rsurface.batchtvector3f + 3*j, vertexmesh->tvector3f);
8757                         }
8758                 }
8759                 if ((batchneed & BATCHNEED_VERTEXMESH_VERTEXCOLOR) && rsurface.batchlightmapcolor4f)
8760                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8761                                 Vector4Copy(rsurface.batchlightmapcolor4f + 4*j, vertexmesh->color4f);
8762                 if (batchneed & BATCHNEED_VERTEXMESH_TEXCOORD)
8763                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8764                                 Vector2Copy(rsurface.batchtexcoordtexture2f + 2*j, vertexmesh->texcoordtexture2f);
8765                 if ((batchneed & BATCHNEED_VERTEXMESH_LIGHTMAP) && rsurface.batchtexcoordlightmap2f)
8766                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8767                                 Vector2Copy(rsurface.batchtexcoordlightmap2f + 2*j, vertexmesh->texcoordlightmap2f);
8768                 if ((batchneed & BATCHNEED_VERTEXMESH_SKELETAL) && rsurface.batchskeletalindex4ub)
8769                 {
8770                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8771                         {
8772                                 Vector4Copy(rsurface.batchskeletalindex4ub + 4*j, vertexmesh->skeletalindex4ub);
8773                                 Vector4Copy(rsurface.batchskeletalweight4ub + 4*j, vertexmesh->skeletalweight4ub);
8774                         }
8775                 }
8776         }
8777
8778         // upload buffer data for the dynamic batch
8779         if (((r_batch_dynamicbuffer.integer || gl_vbo_dynamicvertex.integer || gl_vbo_dynamicindex.integer) && vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo)
8780         {
8781                 if (rsurface.batchvertexmesh)
8782                         rsurface.batchvertexmesh_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(r_vertexmesh_t), rsurface.batchvertexmesh, R_BUFFERDATA_VERTEX, &rsurface.batchvertexmesh_bufferoffset);
8783                 else
8784                 {
8785                         if (rsurface.batchvertex3f)
8786                                 rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
8787                         if (rsurface.batchsvector3f)
8788                                 rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
8789                         if (rsurface.batchtvector3f)
8790                                 rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
8791                         if (rsurface.batchnormal3f)
8792                                 rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
8793                         if (rsurface.batchlightmapcolor4f)
8794                                 rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
8795                         if (rsurface.batchtexcoordtexture2f)
8796                                 rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
8797                         if (rsurface.batchtexcoordlightmap2f)
8798                                 rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
8799                         if (rsurface.batchskeletalindex4ub)
8800                                 rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
8801                         if (rsurface.batchskeletalweight4ub)
8802                                 rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
8803                 }
8804                 if (rsurface.batchelement3s)
8805                         rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
8806                 else if (rsurface.batchelement3i)
8807                         rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
8808         }
8809 }
8810
8811 void RSurf_DrawBatch(void)
8812 {
8813         // sometimes a zero triangle surface (usually a degenerate patch) makes it
8814         // through the pipeline, killing it earlier in the pipeline would have
8815         // per-surface overhead rather than per-batch overhead, so it's best to
8816         // reject it here, before it hits glDraw.
8817         if (rsurface.batchnumtriangles == 0)
8818                 return;
8819 #if 0
8820         // batch debugging code
8821         if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f)
8822         {
8823                 int i;
8824                 int j;
8825                 int c;
8826                 const int *e;
8827                 e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3;
8828                 for (i = 0;i < rsurface.batchnumtriangles*3;i++)
8829                 {
8830                         c = e[i];
8831                         for (j = 0;j < rsurface.entity->model->num_surfaces;j++)
8832                         {
8833                                 if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
8834                                 {
8835                                         if (rsurface.modelsurfaces[j].texture != rsurface.texture)
8836                                                 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);
8837                                         break;
8838                                 }
8839                         }
8840                 }
8841         }
8842 #endif
8843         if (rsurface.batchmultidraw)
8844         {
8845                 // issue multiple draws rather than copying index data
8846                 int numsurfaces = rsurface.batchmultidrawnumsurfaces;
8847                 const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist;
8848                 int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle;
8849                 for (i = 0;i < numsurfaces;)
8850                 {
8851                         // combine consecutive surfaces as one draw
8852                         for (k = i, j = i + 1;j < numsurfaces;k = j, j++)
8853                                 if (surfacelist[j] != surfacelist[k] + 1)
8854                                         break;
8855                         firstvertex = surfacelist[i]->num_firstvertex;
8856                         endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices;
8857                         firsttriangle = surfacelist[i]->num_firsttriangle;
8858                         endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles;
8859                         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);
8860                         i = j;
8861                 }
8862         }
8863         else
8864         {
8865                 // there is only one consecutive run of index data (may have been combined)
8866                 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);
8867         }
8868 }
8869
8870 static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface)
8871 {
8872         // pick the closest matching water plane
8873         int planeindex, vertexindex, bestplaneindex = -1;
8874         float d, bestd;
8875         vec3_t vert;
8876         const float *v;
8877         r_waterstate_waterplane_t *p;
8878         qboolean prepared = false;
8879         bestd = 0;
8880         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
8881         {
8882                 if(p->camera_entity != rsurface.texture->camera_entity)
8883                         continue;
8884                 d = 0;
8885                 if(!prepared)
8886                 {
8887                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
8888                         prepared = true;
8889                         if(rsurface.batchnumvertices == 0)
8890                                 break;
8891                 }
8892                 for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
8893                 {
8894                         Matrix4x4_Transform(&rsurface.matrix, v, vert);
8895                         d += fabs(PlaneDiff(vert, &p->plane));
8896                 }
8897                 if (bestd > d || bestplaneindex < 0)
8898                 {
8899                         bestd = d;
8900                         bestplaneindex = planeindex;
8901                 }
8902         }
8903         return bestplaneindex;
8904         // NOTE: this MAY return a totally unrelated water plane; we can ignore
8905         // this situation though, as it might be better to render single larger
8906         // batches with useless stuff (backface culled for example) than to
8907         // render multiple smaller batches
8908 }
8909
8910 void RSurf_SetupDepthAndCulling(void)
8911 {
8912         // submodels are biased to avoid z-fighting with world surfaces that they
8913         // may be exactly overlapping (avoids z-fighting artifacts on certain
8914         // doors and things in Quake maps)
8915         GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
8916         GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
8917         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
8918         GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
8919 }
8920
8921 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8922 {
8923         int i, j;
8924         // transparent sky would be ridiculous
8925         if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8926                 return;
8927         R_SetupShader_Generic_NoTexture(false, false);
8928         skyrenderlater = true;
8929         RSurf_SetupDepthAndCulling();
8930         GL_DepthMask(true);
8931
8932         // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
8933         if (r_sky_scissor.integer)
8934         {
8935                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8936                 for (i = 0; i < texturenumsurfaces; i++)
8937                 {
8938                         const msurface_t *surf = texturesurfacelist[i];
8939                         const float *v;
8940                         float p[3];
8941                         float mins[3], maxs[3];
8942                         int scissor[4];
8943                         for (j = 0, v = rsurface.batchvertex3f + 3 * surf->num_firstvertex; j < surf->num_vertices; j++, v += 3)
8944                         {
8945                                 Matrix4x4_Transform(&rsurface.matrix, v, p);
8946                                 if (j > 0)
8947                                 {
8948                                         if (mins[0] > p[0]) mins[0] = p[0];
8949                                         if (mins[1] > p[1]) mins[1] = p[1];
8950                                         if (mins[2] > p[2]) mins[2] = p[2];
8951                                         if (maxs[0] < p[0]) maxs[0] = p[0];
8952                                         if (maxs[1] < p[1]) maxs[1] = p[1];
8953                                         if (maxs[2] < p[2]) maxs[2] = p[2];
8954                                 }
8955                                 else
8956                                 {
8957                                         VectorCopy(p, mins);
8958                                         VectorCopy(p, maxs);
8959                                 }
8960                         }
8961                         if (!R_ScissorForBBox(mins, maxs, scissor))
8962                         {
8963                                 if (skyscissor[2])
8964                                 {
8965                                         if (skyscissor[0] > scissor[0])
8966                                         {
8967                                                 skyscissor[2] += skyscissor[0] - scissor[0];
8968                                                 skyscissor[0] = scissor[0];
8969                                         }
8970                                         if (skyscissor[1] > scissor[1])
8971                                         {
8972                                                 skyscissor[3] += skyscissor[1] - scissor[1];
8973                                                 skyscissor[1] = scissor[1];
8974                                         }
8975                                         if (skyscissor[0] + skyscissor[2] < scissor[0] + scissor[2])
8976                                                 skyscissor[2] = scissor[0] + scissor[2] - skyscissor[0];
8977                                         if (skyscissor[1] + skyscissor[3] < scissor[1] + scissor[3])
8978                                                 skyscissor[3] = scissor[1] + scissor[3] - skyscissor[1];
8979                                 }
8980                                 else
8981                                         Vector4Copy(scissor, skyscissor);
8982                         }
8983                 }
8984         }
8985
8986         // LadyHavoc: HalfLife maps have freaky skypolys so don't use
8987         // skymasking on them, and Quake3 never did sky masking (unlike
8988         // software Quake and software Quake2), so disable the sky masking
8989         // in Quake3 maps as it causes problems with q3map2 sky tricks,
8990         // and skymasking also looks very bad when noclipping outside the
8991         // level, so don't use it then either.
8992         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)
8993         {
8994                 R_Mesh_ResetTextureState();
8995                 if (skyrendermasked)
8996                 {
8997                         R_SetupShader_DepthOrShadow(false, false, false);
8998                         // depth-only (masking)
8999                         GL_ColorMask(0, 0, 0, 0);
9000                         // just to make sure that braindead drivers don't draw
9001                         // anything despite that colormask...
9002                         GL_BlendFunc(GL_ZERO, GL_ONE);
9003                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9004                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9005                 }
9006                 else
9007                 {
9008                         R_SetupShader_Generic_NoTexture(false, false);
9009                         // fog sky
9010                         GL_BlendFunc(GL_ONE, GL_ZERO);
9011                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9012                         GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
9013                         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9014                 }
9015                 RSurf_DrawBatch();
9016                 if (skyrendermasked)
9017                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
9018         }
9019         R_Mesh_ResetTextureState();
9020         GL_Color(1, 1, 1, 1);
9021 }
9022
9023 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
9024 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
9025 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
9026 {
9027         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
9028                 return;
9029         if (prepass)
9030         {
9031                 // render screenspace normalmap to texture
9032                 GL_DepthMask(true);
9033                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false);
9034                 RSurf_DrawBatch();
9035                 return;
9036         }
9037
9038         // bind lightmap texture
9039
9040         // water/refraction/reflection/camera surfaces have to be handled specially
9041         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)))
9042         {
9043                 int start, end, startplaneindex;
9044                 for (start = 0;start < texturenumsurfaces;start = end)
9045                 {
9046                         startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]);
9047                         if(startplaneindex < 0)
9048                         {
9049                                 // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this.
9050                                 // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags);
9051                                 end = start + 1;
9052                                 continue;
9053                         }
9054                         for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++)
9055                                 ;
9056                         // now that we have a batch using the same planeindex, render it
9057                         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)))
9058                         {
9059                                 // render water or distortion background
9060                                 GL_DepthMask(true);
9061                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
9062                                 RSurf_DrawBatch();
9063                                 // blend surface on top
9064                                 GL_DepthMask(false);
9065                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false);
9066                                 RSurf_DrawBatch();
9067                         }
9068                         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
9069                         {
9070                                 // render surface with reflection texture as input
9071                                 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
9072                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
9073                                 RSurf_DrawBatch();
9074                         }
9075                 }
9076                 return;
9077         }
9078
9079         // render surface batch normally
9080         GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
9081         R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0);
9082         RSurf_DrawBatch();
9083 }
9084
9085 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
9086 {
9087         int vi;
9088         int j;
9089         r_vertexgeneric_t *batchvertex;
9090         float c[4];
9091         texture_t *t = rsurface.texture;
9092
9093 //      R_Mesh_ResetTextureState();
9094         R_SetupShader_Generic_NoTexture(false, false);
9095
9096         if(t && t->currentskinframe)
9097         {
9098                 memcpy(c, t->currentskinframe->avgcolor, sizeof(c));
9099                 c[3] *= t->currentalpha;
9100         }
9101         else
9102         {
9103                 c[0] = 1;
9104                 c[1] = 0;
9105                 c[2] = 1;
9106                 c[3] = 1;
9107         }
9108
9109         if (t->pantstexture || t->shirttexture)
9110         {
9111                 c[0] = 0.5 * (t->render_colormap_pants[0] * 0.3 + t->render_colormap_shirt[0] * 0.7);
9112                 c[1] = 0.5 * (t->render_colormap_pants[1] * 0.3 + t->render_colormap_shirt[1] * 0.7);
9113                 c[2] = 0.5 * (t->render_colormap_pants[2] * 0.3 + t->render_colormap_shirt[2] * 0.7);
9114         }
9115
9116         // brighten it up (as texture value 127 means "unlit")
9117         c[0] *= 2 * r_refdef.view.colorscale;
9118         c[1] *= 2 * r_refdef.view.colorscale;
9119         c[2] *= 2 * r_refdef.view.colorscale;
9120
9121         if(t->currentmaterialflags & MATERIALFLAG_WATERALPHA)
9122                 c[3] *= r_wateralpha.value;
9123
9124         if(t->currentmaterialflags & MATERIALFLAG_ALPHA && c[3] != 1)
9125         {
9126                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9127                 GL_DepthMask(false);
9128         }
9129         else if(t->currentmaterialflags & MATERIALFLAG_ADD)
9130         {
9131                 GL_BlendFunc(GL_ONE, GL_ONE);
9132                 GL_DepthMask(false);
9133         }
9134         else if(t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
9135         {
9136                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // can't do alpha test without texture, so let's blend instead
9137                 GL_DepthMask(false);
9138         }
9139         else if(t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
9140         {
9141                 GL_BlendFunc(t->customblendfunc[0], t->customblendfunc[1]);
9142                 GL_DepthMask(false);
9143         }
9144         else
9145         {
9146                 GL_BlendFunc(GL_ONE, GL_ZERO);
9147                 GL_DepthMask(writedepth);
9148         }
9149
9150         if (!r_refdef.view.showdebug)
9151         {
9152                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9153                 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchnumvertices);
9154                 for (j = 0, vi = 0;j < rsurface.batchnumvertices;j++, vi++)
9155                 {
9156                         VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
9157                         Vector4Set(batchvertex[vi].color4f, 0, 0, 0, 1);
9158                 }
9159                 R_Mesh_PrepareVertices_Generic_Unlock();
9160                 RSurf_DrawBatch();
9161         }
9162         else if (r_showsurfaces.integer == 4)
9163         {
9164                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9165                 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchnumvertices);
9166                 for (j = 0, vi = 0;j < rsurface.batchnumvertices;j++, vi++)
9167                 {
9168                         float d = (vi << 3) * (1.0f / 256.0f);
9169                         VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
9170                         Vector4Set(batchvertex[vi].color4f, d, d, d, 1);
9171                 }
9172                 R_Mesh_PrepareVertices_Generic_Unlock();
9173                 RSurf_DrawBatch();
9174         }
9175         else if (r_showsurfaces.integer == 2)
9176         {
9177                 const int *e;
9178                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9179                 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(3*rsurface.batchnumtriangles);
9180                 for (j = 0, e = rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle;j < rsurface.batchnumtriangles;j++, e += 3)
9181                 {
9182                         float d = ((j + rsurface.batchfirsttriangle) << 3) * (1.0f / 256.0f);
9183                         VectorCopy(rsurface.batchvertex3f + 3*e[0], batchvertex[j*3+0].vertex3f);
9184                         VectorCopy(rsurface.batchvertex3f + 3*e[1], batchvertex[j*3+1].vertex3f);
9185                         VectorCopy(rsurface.batchvertex3f + 3*e[2], batchvertex[j*3+2].vertex3f);
9186                         Vector4Set(batchvertex[j*3+0].color4f, d, d, d, 1);
9187                         Vector4Set(batchvertex[j*3+1].color4f, d, d, d, 1);
9188                         Vector4Set(batchvertex[j*3+2].color4f, d, d, d, 1);
9189                 }
9190                 R_Mesh_PrepareVertices_Generic_Unlock();
9191                 R_Mesh_Draw(0, rsurface.batchnumtriangles*3, 0, rsurface.batchnumtriangles, NULL, NULL, 0, NULL, NULL, 0);
9192         }
9193         else
9194         {
9195                 int texturesurfaceindex;
9196                 int k;
9197                 const msurface_t *surface;
9198                 float surfacecolor4f[4];
9199                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9200                 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchfirstvertex + rsurface.batchnumvertices);
9201                 vi = 0;
9202                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
9203                 {
9204                         surface = texturesurfacelist[texturesurfaceindex];
9205                         k = (int)(((size_t)surface) / sizeof(msurface_t));
9206                         Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
9207                         for (j = 0;j < surface->num_vertices;j++)
9208                         {
9209                                 VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
9210                                 Vector4Copy(surfacecolor4f, batchvertex[vi].color4f);
9211                                 vi++;
9212                         }
9213                 }
9214                 R_Mesh_PrepareVertices_Generic_Unlock();
9215                 RSurf_DrawBatch();
9216         }
9217 }
9218
9219 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
9220 {
9221         CHECKGLERROR
9222         RSurf_SetupDepthAndCulling();
9223         if (r_showsurfaces.integer)
9224         {
9225                 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
9226                 return;
9227         }
9228         switch (vid.renderpath)
9229         {
9230         case RENDERPATH_GL20:
9231         case RENDERPATH_GLES2:
9232                 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
9233                 break;
9234         }
9235         CHECKGLERROR
9236 }
9237
9238 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9239 {
9240         int i, j;
9241         int texturenumsurfaces, endsurface;
9242         texture_t *texture;
9243         const msurface_t *surface;
9244         const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
9245
9246         RSurf_ActiveModelEntity(ent, true, true, false);
9247
9248         if (r_transparentdepthmasking.integer)
9249         {
9250                 qboolean setup = false;
9251                 for (i = 0;i < numsurfaces;i = j)
9252                 {
9253                         j = i + 1;
9254                         surface = rsurface.modelsurfaces + surfacelist[i];
9255                         texture = surface->texture;
9256                         rsurface.texture = R_GetCurrentTexture(texture);
9257                         rsurface.lightmaptexture = NULL;
9258                         rsurface.deluxemaptexture = NULL;
9259                         rsurface.uselightmaptexture = false;
9260                         // scan ahead until we find a different texture
9261                         endsurface = min(i + 1024, numsurfaces);
9262                         texturenumsurfaces = 0;
9263                         texturesurfacelist[texturenumsurfaces++] = surface;
9264                         for (;j < endsurface;j++)
9265                         {
9266                                 surface = rsurface.modelsurfaces + surfacelist[j];
9267                                 if (texture != surface->texture)
9268                                         break;
9269                                 texturesurfacelist[texturenumsurfaces++] = surface;
9270                         }
9271                         if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
9272                                 continue;
9273                         // render the range of surfaces as depth
9274                         if (!setup)
9275                         {
9276                                 setup = true;
9277                                 GL_ColorMask(0,0,0,0);
9278                                 GL_Color(1,1,1,1);
9279                                 GL_DepthTest(true);
9280                                 GL_BlendFunc(GL_ONE, GL_ZERO);
9281                                 GL_DepthMask(true);
9282 //                              R_Mesh_ResetTextureState();
9283                         }
9284                         RSurf_SetupDepthAndCulling();
9285                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9286                         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
9287                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9288                         RSurf_DrawBatch();
9289                 }
9290                 if (setup)
9291                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
9292         }
9293
9294         for (i = 0;i < numsurfaces;i = j)
9295         {
9296                 j = i + 1;
9297                 surface = rsurface.modelsurfaces + surfacelist[i];
9298                 texture = surface->texture;
9299                 rsurface.texture = R_GetCurrentTexture(texture);
9300                 // scan ahead until we find a different texture
9301                 endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
9302                 texturenumsurfaces = 0;
9303                 texturesurfacelist[texturenumsurfaces++] = surface;
9304                 if(FAKELIGHT_ENABLED)
9305                 {
9306                         rsurface.lightmaptexture = NULL;
9307                         rsurface.deluxemaptexture = NULL;
9308                         rsurface.uselightmaptexture = false;
9309                         for (;j < endsurface;j++)
9310                         {
9311                                 surface = rsurface.modelsurfaces + surfacelist[j];
9312                                 if (texture != surface->texture)
9313                                         break;
9314                                 texturesurfacelist[texturenumsurfaces++] = surface;
9315                         }
9316                 }
9317                 else
9318                 {
9319                         rsurface.lightmaptexture = surface->lightmaptexture;
9320                         rsurface.deluxemaptexture = surface->deluxemaptexture;
9321                         rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
9322                         for (;j < endsurface;j++)
9323                         {
9324                                 surface = rsurface.modelsurfaces + surfacelist[j];
9325                                 if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture)
9326                                         break;
9327                                 texturesurfacelist[texturenumsurfaces++] = surface;
9328                         }
9329                 }
9330                 // render the range of surfaces
9331                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false);
9332         }
9333         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
9334 }
9335
9336 static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
9337 {
9338         // transparent surfaces get pushed off into the transparent queue
9339         int surfacelistindex;
9340         const msurface_t *surface;
9341         vec3_t tempcenter, center;
9342         for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
9343         {
9344                 surface = texturesurfacelist[surfacelistindex];
9345                 if (r_transparent_sortsurfacesbynearest.integer)
9346                 {
9347                         tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]);
9348                         tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]);
9349                         tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]);
9350                 }
9351                 else
9352                 {
9353                         tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
9354                         tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
9355                         tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
9356                 }
9357                 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
9358                 if (rsurface.entity->transparent_offset) // transparent offset
9359                 {
9360                         center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset;
9361                         center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset;
9362                         center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset;
9363                 }
9364                 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);
9365         }
9366 }
9367
9368 static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist)
9369 {
9370         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
9371                 return;
9372         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
9373                 return;
9374         RSurf_SetupDepthAndCulling();
9375         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9376         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9377         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
9378         RSurf_DrawBatch();
9379 }
9380
9381 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass)
9382 {
9383         CHECKGLERROR
9384         if (depthonly)
9385                 R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
9386         else if (prepass)
9387         {
9388                 if (!rsurface.texture->currentnumlayers)
9389                         return;
9390                 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
9391                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9392                 else
9393                         R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
9394         }
9395         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3))
9396                 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
9397         else if (!rsurface.texture->currentnumlayers)
9398                 return;
9399         else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
9400         {
9401                 // in the deferred case, transparent surfaces were queued during prepass
9402                 if (!r_shadow_usingdeferredprepass)
9403                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9404         }
9405         else
9406         {
9407                 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
9408                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass);
9409         }
9410         CHECKGLERROR
9411 }
9412
9413 static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass)
9414 {
9415         int i, j;
9416         texture_t *texture;
9417         R_FrameData_SetMark();
9418         // break the surface list down into batches by texture and use of lightmapping
9419         for (i = 0;i < numsurfaces;i = j)
9420         {
9421                 j = i + 1;
9422                 // texture is the base texture pointer, rsurface.texture is the
9423                 // current frame/skin the texture is directing us to use (for example
9424                 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
9425                 // use skin 1 instead)
9426                 texture = surfacelist[i]->texture;
9427                 rsurface.texture = R_GetCurrentTexture(texture);
9428                 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
9429                 {
9430                         // if this texture is not the kind we want, skip ahead to the next one
9431                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9432                                 ;
9433                         continue;
9434                 }
9435                 if(FAKELIGHT_ENABLED || depthonly || prepass)
9436                 {
9437                         rsurface.lightmaptexture = NULL;
9438                         rsurface.deluxemaptexture = NULL;
9439                         rsurface.uselightmaptexture = false;
9440                         // simply scan ahead until we find a different texture or lightmap state
9441                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9442                                 ;
9443                 }
9444                 else
9445                 {
9446                         rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
9447                         rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
9448                         rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
9449                         // simply scan ahead until we find a different texture or lightmap state
9450                         for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
9451                                 ;
9452                 }
9453                 // render the range of surfaces
9454                 R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass);
9455         }
9456         R_FrameData_ReturnToMark();
9457 }
9458
9459 float locboxvertex3f[6*4*3] =
9460 {
9461         1,0,1, 1,0,0, 1,1,0, 1,1,1,
9462         0,1,1, 0,1,0, 0,0,0, 0,0,1,
9463         1,1,1, 1,1,0, 0,1,0, 0,1,1,
9464         0,0,1, 0,0,0, 1,0,0, 1,0,1,
9465         0,0,1, 1,0,1, 1,1,1, 0,1,1,
9466         1,0,0, 0,0,0, 0,1,0, 1,1,0
9467 };
9468
9469 unsigned short locboxelements[6*2*3] =
9470 {
9471          0, 1, 2, 0, 2, 3,
9472          4, 5, 6, 4, 6, 7,
9473          8, 9,10, 8,10,11,
9474         12,13,14, 12,14,15,
9475         16,17,18, 16,18,19,
9476         20,21,22, 20,22,23
9477 };
9478
9479 static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9480 {
9481         int i, j;
9482         cl_locnode_t *loc = (cl_locnode_t *)ent;
9483         vec3_t mins, size;
9484         float vertex3f[6*4*3];
9485         CHECKGLERROR
9486         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9487         GL_DepthMask(false);
9488         GL_DepthRange(0, 1);
9489         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9490         GL_DepthTest(true);
9491         GL_CullFace(GL_NONE);
9492         R_EntityMatrix(&identitymatrix);
9493
9494 //      R_Mesh_ResetTextureState();
9495
9496         i = surfacelist[0];
9497         GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9498                          ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9499                          ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9500                         surfacelist[0] < 0 ? 0.5f : 0.125f);
9501
9502         if (VectorCompare(loc->mins, loc->maxs))
9503         {
9504                 VectorSet(size, 2, 2, 2);
9505                 VectorMA(loc->mins, -0.5f, size, mins);
9506         }
9507         else
9508         {
9509                 VectorCopy(loc->mins, mins);
9510                 VectorSubtract(loc->maxs, loc->mins, size);
9511         }
9512
9513         for (i = 0;i < 6*4*3;)
9514                 for (j = 0;j < 3;j++, i++)
9515                         vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
9516
9517         R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
9518         R_SetupShader_Generic_NoTexture(false, false);
9519         R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
9520 }
9521
9522 void R_DrawLocs(void)
9523 {
9524         int index;
9525         cl_locnode_t *loc, *nearestloc;
9526         vec3_t center;
9527         nearestloc = CL_Locs_FindNearest(cl.movement_origin);
9528         for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
9529         {
9530                 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
9531                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
9532         }
9533 }
9534
9535 void R_DecalSystem_Reset(decalsystem_t *decalsystem)
9536 {
9537         if (decalsystem->decals)
9538                 Mem_Free(decalsystem->decals);
9539         memset(decalsystem, 0, sizeof(*decalsystem));
9540 }
9541
9542 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)
9543 {
9544         tridecal_t *decal;
9545         tridecal_t *decals;
9546         int i;
9547
9548         // expand or initialize the system
9549         if (decalsystem->maxdecals <= decalsystem->numdecals)
9550         {
9551                 decalsystem_t old = *decalsystem;
9552                 qboolean useshortelements;
9553                 decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2);
9554                 useshortelements = decalsystem->maxdecals * 3 <= 65536;
9555                 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)));
9556                 decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals);
9557                 decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12);
9558                 decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6);
9559                 decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
9560                 decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
9561                 if (decalsystem->numdecals)
9562                         memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
9563                 if (old.decals)
9564                         Mem_Free(old.decals);
9565                 for (i = 0;i < decalsystem->maxdecals*3;i++)
9566                         decalsystem->element3i[i] = i;
9567                 if (useshortelements)
9568                         for (i = 0;i < decalsystem->maxdecals*3;i++)
9569                                 decalsystem->element3s[i] = i;
9570         }
9571
9572         // grab a decal and search for another free slot for the next one
9573         decals = decalsystem->decals;
9574         decal = decalsystem->decals + (i = decalsystem->freedecal++);
9575         for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4f[0][3];i++)
9576                 ;
9577         decalsystem->freedecal = i;
9578         if (decalsystem->numdecals <= i)
9579                 decalsystem->numdecals = i + 1;
9580
9581         // initialize the decal
9582         decal->lived = 0;
9583         decal->triangleindex = triangleindex;
9584         decal->surfaceindex = surfaceindex;
9585         decal->decalsequence = decalsequence;
9586         decal->color4f[0][0] = c0[0];
9587         decal->color4f[0][1] = c0[1];
9588         decal->color4f[0][2] = c0[2];
9589         decal->color4f[0][3] = 1;
9590         decal->color4f[1][0] = c1[0];
9591         decal->color4f[1][1] = c1[1];
9592         decal->color4f[1][2] = c1[2];
9593         decal->color4f[1][3] = 1;
9594         decal->color4f[2][0] = c2[0];
9595         decal->color4f[2][1] = c2[1];
9596         decal->color4f[2][2] = c2[2];
9597         decal->color4f[2][3] = 1;
9598         decal->vertex3f[0][0] = v0[0];
9599         decal->vertex3f[0][1] = v0[1];
9600         decal->vertex3f[0][2] = v0[2];
9601         decal->vertex3f[1][0] = v1[0];
9602         decal->vertex3f[1][1] = v1[1];
9603         decal->vertex3f[1][2] = v1[2];
9604         decal->vertex3f[2][0] = v2[0];
9605         decal->vertex3f[2][1] = v2[1];
9606         decal->vertex3f[2][2] = v2[2];
9607         decal->texcoord2f[0][0] = t0[0];
9608         decal->texcoord2f[0][1] = t0[1];
9609         decal->texcoord2f[1][0] = t1[0];
9610         decal->texcoord2f[1][1] = t1[1];
9611         decal->texcoord2f[2][0] = t2[0];
9612         decal->texcoord2f[2][1] = t2[1];
9613         TriangleNormal(v0, v1, v2, decal->plane);
9614         VectorNormalize(decal->plane);
9615         decal->plane[3] = DotProduct(v0, decal->plane);
9616 }
9617
9618 extern cvar_t cl_decals_bias;
9619 extern cvar_t cl_decals_models;
9620 extern cvar_t cl_decals_newsystem_intensitymultiplier;
9621 // baseparms, parms, temps
9622 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)
9623 {
9624         int cornerindex;
9625         int index;
9626         float v[9][3];
9627         const float *vertex3f;
9628         const float *normal3f;
9629         int numpoints;
9630         float points[2][9][3];
9631         float temp[3];
9632         float tc[9][2];
9633         float f;
9634         float c[9][4];
9635         const int *e;
9636
9637         e = rsurface.modelelement3i + 3*triangleindex;
9638
9639         vertex3f = rsurface.modelvertex3f;
9640         normal3f = rsurface.modelnormal3f;
9641
9642         if (normal3f)
9643         {
9644                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9645                 {
9646                         index = 3*e[cornerindex];
9647                         VectorMA(vertex3f + index, cl_decals_bias.value, normal3f + index, v[cornerindex]);
9648                 }
9649         }
9650         else
9651         {
9652                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9653                 {
9654                         index = 3*e[cornerindex];
9655                         VectorCopy(vertex3f + index, v[cornerindex]);
9656                 }
9657         }
9658
9659         // cull backfaces
9660         //TriangleNormal(v[0], v[1], v[2], normal);
9661         //if (DotProduct(normal, localnormal) < 0.0f)
9662         //      continue;
9663         // clip by each of the box planes formed from the projection matrix
9664         // if anything survives, we emit the decal
9665         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]);
9666         if (numpoints < 3)
9667                 return;
9668         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]);
9669         if (numpoints < 3)
9670                 return;
9671         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]);
9672         if (numpoints < 3)
9673                 return;
9674         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]);
9675         if (numpoints < 3)
9676                 return;
9677         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]);
9678         if (numpoints < 3)
9679                 return;
9680         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]);
9681         if (numpoints < 3)
9682                 return;
9683         // some part of the triangle survived, so we have to accept it...
9684         if (dynamic)
9685         {
9686                 // dynamic always uses the original triangle
9687                 numpoints = 3;
9688                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9689                 {
9690                         index = 3*e[cornerindex];
9691                         VectorCopy(vertex3f + index, v[cornerindex]);
9692                 }
9693         }
9694         for (cornerindex = 0;cornerindex < numpoints;cornerindex++)
9695         {
9696                 // convert vertex positions to texcoords
9697                 Matrix4x4_Transform(projection, v[cornerindex], temp);
9698                 tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
9699                 tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
9700                 // calculate distance fade from the projection origin
9701                 f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
9702                 f = bound(0.0f, f, 1.0f);
9703                 c[cornerindex][0] = r * f;
9704                 c[cornerindex][1] = g * f;
9705                 c[cornerindex][2] = b * f;
9706                 c[cornerindex][3] = 1.0f;
9707                 //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
9708         }
9709         if (dynamic)
9710                 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);
9711         else
9712                 for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
9713                         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);
9714 }
9715 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)
9716 {
9717         matrix4x4_t projection;
9718         decalsystem_t *decalsystem;
9719         qboolean dynamic;
9720         dp_model_t *model;
9721         const msurface_t *surface;
9722         const msurface_t *surfaces;
9723         const int *surfacelist;
9724         const texture_t *texture;
9725         int numtriangles;
9726         int numsurfacelist;
9727         int surfacelistindex;
9728         int surfaceindex;
9729         int triangleindex;
9730         float localorigin[3];
9731         float localnormal[3];
9732         float localmins[3];
9733         float localmaxs[3];
9734         float localsize;
9735         //float normal[3];
9736         float planes[6][4];
9737         float angles[3];
9738         bih_t *bih;
9739         int bih_triangles_count;
9740         int bih_triangles[256];
9741         int bih_surfaces[256];
9742
9743         decalsystem = &ent->decalsystem;
9744         model = ent->model;
9745         if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST)))
9746         {
9747                 R_DecalSystem_Reset(&ent->decalsystem);
9748                 return;
9749         }
9750
9751         if (!model->brush.data_leafs && !cl_decals_models.integer)
9752         {
9753                 if (decalsystem->model)
9754                         R_DecalSystem_Reset(decalsystem);
9755                 return;
9756         }
9757
9758         if (decalsystem->model != model)
9759                 R_DecalSystem_Reset(decalsystem);
9760         decalsystem->model = model;
9761
9762         RSurf_ActiveModelEntity(ent, true, false, false);
9763
9764         Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
9765         Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
9766         VectorNormalize(localnormal);
9767         localsize = worldsize*rsurface.inversematrixscale;
9768         localmins[0] = localorigin[0] - localsize;
9769         localmins[1] = localorigin[1] - localsize;
9770         localmins[2] = localorigin[2] - localsize;
9771         localmaxs[0] = localorigin[0] + localsize;
9772         localmaxs[1] = localorigin[1] + localsize;
9773         localmaxs[2] = localorigin[2] + localsize;
9774
9775         //VectorCopy(localnormal, planes[4]);
9776         //VectorVectors(planes[4], planes[2], planes[0]);
9777         AnglesFromVectors(angles, localnormal, NULL, false);
9778         AngleVectors(angles, planes[0], planes[2], planes[4]);
9779         VectorNegate(planes[0], planes[1]);
9780         VectorNegate(planes[2], planes[3]);
9781         VectorNegate(planes[4], planes[5]);
9782         planes[0][3] = DotProduct(planes[0], localorigin) - localsize;
9783         planes[1][3] = DotProduct(planes[1], localorigin) - localsize;
9784         planes[2][3] = DotProduct(planes[2], localorigin) - localsize;
9785         planes[3][3] = DotProduct(planes[3], localorigin) - localsize;
9786         planes[4][3] = DotProduct(planes[4], localorigin) - localsize;
9787         planes[5][3] = DotProduct(planes[5], localorigin) - localsize;
9788
9789 #if 1
9790 // works
9791 {
9792         matrix4x4_t forwardprojection;
9793         Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize);
9794         Matrix4x4_Invert_Simple(&projection, &forwardprojection);
9795 }
9796 #else
9797 // broken
9798 {
9799         float projectionvector[4][3];
9800         VectorScale(planes[0], ilocalsize, projectionvector[0]);
9801         VectorScale(planes[2], ilocalsize, projectionvector[1]);
9802         VectorScale(planes[4], ilocalsize, projectionvector[2]);
9803         projectionvector[0][0] = planes[0][0] * ilocalsize;
9804         projectionvector[0][1] = planes[1][0] * ilocalsize;
9805         projectionvector[0][2] = planes[2][0] * ilocalsize;
9806         projectionvector[1][0] = planes[0][1] * ilocalsize;
9807         projectionvector[1][1] = planes[1][1] * ilocalsize;
9808         projectionvector[1][2] = planes[2][1] * ilocalsize;
9809         projectionvector[2][0] = planes[0][2] * ilocalsize;
9810         projectionvector[2][1] = planes[1][2] * ilocalsize;
9811         projectionvector[2][2] = planes[2][2] * ilocalsize;
9812         projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]);
9813         projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]);
9814         projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]);
9815         Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]);
9816 }
9817 #endif
9818
9819         dynamic = model->surfmesh.isanimated;
9820         numsurfacelist = model->nummodelsurfaces;
9821         surfacelist = model->sortedmodelsurfaces;
9822         surfaces = model->data_surfaces;
9823
9824         bih = NULL;
9825         bih_triangles_count = -1;
9826         if(!dynamic)
9827         {
9828                 if(model->render_bih.numleafs)
9829                         bih = &model->render_bih;
9830                 else if(model->collision_bih.numleafs)
9831                         bih = &model->collision_bih;
9832         }
9833         if(bih)
9834                 bih_triangles_count = BIH_GetTriangleListForBox(bih, sizeof(bih_triangles) / sizeof(*bih_triangles), bih_triangles, bih_surfaces, localmins, localmaxs);
9835         if(bih_triangles_count == 0)
9836                 return;
9837         if(bih_triangles_count > (int) (sizeof(bih_triangles) / sizeof(*bih_triangles))) // hit too many, likely bad anyway
9838                 return;
9839         if(bih_triangles_count > 0)
9840         {
9841                 for (triangleindex = 0; triangleindex < bih_triangles_count; ++triangleindex)
9842                 {
9843                         surfaceindex = bih_surfaces[triangleindex];
9844                         surface = surfaces + surfaceindex;
9845                         texture = surface->texture;
9846                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9847                                 continue;
9848                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9849                                 continue;
9850                         R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, bih_triangles[triangleindex], surfaceindex);
9851                 }
9852         }
9853         else
9854         {
9855                 for (surfacelistindex = 0;surfacelistindex < numsurfacelist;surfacelistindex++)
9856                 {
9857                         surfaceindex = surfacelist[surfacelistindex];
9858                         surface = surfaces + surfaceindex;
9859                         // check cull box first because it rejects more than any other check
9860                         if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
9861                                 continue;
9862                         // skip transparent surfaces
9863                         texture = surface->texture;
9864                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9865                                 continue;
9866                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9867                                 continue;
9868                         numtriangles = surface->num_triangles;
9869                         for (triangleindex = 0; triangleindex < numtriangles; triangleindex++)
9870                                 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, triangleindex + surface->num_firsttriangle, surfaceindex);
9871                 }
9872         }
9873 }
9874
9875 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
9876 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)
9877 {
9878         int renderentityindex;
9879         float worldmins[3];
9880         float worldmaxs[3];
9881         entity_render_t *ent;
9882
9883         if (!cl_decals_newsystem.integer)
9884                 return;
9885
9886         worldmins[0] = worldorigin[0] - worldsize;
9887         worldmins[1] = worldorigin[1] - worldsize;
9888         worldmins[2] = worldorigin[2] - worldsize;
9889         worldmaxs[0] = worldorigin[0] + worldsize;
9890         worldmaxs[1] = worldorigin[1] + worldsize;
9891         worldmaxs[2] = worldorigin[2] + worldsize;
9892
9893         R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9894
9895         for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
9896         {
9897                 ent = r_refdef.scene.entities[renderentityindex];
9898                 if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
9899                         continue;
9900
9901                 R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9902         }
9903 }
9904
9905 typedef struct r_decalsystem_splatqueue_s
9906 {
9907         vec3_t worldorigin;
9908         vec3_t worldnormal;
9909         float color[4];
9910         float tcrange[4];
9911         float worldsize;
9912         unsigned int decalsequence;
9913 }
9914 r_decalsystem_splatqueue_t;
9915
9916 int r_decalsystem_numqueued = 0;
9917 r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
9918
9919 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)
9920 {
9921         r_decalsystem_splatqueue_t *queue;
9922
9923         if (!cl_decals_newsystem.integer || r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
9924                 return;
9925
9926         queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
9927         VectorCopy(worldorigin, queue->worldorigin);
9928         VectorCopy(worldnormal, queue->worldnormal);
9929         Vector4Set(queue->color, r, g, b, a);
9930         Vector4Set(queue->tcrange, s1, t1, s2, t2);
9931         queue->worldsize = worldsize;
9932         queue->decalsequence = cl.decalsequence++;
9933 }
9934
9935 static void R_DecalSystem_ApplySplatEntitiesQueue(void)
9936 {
9937         int i;
9938         r_decalsystem_splatqueue_t *queue;
9939
9940         for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
9941                 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);
9942         r_decalsystem_numqueued = 0;
9943 }
9944
9945 extern cvar_t cl_decals_max;
9946 static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
9947 {
9948         int i;
9949         decalsystem_t *decalsystem = &ent->decalsystem;
9950         int numdecals;
9951         unsigned int killsequence;
9952         tridecal_t *decal;
9953         float frametime;
9954         float lifetime;
9955
9956         if (!decalsystem->numdecals)
9957                 return;
9958
9959         if (r_showsurfaces.integer)
9960                 return;
9961
9962         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9963         {
9964                 R_DecalSystem_Reset(decalsystem);
9965                 return;
9966         }
9967
9968         killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
9969         lifetime = cl_decals_time.value + cl_decals_fadetime.value;
9970
9971         if (decalsystem->lastupdatetime)
9972                 frametime = (r_refdef.scene.time - decalsystem->lastupdatetime);
9973         else
9974                 frametime = 0;
9975         decalsystem->lastupdatetime = r_refdef.scene.time;
9976         numdecals = decalsystem->numdecals;
9977
9978         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9979         {
9980                 if (decal->color4f[0][3])
9981                 {
9982                         decal->lived += frametime;
9983                         if (killsequence > decal->decalsequence || decal->lived >= lifetime)
9984                         {
9985                                 memset(decal, 0, sizeof(*decal));
9986                                 if (decalsystem->freedecal > i)
9987                                         decalsystem->freedecal = i;
9988                         }
9989                 }
9990         }
9991         decal = decalsystem->decals;
9992         while (numdecals > 0 && !decal[numdecals-1].color4f[0][3])
9993                 numdecals--;
9994
9995         // collapse the array by shuffling the tail decals into the gaps
9996         for (;;)
9997         {
9998                 while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4f[0][3])
9999                         decalsystem->freedecal++;
10000                 if (decalsystem->freedecal == numdecals)
10001                         break;
10002                 decal[decalsystem->freedecal] = decal[--numdecals];
10003         }
10004
10005         decalsystem->numdecals = numdecals;
10006
10007         if (numdecals <= 0)
10008         {
10009                 // if there are no decals left, reset decalsystem
10010                 R_DecalSystem_Reset(decalsystem);
10011         }
10012 }
10013
10014 extern skinframe_t *decalskinframe;
10015 static void R_DrawModelDecals_Entity(entity_render_t *ent)
10016 {
10017         int i;
10018         decalsystem_t *decalsystem = &ent->decalsystem;
10019         int numdecals;
10020         tridecal_t *decal;
10021         float faderate;
10022         float alpha;
10023         float *v3f;
10024         float *c4f;
10025         float *t2f;
10026         const int *e;
10027         const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
10028         int numtris = 0;
10029
10030         numdecals = decalsystem->numdecals;
10031         if (!numdecals)
10032                 return;
10033
10034         if (r_showsurfaces.integer)
10035                 return;
10036
10037         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
10038         {
10039                 R_DecalSystem_Reset(decalsystem);
10040                 return;
10041         }
10042
10043         // if the model is static it doesn't matter what value we give for
10044         // wantnormals and wanttangents, so this logic uses only rules applicable
10045         // to a model, knowing that they are meaningless otherwise
10046         RSurf_ActiveModelEntity(ent, false, false, false);
10047
10048         decalsystem->lastupdatetime = r_refdef.scene.time;
10049
10050         faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
10051
10052         // update vertex positions for animated models
10053         v3f = decalsystem->vertex3f;
10054         c4f = decalsystem->color4f;
10055         t2f = decalsystem->texcoord2f;
10056         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
10057         {
10058                 if (!decal->color4f[0][3])
10059                         continue;
10060
10061                 if (surfacevisible && !surfacevisible[decal->surfaceindex])
10062                         continue;
10063
10064                 // skip backfaces
10065                 if (decal->triangleindex < 0 && DotProduct(r_refdef.view.origin, decal->plane) < decal->plane[3])
10066                         continue;
10067
10068                 // update color values for fading decals
10069                 if (decal->lived >= cl_decals_time.value)
10070                         alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
10071                 else
10072                         alpha = 1.0f;
10073
10074                 c4f[ 0] = decal->color4f[0][0] * alpha;
10075                 c4f[ 1] = decal->color4f[0][1] * alpha;
10076                 c4f[ 2] = decal->color4f[0][2] * alpha;
10077                 c4f[ 3] = 1;
10078                 c4f[ 4] = decal->color4f[1][0] * alpha;
10079                 c4f[ 5] = decal->color4f[1][1] * alpha;
10080                 c4f[ 6] = decal->color4f[1][2] * alpha;
10081                 c4f[ 7] = 1;
10082                 c4f[ 8] = decal->color4f[2][0] * alpha;
10083                 c4f[ 9] = decal->color4f[2][1] * alpha;
10084                 c4f[10] = decal->color4f[2][2] * alpha;
10085                 c4f[11] = 1;
10086
10087                 t2f[0] = decal->texcoord2f[0][0];
10088                 t2f[1] = decal->texcoord2f[0][1];
10089                 t2f[2] = decal->texcoord2f[1][0];
10090                 t2f[3] = decal->texcoord2f[1][1];
10091                 t2f[4] = decal->texcoord2f[2][0];
10092                 t2f[5] = decal->texcoord2f[2][1];
10093
10094                 // update vertex positions for animated models
10095                 if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
10096                 {
10097                         e = rsurface.modelelement3i + 3*decal->triangleindex;
10098                         VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f);
10099                         VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3);
10100                         VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6);
10101                 }
10102                 else
10103                 {
10104                         VectorCopy(decal->vertex3f[0], v3f);
10105                         VectorCopy(decal->vertex3f[1], v3f + 3);
10106                         VectorCopy(decal->vertex3f[2], v3f + 6);
10107                 }
10108
10109                 if (r_refdef.fogenabled)
10110                 {
10111                         alpha = RSurf_FogVertex(v3f);
10112                         VectorScale(c4f, alpha, c4f);
10113                         alpha = RSurf_FogVertex(v3f + 3);
10114                         VectorScale(c4f + 4, alpha, c4f + 4);
10115                         alpha = RSurf_FogVertex(v3f + 6);
10116                         VectorScale(c4f + 8, alpha, c4f + 8);
10117                 }
10118
10119                 v3f += 9;
10120                 c4f += 12;
10121                 t2f += 6;
10122                 numtris++;
10123         }
10124
10125         if (numtris > 0)
10126         {
10127                 r_refdef.stats[r_stat_drawndecals] += numtris;
10128
10129                 // now render the decals all at once
10130                 // (this assumes they all use one particle font texture!)
10131                 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);
10132 //              R_Mesh_ResetTextureState();
10133                 R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
10134                 GL_DepthMask(false);
10135                 GL_DepthRange(0, 1);
10136                 GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
10137                 GL_DepthTest(true);
10138                 GL_CullFace(GL_NONE);
10139                 GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
10140                 R_SetupShader_Generic(decalskinframe->base, NULL, GL_MODULATE, 1, false, false, false);
10141                 R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
10142         }
10143 }
10144
10145 static void R_DrawModelDecals(void)
10146 {
10147         int i, numdecals;
10148
10149         // fade faster when there are too many decals
10150         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
10151         for (i = 0;i < r_refdef.scene.numentities;i++)
10152                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
10153
10154         R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
10155         for (i = 0;i < r_refdef.scene.numentities;i++)
10156                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
10157                         R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
10158
10159         R_DecalSystem_ApplySplatEntitiesQueue();
10160
10161         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
10162         for (i = 0;i < r_refdef.scene.numentities;i++)
10163                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
10164
10165         r_refdef.stats[r_stat_totaldecals] += numdecals;
10166
10167         if (r_showsurfaces.integer)
10168                 return;
10169
10170         R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
10171
10172         for (i = 0;i < r_refdef.scene.numentities;i++)
10173         {
10174                 if (!r_refdef.viewcache.entityvisible[i])
10175                         continue;
10176                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
10177                         R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
10178         }
10179 }
10180
10181 extern cvar_t mod_collision_bih;
10182 static void R_DrawDebugModel(void)
10183 {
10184         entity_render_t *ent = rsurface.entity;
10185         int i, j, flagsmask;
10186         const msurface_t *surface;
10187         dp_model_t *model = ent->model;
10188
10189         if (!sv.active  && !cls.demoplayback && ent != r_refdef.scene.worldentity)
10190                 return;
10191
10192         if (r_showoverdraw.value > 0)
10193         {
10194                 float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
10195                 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
10196                 R_SetupShader_Generic_NoTexture(false, false);
10197                 GL_DepthTest(false);
10198                 GL_DepthMask(false);
10199                 GL_DepthRange(0, 1);
10200                 GL_BlendFunc(GL_ONE, GL_ONE);
10201                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
10202                 {
10203                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
10204                                 continue;
10205                         rsurface.texture = R_GetCurrentTexture(surface->texture);
10206                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
10207                         {
10208                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface);
10209                                 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
10210                                 if (!rsurface.texture->currentlayers->depthmask)
10211                                         GL_Color(c, 0, 0, 1.0f);
10212                                 else if (ent == r_refdef.scene.worldentity)
10213                                         GL_Color(c, c, c, 1.0f);
10214                                 else
10215                                         GL_Color(0, c, 0, 1.0f);
10216                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
10217                                 RSurf_DrawBatch();
10218                         }
10219                 }
10220                 rsurface.texture = NULL;
10221         }
10222
10223         flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
10224
10225 //      R_Mesh_ResetTextureState();
10226         R_SetupShader_Generic_NoTexture(false, false);
10227         GL_DepthRange(0, 1);
10228         GL_DepthTest(!r_showdisabledepthtest.integer);
10229         GL_DepthMask(false);
10230         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
10231
10232         if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs)
10233         {
10234                 int triangleindex;
10235                 int bihleafindex;
10236                 qboolean cullbox = false;
10237                 const q3mbrush_t *brush;
10238                 const bih_t *bih = &model->collision_bih;
10239                 const bih_leaf_t *bihleaf;
10240                 float vertex3f[3][3];
10241                 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
10242                 for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
10243                 {
10244                         if (cullbox && R_CullBox(bihleaf->mins, bihleaf->maxs))
10245                                 continue;
10246                         switch (bihleaf->type)
10247                         {
10248                         case BIH_BRUSH:
10249                                 brush = model->brush.data_brushes + bihleaf->itemindex;
10250                                 if (brush->colbrushf && brush->colbrushf->numtriangles)
10251                                 {
10252                                         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);
10253                                         R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL);
10254                                         R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0);
10255                                 }
10256                                 break;
10257                         case BIH_COLLISIONTRIANGLE:
10258                                 triangleindex = bihleaf->itemindex;
10259                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
10260                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
10261                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
10262                                 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);
10263                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
10264                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
10265                                 break;
10266                         case BIH_RENDERTRIANGLE:
10267                                 triangleindex = bihleaf->itemindex;
10268                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
10269                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
10270                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]);
10271                                 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);
10272                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
10273                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
10274                                 break;
10275                         }
10276                 }
10277         }
10278
10279         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
10280
10281 #ifndef USE_GLES2
10282         if (r_showtris.value > 0 && qglPolygonMode)
10283         {
10284                 if (r_showdisabledepthtest.integer)
10285                 {
10286                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
10287                         GL_DepthMask(false);
10288                 }
10289                 else
10290                 {
10291                         GL_BlendFunc(GL_ONE, GL_ZERO);
10292                         GL_DepthMask(true);
10293                 }
10294                 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR
10295                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
10296                 {
10297                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
10298                                 continue;
10299                         rsurface.texture = R_GetCurrentTexture(surface->texture);
10300                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
10301                         {
10302                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
10303                                 if (!rsurface.texture->currentlayers->depthmask)
10304                                         GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value);
10305                                 else if (ent == r_refdef.scene.worldentity)
10306                                         GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
10307                                 else
10308                                         GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
10309                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
10310                                 RSurf_DrawBatch();
10311                         }
10312                 }
10313                 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);CHECKGLERROR
10314                 rsurface.texture = NULL;
10315         }
10316
10317 # if 0
10318         // FIXME!  implement r_shownormals with just triangles
10319         if (r_shownormals.value != 0 && qglBegin)
10320         {
10321                 int l, k;
10322                 vec3_t v;
10323                 if (r_showdisabledepthtest.integer)
10324                 {
10325                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
10326                         GL_DepthMask(false);
10327                 }
10328                 else
10329                 {
10330                         GL_BlendFunc(GL_ONE, GL_ZERO);
10331                         GL_DepthMask(true);
10332                 }
10333                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
10334                 {
10335                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
10336                                 continue;
10337                         rsurface.texture = R_GetCurrentTexture(surface->texture);
10338                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
10339                         {
10340                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
10341                                 qglBegin(GL_LINES);
10342                                 if (r_shownormals.value < 0 && rsurface.batchnormal3f)
10343                                 {
10344                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10345                                         {
10346                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10347                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10348                                                 qglVertex3f(v[0], v[1], v[2]);
10349                                                 VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10350                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10351                                                 qglVertex3f(v[0], v[1], v[2]);
10352                                         }
10353                                 }
10354                                 if (r_shownormals.value > 0 && rsurface.batchsvector3f)
10355                                 {
10356                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10357                                         {
10358                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10359                                                 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
10360                                                 qglVertex3f(v[0], v[1], v[2]);
10361                                                 VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
10362                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10363                                                 qglVertex3f(v[0], v[1], v[2]);
10364                                         }
10365                                 }
10366                                 if (r_shownormals.value > 0 && rsurface.batchtvector3f)
10367                                 {
10368                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10369                                         {
10370                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10371                                                 GL_Color(0, r_refdef.view.colorscale, 0, 1);
10372                                                 qglVertex3f(v[0], v[1], v[2]);
10373                                                 VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
10374                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10375                                                 qglVertex3f(v[0], v[1], v[2]);
10376                                         }
10377                                 }
10378                                 if (r_shownormals.value > 0 && rsurface.batchnormal3f)
10379                                 {
10380                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10381                                         {
10382                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10383                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10384                                                 qglVertex3f(v[0], v[1], v[2]);
10385                                                 VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10386                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10387                                                 qglVertex3f(v[0], v[1], v[2]);
10388                                         }
10389                                 }
10390                                 qglEnd();
10391                                 CHECKGLERROR
10392                         }
10393                 }
10394                 rsurface.texture = NULL;
10395         }
10396 # endif
10397 #endif
10398 }
10399
10400 int r_maxsurfacelist = 0;
10401 const msurface_t **r_surfacelist = NULL;
10402 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass)
10403 {
10404         int i, j, endj, flagsmask;
10405         dp_model_t *model = ent->model;
10406         msurface_t *surfaces;
10407         unsigned char *update;
10408         int numsurfacelist = 0;
10409         if (model == NULL)
10410                 return;
10411
10412         if (r_maxsurfacelist < model->num_surfaces)
10413         {
10414                 r_maxsurfacelist = model->num_surfaces;
10415                 if (r_surfacelist)
10416                         Mem_Free((msurface_t **)r_surfacelist);
10417                 r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
10418         }
10419
10420         if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
10421                 RSurf_ActiveModelEntity(ent, false, false, false);
10422         else if (prepass)
10423                 RSurf_ActiveModelEntity(ent, true, true, true);
10424         else if (depthonly)
10425                 RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
10426         else
10427                 RSurf_ActiveModelEntity(ent, true, true, false);
10428
10429         surfaces = model->data_surfaces;
10430         update = model->brushq1.lightmapupdateflags;
10431
10432         // update light styles
10433         if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0)
10434         {
10435                 model_brush_lightstyleinfo_t *style;
10436                 for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++)
10437                 {
10438                         if (style->value != r_refdef.scene.lightstylevalue[style->style])
10439                         {
10440                                 int *list = style->surfacelist;
10441                                 style->value = r_refdef.scene.lightstylevalue[style->style];
10442                                 for (j = 0;j < style->numsurfaces;j++)
10443                                         update[list[j]] = true;
10444                         }
10445                 }
10446         }
10447
10448         flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
10449
10450         if (debug)
10451         {
10452                 R_DrawDebugModel();
10453                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10454                 return;
10455         }
10456
10457         rsurface.lightmaptexture = NULL;
10458         rsurface.deluxemaptexture = NULL;
10459         rsurface.uselightmaptexture = false;
10460         rsurface.texture = NULL;
10461         rsurface.rtlight = NULL;
10462         numsurfacelist = 0;
10463         // add visible surfaces to draw list
10464         if (ent == r_refdef.scene.worldentity)
10465         {
10466                 // for the world entity, check surfacevisible
10467                 for (i = 0;i < model->nummodelsurfaces;i++)
10468                 {
10469                         j = model->sortedmodelsurfaces[i];
10470                         if (r_refdef.viewcache.world_surfacevisible[j])
10471                                 r_surfacelist[numsurfacelist++] = surfaces + j;
10472                 }
10473         }
10474         else
10475         {
10476                 // add all surfaces
10477                 for (i = 0; i < model->nummodelsurfaces; i++)
10478                         r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i];
10479         }
10480         // don't do anything if there were no surfaces
10481         if (!numsurfacelist)
10482         {
10483                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10484                 return;
10485         }
10486         // update lightmaps if needed
10487         if (update)
10488         {
10489                 int updated = 0;
10490                 for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
10491                 {
10492                         if (update[j])
10493                         {
10494                                 updated++;
10495                                 R_BuildLightMap(ent, surfaces + j);
10496                         }
10497                 }
10498         }
10499
10500         R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass);
10501
10502         // add to stats if desired
10503         if (r_speeds.integer && !skysurfaces && !depthonly)
10504         {
10505                 r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist;
10506                 for (j = 0;j < numsurfacelist;j++)
10507                         r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
10508         }
10509
10510         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10511 }
10512
10513 void R_DebugLine(vec3_t start, vec3_t end)
10514 {
10515         dp_model_t *mod = CL_Mesh_UI();
10516         msurface_t *surf;
10517         int e0, e1, e2, e3;
10518         float offsetx, offsety, x1, y1, x2, y2, width = 1.0f;
10519         float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f, alpha1 = 0.25f;
10520         float r2 = 1.0f, g2 = 1.0f, b2 = 0.0f, alpha2 = 0.25f;
10521         vec4_t w[2], s[2];
10522
10523         // transform to screen coords first
10524         Vector4Set(w[0], start[0], start[1], start[2], 1);
10525         Vector4Set(w[1], end[0], end[1], end[2], 1);
10526         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
10527         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
10528         x1 = s[0][0] * vid_conwidth.value / vid.width;
10529         y1 = (vid.height - s[0][1]) * vid_conheight.value / vid.height;
10530         x2 = s[1][0] * vid_conwidth.value / vid.width;
10531         y2 = (vid.height - s[1][1]) * vid_conheight.value / vid.height;
10532         //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
10533
10534         // add the line to the UI mesh for drawing later
10535
10536         // width is measured in real pixels
10537         if (fabs(x2 - x1) > fabs(y2 - y1))
10538         {
10539                 offsetx = 0;
10540                 offsety = 0.5f * width * vid_conheight.value / vid.height;
10541         }
10542         else
10543         {
10544                 offsetx = 0.5f * width * vid_conwidth.value / vid.width;
10545                 offsety = 0;
10546         }
10547         surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, "white", 0, 0, MATERIALFLAG_VERTEXCOLOR), true);
10548         e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10549         e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10550         e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10551         e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10552         Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
10553         Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
10554
10555 }
10556
10557
10558 void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass)
10559 {
10560         int q;
10561         static texture_t texture;
10562         static msurface_t surface;
10563         const msurface_t *surfacelist = &surface;
10564
10565         // fake enough texture and surface state to render this geometry
10566
10567         texture.update_lastrenderframe = -1; // regenerate this texture
10568         texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
10569         texture.basealpha = 1.0f;
10570         texture.currentskinframe = skinframe;
10571         texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
10572         texture.offsetmapping = OFFSETMAPPING_OFF;
10573         texture.offsetscale = 1;
10574         texture.specularscalemod = 1;
10575         texture.specularpowermod = 1;
10576         texture.transparentsort = TRANSPARENTSORT_DISTANCE;
10577         // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
10578         // JUST GREP FOR "specularscalemod = 1".
10579
10580         for (q = 0; q < 3; q++)
10581         {
10582                 texture.render_glowmod[q] = r_refdef.view.colorscale * r_hdr_glowintensity.value;
10583                 texture.render_modellight_lightdir[q] = q == 2;
10584                 texture.render_modellight_ambient[q] = r_refdef.view.colorscale * r_refdef.scene.ambientintensity;
10585                 texture.render_modellight_diffuse[q] = r_refdef.view.colorscale;
10586                 texture.render_modellight_specular[q] = r_refdef.view.colorscale;
10587                 texture.render_lightmap_ambient[q] = r_refdef.view.colorscale * r_refdef.scene.ambientintensity;
10588                 texture.render_lightmap_diffuse[q] = r_refdef.view.colorscale * r_refdef.scene.lightmapintensity;
10589                 texture.render_lightmap_specular[q] = r_refdef.view.colorscale;
10590                 texture.render_rtlight_diffuse[q] = r_refdef.view.colorscale;
10591                 texture.render_rtlight_specular[q] = r_refdef.view.colorscale;
10592         }
10593         texture.currentalpha = 1.0f;
10594
10595         surface.texture = &texture;
10596         surface.num_triangles = numtriangles;
10597         surface.num_firsttriangle = firsttriangle;
10598         surface.num_vertices = numvertices;
10599         surface.num_firstvertex = firstvertex;
10600
10601         // now render it
10602         rsurface.texture = R_GetCurrentTexture(surface.texture);
10603         rsurface.lightmaptexture = NULL;
10604         rsurface.deluxemaptexture = NULL;
10605         rsurface.uselightmaptexture = false;
10606         R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass);
10607 }
10608
10609 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)
10610 {
10611         static msurface_t surface;
10612         const msurface_t *surfacelist = &surface;
10613
10614         // fake enough texture and surface state to render this geometry
10615         surface.texture = texture;
10616         surface.num_triangles = numtriangles;
10617         surface.num_firsttriangle = firsttriangle;
10618         surface.num_vertices = numvertices;
10619         surface.num_firstvertex = firstvertex;
10620
10621         // now render it
10622         rsurface.texture = R_GetCurrentTexture(surface.texture);
10623         rsurface.lightmaptexture = NULL;
10624         rsurface.deluxemaptexture = NULL;
10625         rsurface.uselightmaptexture = false;
10626         R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass);
10627 }