]> git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rmain.c
Fix multiple bugs with ft2 font loading that were caused by the switch to cachepic...
[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 extern cvar_t gl_picmip;
2282 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2283 {
2284         int j;
2285         unsigned char *pixels;
2286         unsigned char *bumppixels;
2287         unsigned char *basepixels = NULL;
2288         int basepixels_width = 0;
2289         int basepixels_height = 0;
2290         skinframe_t *skinframe;
2291         rtexture_t *ddsbase = NULL;
2292         qboolean ddshasalpha = false;
2293         float ddsavgcolor[4];
2294         char basename[MAX_QPATH];
2295         int miplevel = R_PicmipForFlags(textureflags);
2296         int savemiplevel = miplevel;
2297         int mymiplevel;
2298         char vabuf[1024];
2299
2300         if (cls.state == ca_dedicated)
2301                 return NULL;
2302
2303         // return an existing skinframe if already loaded
2304         // if loading of the first image fails, don't make a new skinframe as it
2305         // would cause all future lookups of this to be missing
2306         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, -1, false);
2307         if (skinframe && skinframe->base)
2308                 return skinframe;
2309
2310         Image_StripImageExtension(name, basename, sizeof(basename));
2311
2312         // check for DDS texture file first
2313         if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false)))
2314         {
2315                 basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel);
2316                 if (basepixels == NULL && fallbacknotexture)
2317                         basepixels = Image_GenerateNoTexture();
2318                 if (basepixels == NULL)
2319                         return NULL;
2320         }
2321
2322         // FIXME handle miplevel
2323
2324         if (developer_loading.integer)
2325                 Con_Printf("loading skin \"%s\"\n", name);
2326
2327         // we've got some pixels to store, so really allocate this new texture now
2328         if (!skinframe)
2329                 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
2330         textureflags &= ~TEXF_FORCE_RELOAD;
2331         skinframe->stain = NULL;
2332         skinframe->merged = NULL;
2333         skinframe->base = NULL;
2334         skinframe->pants = NULL;
2335         skinframe->shirt = NULL;
2336         skinframe->nmap = NULL;
2337         skinframe->gloss = NULL;
2338         skinframe->glow = NULL;
2339         skinframe->fog = NULL;
2340         skinframe->reflect = NULL;
2341         skinframe->hasalpha = false;
2342         // we could store the q2animname here too
2343
2344         if (ddsbase)
2345         {
2346                 skinframe->base = ddsbase;
2347                 skinframe->hasalpha = ddshasalpha;
2348                 VectorCopy(ddsavgcolor, skinframe->avgcolor);
2349                 if (r_loadfog && skinframe->hasalpha)
2350                         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);
2351                 //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]);
2352         }
2353         else
2354         {
2355                 basepixels_width = image_width;
2356                 basepixels_height = image_height;
2357                 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);
2358                 if (textureflags & TEXF_ALPHA)
2359                 {
2360                         for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
2361                         {
2362                                 if (basepixels[j] < 255)
2363                                 {
2364                                         skinframe->hasalpha = true;
2365                                         break;
2366                                 }
2367                         }
2368                         if (r_loadfog && skinframe->hasalpha)
2369                         {
2370                                 // has transparent pixels
2371                                 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2372                                 for (j = 0;j < image_width * image_height * 4;j += 4)
2373                                 {
2374                                         pixels[j+0] = 255;
2375                                         pixels[j+1] = 255;
2376                                         pixels[j+2] = 255;
2377                                         pixels[j+3] = basepixels[j+3];
2378                                 }
2379                                 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);
2380                                 Mem_Free(pixels);
2381                         }
2382                 }
2383                 R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
2384 #ifndef USE_GLES2
2385                 //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]);
2386                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->base)
2387                         R_SaveTextureDDSFile(skinframe->base, va(vabuf, sizeof(vabuf), "dds/%s.dds", skinframe->basename), r_texture_dds_save.integer < 2, skinframe->hasalpha);
2388                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->fog)
2389                         R_SaveTextureDDSFile(skinframe->fog, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2390 #endif
2391         }
2392
2393         if (r_loaddds)
2394         {
2395                 mymiplevel = savemiplevel;
2396                 if (r_loadnormalmap)
2397                         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);
2398                 skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2399                 if (r_loadgloss)
2400                         skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2401                 skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2402                 skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2403                 skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2404         }
2405
2406         // _norm is the name used by tenebrae and has been adopted as standard
2407         if (r_loadnormalmap && skinframe->nmap == NULL)
2408         {
2409                 mymiplevel = savemiplevel;
2410                 if ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2411                 {
2412                         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);
2413                         Mem_Free(pixels);
2414                         pixels = NULL;
2415                 }
2416                 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_bump", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2417                 {
2418                         pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2419                         Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
2420                         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);
2421                         Mem_Free(pixels);
2422                         Mem_Free(bumppixels);
2423                 }
2424                 else if (r_shadow_bumpscale_basetexture.value > 0)
2425                 {
2426                         pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
2427                         Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
2428                         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);
2429                         Mem_Free(pixels);
2430                 }
2431 #ifndef USE_GLES2
2432                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->nmap)
2433                         R_SaveTextureDDSFile(skinframe->nmap, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2434 #endif
2435         }
2436
2437         // _luma is supported only for tenebrae compatibility
2438         // _glow is the preferred name
2439         mymiplevel = savemiplevel;
2440         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))))
2441         {
2442                 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);
2443 #ifndef USE_GLES2
2444                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->glow)
2445                         R_SaveTextureDDSFile(skinframe->glow, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2446 #endif
2447                 Mem_Free(pixels);pixels = NULL;
2448         }
2449
2450         mymiplevel = savemiplevel;
2451         if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), false, false, false, &mymiplevel)))
2452         {
2453                 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);
2454 #ifndef USE_GLES2
2455                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->gloss)
2456                         R_SaveTextureDDSFile(skinframe->gloss, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2457 #endif
2458                 Mem_Free(pixels);
2459                 pixels = NULL;
2460         }
2461
2462         mymiplevel = savemiplevel;
2463         if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), false, false, false, &mymiplevel)))
2464         {
2465                 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);
2466 #ifndef USE_GLES2
2467                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->pants)
2468                         R_SaveTextureDDSFile(skinframe->pants, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2469 #endif
2470                 Mem_Free(pixels);
2471                 pixels = NULL;
2472         }
2473
2474         mymiplevel = savemiplevel;
2475         if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), false, false, false, &mymiplevel)))
2476         {
2477                 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);
2478 #ifndef USE_GLES2
2479                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->shirt)
2480                         R_SaveTextureDDSFile(skinframe->shirt, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2481 #endif
2482                 Mem_Free(pixels);
2483                 pixels = NULL;
2484         }
2485
2486         mymiplevel = savemiplevel;
2487         if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), false, false, false, &mymiplevel)))
2488         {
2489                 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);
2490 #ifndef USE_GLES2
2491                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->reflect)
2492                         R_SaveTextureDDSFile(skinframe->reflect, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2493 #endif
2494                 Mem_Free(pixels);
2495                 pixels = NULL;
2496         }
2497
2498         if (basepixels)
2499                 Mem_Free(basepixels);
2500
2501         return skinframe;
2502 }
2503
2504 // this is only used by .spr32 sprites, HL .spr files, HL .bsp files
2505 skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height, qboolean sRGB)
2506 {
2507         int i;
2508         skinframe_t *skinframe;
2509         char vabuf[1024];
2510
2511         if (cls.state == ca_dedicated)
2512                 return NULL;
2513
2514         // if already loaded just return it, otherwise make a new skinframe
2515         skinframe = R_SkinFrame_Find(name, textureflags, width, height, (textureflags & TEXF_FORCE_RELOAD) ? -1 : skindata ? CRC_Block(skindata, width*height*4) : 0, true);
2516         if (skinframe->base)
2517                 return skinframe;
2518         textureflags &= ~TEXF_FORCE_RELOAD;
2519
2520         skinframe->stain = NULL;
2521         skinframe->merged = NULL;
2522         skinframe->base = NULL;
2523         skinframe->pants = NULL;
2524         skinframe->shirt = NULL;
2525         skinframe->nmap = NULL;
2526         skinframe->gloss = NULL;
2527         skinframe->glow = NULL;
2528         skinframe->fog = NULL;
2529         skinframe->reflect = NULL;
2530         skinframe->hasalpha = false;
2531
2532         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2533         if (!skindata)
2534                 return NULL;
2535
2536         if (developer_loading.integer)
2537                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2538
2539         if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0)
2540         {
2541                 unsigned char *a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2542                 unsigned char *b = a + width * height * 4;
2543                 Image_HeightmapToNormalmap_BGRA(skindata, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2544                 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);
2545                 Mem_Free(a);
2546         }
2547         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL);
2548         if (textureflags & TEXF_ALPHA)
2549         {
2550                 for (i = 3;i < width * height * 4;i += 4)
2551                 {
2552                         if (skindata[i] < 255)
2553                         {
2554                                 skinframe->hasalpha = true;
2555                                 break;
2556                         }
2557                 }
2558                 if (r_loadfog && skinframe->hasalpha)
2559                 {
2560                         unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
2561                         memcpy(fogpixels, skindata, width * height * 4);
2562                         for (i = 0;i < width * height * 4;i += 4)
2563                                 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
2564                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, textureflags, -1, NULL);
2565                         Mem_Free(fogpixels);
2566                 }
2567         }
2568
2569         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]);
2570         //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]);
2571
2572         return skinframe;
2573 }
2574
2575 skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height)
2576 {
2577         int i;
2578         int featuresmask;
2579         skinframe_t *skinframe;
2580
2581         if (cls.state == ca_dedicated)
2582                 return NULL;
2583
2584         // if already loaded just return it, otherwise make a new skinframe
2585         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2586         if (skinframe->base)
2587                 return skinframe;
2588         //textureflags &= ~TEXF_FORCE_RELOAD;
2589
2590         skinframe->stain = NULL;
2591         skinframe->merged = NULL;
2592         skinframe->base = NULL;
2593         skinframe->pants = NULL;
2594         skinframe->shirt = NULL;
2595         skinframe->nmap = NULL;
2596         skinframe->gloss = NULL;
2597         skinframe->glow = NULL;
2598         skinframe->fog = NULL;
2599         skinframe->reflect = NULL;
2600         skinframe->hasalpha = false;
2601
2602         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2603         if (!skindata)
2604                 return NULL;
2605
2606         if (developer_loading.integer)
2607                 Con_Printf("loading quake skin \"%s\"\n", name);
2608
2609         // 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)
2610         skinframe->qpixels = (unsigned char *)Mem_Alloc(r_main_mempool, width*height); // FIXME LEAK
2611         memcpy(skinframe->qpixels, skindata, width*height);
2612         skinframe->qwidth = width;
2613         skinframe->qheight = height;
2614
2615         featuresmask = 0;
2616         for (i = 0;i < width * height;i++)
2617                 featuresmask |= palette_featureflags[skindata[i]];
2618
2619         skinframe->hasalpha = false;
2620         // fence textures
2621         if (name[0] == '{')
2622                 skinframe->hasalpha = true;
2623         skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT));
2624         skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0;
2625         skinframe->qgeneratemerged = true;
2626         skinframe->qgeneratebase = skinframe->qhascolormapping;
2627         skinframe->qgenerateglow = loadglowtexture && (featuresmask & PALETTEFEATURE_GLOW);
2628
2629         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette_bgra_complete)[skindata[pix]*4 + comp]);
2630         //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]);
2631
2632         return skinframe;
2633 }
2634
2635 static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qboolean colormapped)
2636 {
2637         int width;
2638         int height;
2639         unsigned char *skindata;
2640         char vabuf[1024];
2641
2642         if (!skinframe->qpixels)
2643                 return;
2644
2645         if (!skinframe->qhascolormapping)
2646                 colormapped = false;
2647
2648         if (colormapped)
2649         {
2650                 if (!skinframe->qgeneratebase)
2651                         return;
2652         }
2653         else
2654         {
2655                 if (!skinframe->qgeneratemerged)
2656                         return;
2657         }
2658
2659         width = skinframe->qwidth;
2660         height = skinframe->qheight;
2661         skindata = skinframe->qpixels;
2662
2663         if (skinframe->qgeneratenmap)
2664         {
2665                 unsigned char *a, *b;
2666                 skinframe->qgeneratenmap = false;
2667                 a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2668                 b = a + width * height * 4;
2669                 // use either a custom palette or the quake palette
2670                 Image_Copy8bitBGRA(skindata, a, width * height, palette_bgra_complete);
2671                 Image_HeightmapToNormalmap_BGRA(a, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2672                 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);
2673                 Mem_Free(a);
2674         }
2675
2676         if (skinframe->qgenerateglow)
2677         {
2678                 skinframe->qgenerateglow = false;
2679                 if (skinframe->hasalpha) // fence textures
2680                         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
2681                 else
2682                         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
2683         }
2684
2685         if (colormapped)
2686         {
2687                 skinframe->qgeneratebase = false;
2688                 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);
2689                 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);
2690                 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);
2691         }
2692         else
2693         {
2694                 skinframe->qgeneratemerged = false;
2695                 if (skinframe->hasalpha) // fence textures
2696                         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);
2697                 else
2698                         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);
2699         }
2700
2701         if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase)
2702         {
2703                 Mem_Free(skinframe->qpixels);
2704                 skinframe->qpixels = NULL;
2705         }
2706 }
2707
2708 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)
2709 {
2710         int i;
2711         skinframe_t *skinframe;
2712         char vabuf[1024];
2713
2714         if (cls.state == ca_dedicated)
2715                 return NULL;
2716
2717         // if already loaded just return it, otherwise make a new skinframe
2718         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2719         if (skinframe->base)
2720                 return skinframe;
2721         textureflags &= ~TEXF_FORCE_RELOAD;
2722
2723         skinframe->stain = NULL;
2724         skinframe->merged = NULL;
2725         skinframe->base = NULL;
2726         skinframe->pants = NULL;
2727         skinframe->shirt = NULL;
2728         skinframe->nmap = NULL;
2729         skinframe->gloss = NULL;
2730         skinframe->glow = NULL;
2731         skinframe->fog = NULL;
2732         skinframe->reflect = NULL;
2733         skinframe->hasalpha = false;
2734
2735         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2736         if (!skindata)
2737                 return NULL;
2738
2739         if (developer_loading.integer)
2740                 Con_Printf("loading embedded 8bit image \"%s\"\n", name);
2741
2742         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, palette);
2743         if ((textureflags & TEXF_ALPHA) && alphapalette)
2744         {
2745                 for (i = 0;i < width * height;i++)
2746                 {
2747                         if (((unsigned char *)palette)[skindata[i]*4+3] < 255)
2748                         {
2749                                 skinframe->hasalpha = true;
2750                                 break;
2751                         }
2752                 }
2753                 if (r_loadfog && skinframe->hasalpha)
2754                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, alphapalette);
2755         }
2756
2757         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
2758         //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]);
2759
2760         return skinframe;
2761 }
2762
2763 skinframe_t *R_SkinFrame_LoadMissing(void)
2764 {
2765         skinframe_t *skinframe;
2766
2767         if (cls.state == ca_dedicated)
2768                 return NULL;
2769
2770         skinframe = R_SkinFrame_Find("missing", TEXF_FORCENEAREST, 0, 0, 0, true);
2771         skinframe->stain = NULL;
2772         skinframe->merged = NULL;
2773         skinframe->base = NULL;
2774         skinframe->pants = NULL;
2775         skinframe->shirt = NULL;
2776         skinframe->nmap = NULL;
2777         skinframe->gloss = NULL;
2778         skinframe->glow = NULL;
2779         skinframe->fog = NULL;
2780         skinframe->reflect = NULL;
2781         skinframe->hasalpha = false;
2782
2783         skinframe->avgcolor[0] = rand() / RAND_MAX;
2784         skinframe->avgcolor[1] = rand() / RAND_MAX;
2785         skinframe->avgcolor[2] = rand() / RAND_MAX;
2786         skinframe->avgcolor[3] = 1;
2787
2788         return skinframe;
2789 }
2790
2791 skinframe_t *R_SkinFrame_LoadNoTexture(void)
2792 {
2793         int x, y;
2794         static unsigned char pix[16][16][4];
2795
2796         if (cls.state == ca_dedicated)
2797                 return NULL;
2798
2799         // this makes a light grey/dark grey checkerboard texture
2800         if (!pix[0][0][3])
2801         {
2802                 for (y = 0; y < 16; y++)
2803                 {
2804                         for (x = 0; x < 16; x++)
2805                         {
2806                                 if ((y < 8) ^ (x < 8))
2807                                 {
2808                                         pix[y][x][0] = 128;
2809                                         pix[y][x][1] = 128;
2810                                         pix[y][x][2] = 128;
2811                                         pix[y][x][3] = 255;
2812                                 }
2813                                 else
2814                                 {
2815                                         pix[y][x][0] = 64;
2816                                         pix[y][x][1] = 64;
2817                                         pix[y][x][2] = 64;
2818                                         pix[y][x][3] = 255;
2819                                 }
2820                         }
2821                 }
2822         }
2823
2824         return R_SkinFrame_LoadInternalBGRA("notexture", TEXF_FORCENEAREST, pix[0][0], 16, 16, false);
2825 }
2826
2827 skinframe_t *R_SkinFrame_LoadInternalUsingTexture(const char *name, int textureflags, rtexture_t *tex, int width, int height, qboolean sRGB)
2828 {
2829         skinframe_t *skinframe;
2830         if (cls.state == ca_dedicated)
2831                 return NULL;
2832         // if already loaded just return it, otherwise make a new skinframe
2833         skinframe = R_SkinFrame_Find(name, textureflags, width, height, (textureflags & TEXF_FORCE_RELOAD) ? -1 : 0, true);
2834         if (skinframe->base)
2835                 return skinframe;
2836         textureflags &= ~TEXF_FORCE_RELOAD;
2837         skinframe->stain = NULL;
2838         skinframe->merged = NULL;
2839         skinframe->base = NULL;
2840         skinframe->pants = NULL;
2841         skinframe->shirt = NULL;
2842         skinframe->nmap = NULL;
2843         skinframe->gloss = NULL;
2844         skinframe->glow = NULL;
2845         skinframe->fog = NULL;
2846         skinframe->reflect = NULL;
2847         skinframe->hasalpha = (textureflags & TEXF_ALPHA) != 0;
2848         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2849         if (!tex)
2850                 return NULL;
2851         if (developer_loading.integer)
2852                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2853         skinframe->base = skinframe->merged = tex;
2854         Vector4Set(skinframe->avgcolor, 1, 1, 1, 1); // bogus placeholder
2855         return skinframe;
2856 }
2857
2858 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2859 typedef struct suffixinfo_s
2860 {
2861         const char *suffix;
2862         qboolean flipx, flipy, flipdiagonal;
2863 }
2864 suffixinfo_t;
2865 static suffixinfo_t suffix[3][6] =
2866 {
2867         {
2868                 {"px",   false, false, false},
2869                 {"nx",   false, false, false},
2870                 {"py",   false, false, false},
2871                 {"ny",   false, false, false},
2872                 {"pz",   false, false, false},
2873                 {"nz",   false, false, false}
2874         },
2875         {
2876                 {"posx", false, false, false},
2877                 {"negx", false, false, false},
2878                 {"posy", false, false, false},
2879                 {"negy", false, false, false},
2880                 {"posz", false, false, false},
2881                 {"negz", false, false, false}
2882         },
2883         {
2884                 {"rt",    true, false,  true},
2885                 {"lf",   false,  true,  true},
2886                 {"ft",    true,  true, false},
2887                 {"bk",   false, false, false},
2888                 {"up",    true, false,  true},
2889                 {"dn",    true, false,  true}
2890         }
2891 };
2892
2893 static int componentorder[4] = {0, 1, 2, 3};
2894
2895 static rtexture_t *R_LoadCubemap(const char *basename)
2896 {
2897         int i, j, cubemapsize;
2898         unsigned char *cubemappixels, *image_buffer;
2899         rtexture_t *cubemaptexture;
2900         char name[256];
2901         // must start 0 so the first loadimagepixels has no requested width/height
2902         cubemapsize = 0;
2903         cubemappixels = NULL;
2904         cubemaptexture = NULL;
2905         // keep trying different suffix groups (posx, px, rt) until one loads
2906         for (j = 0;j < 3 && !cubemappixels;j++)
2907         {
2908                 // load the 6 images in the suffix group
2909                 for (i = 0;i < 6;i++)
2910                 {
2911                         // generate an image name based on the base and and suffix
2912                         dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2913                         // load it
2914                         if ((image_buffer = loadimagepixelsbgra(name, false, false, false, NULL)))
2915                         {
2916                                 // an image loaded, make sure width and height are equal
2917                                 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
2918                                 {
2919                                         // if this is the first image to load successfully, allocate the cubemap memory
2920                                         if (!cubemappixels && image_width >= 1)
2921                                         {
2922                                                 cubemapsize = image_width;
2923                                                 // note this clears to black, so unavailable sides are black
2924                                                 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2925                                         }
2926                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2927                                         if (cubemappixels)
2928                                                 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);
2929                                 }
2930                                 else
2931                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2932                                 // free the image
2933                                 Mem_Free(image_buffer);
2934                         }
2935                 }
2936         }
2937         // if a cubemap loaded, upload it
2938         if (cubemappixels)
2939         {
2940                 if (developer_loading.integer)
2941                         Con_Printf("loading cubemap \"%s\"\n", basename);
2942
2943                 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);
2944                 Mem_Free(cubemappixels);
2945         }
2946         else
2947         {
2948                 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
2949                 if (developer_loading.integer)
2950                 {
2951                         Con_Printf("(tried tried images ");
2952                         for (j = 0;j < 3;j++)
2953                                 for (i = 0;i < 6;i++)
2954                                         Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2955                         Con_Print(" and was unable to find any of them).\n");
2956                 }
2957         }
2958         return cubemaptexture;
2959 }
2960
2961 rtexture_t *R_GetCubemap(const char *basename)
2962 {
2963         int i;
2964         for (i = 0;i < r_texture_numcubemaps;i++)
2965                 if (r_texture_cubemaps[i] != NULL)
2966                         if (!strcasecmp(r_texture_cubemaps[i]->basename, basename))
2967                                 return r_texture_cubemaps[i]->texture ? r_texture_cubemaps[i]->texture : r_texture_whitecube;
2968         if (i >= MAX_CUBEMAPS || !r_main_mempool)
2969                 return r_texture_whitecube;
2970         r_texture_numcubemaps++;
2971         r_texture_cubemaps[i] = (cubemapinfo_t *)Mem_Alloc(r_main_mempool, sizeof(cubemapinfo_t));
2972         strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename));
2973         r_texture_cubemaps[i]->texture = R_LoadCubemap(r_texture_cubemaps[i]->basename);
2974         return r_texture_cubemaps[i]->texture;
2975 }
2976
2977 static void R_Main_FreeViewCache(void)
2978 {
2979         if (r_refdef.viewcache.entityvisible)
2980                 Mem_Free(r_refdef.viewcache.entityvisible);
2981         if (r_refdef.viewcache.world_pvsbits)
2982                 Mem_Free(r_refdef.viewcache.world_pvsbits);
2983         if (r_refdef.viewcache.world_leafvisible)
2984                 Mem_Free(r_refdef.viewcache.world_leafvisible);
2985         if (r_refdef.viewcache.world_surfacevisible)
2986                 Mem_Free(r_refdef.viewcache.world_surfacevisible);
2987         memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache));
2988 }
2989
2990 static void R_Main_ResizeViewCache(void)
2991 {
2992         int numentities = r_refdef.scene.numentities;
2993         int numclusters = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusters : 1;
2994         int numclusterbytes = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusterbytes : 1;
2995         int numleafs = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_leafs : 1;
2996         int numsurfaces = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->num_surfaces : 1;
2997         if (r_refdef.viewcache.maxentities < numentities)
2998         {
2999                 r_refdef.viewcache.maxentities = numentities;
3000                 if (r_refdef.viewcache.entityvisible)
3001                         Mem_Free(r_refdef.viewcache.entityvisible);
3002                 r_refdef.viewcache.entityvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.maxentities);
3003         }
3004         if (r_refdef.viewcache.world_numclusters != numclusters)
3005         {
3006                 r_refdef.viewcache.world_numclusters = numclusters;
3007                 r_refdef.viewcache.world_numclusterbytes = numclusterbytes;
3008                 if (r_refdef.viewcache.world_pvsbits)
3009                         Mem_Free(r_refdef.viewcache.world_pvsbits);
3010                 r_refdef.viewcache.world_pvsbits = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numclusterbytes);
3011         }
3012         if (r_refdef.viewcache.world_numleafs != numleafs)
3013         {
3014                 r_refdef.viewcache.world_numleafs = numleafs;
3015                 if (r_refdef.viewcache.world_leafvisible)
3016                         Mem_Free(r_refdef.viewcache.world_leafvisible);
3017                 r_refdef.viewcache.world_leafvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numleafs);
3018         }
3019         if (r_refdef.viewcache.world_numsurfaces != numsurfaces)
3020         {
3021                 r_refdef.viewcache.world_numsurfaces = numsurfaces;
3022                 if (r_refdef.viewcache.world_surfacevisible)
3023                         Mem_Free(r_refdef.viewcache.world_surfacevisible);
3024                 r_refdef.viewcache.world_surfacevisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numsurfaces);
3025         }
3026 }
3027
3028 extern rtexture_t *loadingscreentexture;
3029 static void gl_main_start(void)
3030 {
3031         loadingscreentexture = NULL;
3032         r_texture_blanknormalmap = NULL;
3033         r_texture_white = NULL;
3034         r_texture_grey128 = NULL;
3035         r_texture_black = NULL;
3036         r_texture_whitecube = NULL;
3037         r_texture_normalizationcube = NULL;
3038         r_texture_fogattenuation = NULL;
3039         r_texture_fogheighttexture = NULL;
3040         r_texture_gammaramps = NULL;
3041         r_texture_numcubemaps = 0;
3042         r_uniformbufferalignment = 32;
3043
3044         r_loaddds = r_texture_dds_load.integer != 0;
3045         r_savedds = vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer;
3046
3047         switch(vid.renderpath)
3048         {
3049         case RENDERPATH_GL20:
3050         case RENDERPATH_GLES2:
3051                 Cvar_SetValueQuick(&r_textureunits, vid.texunits);
3052                 Cvar_SetValueQuick(&gl_combine, 1);
3053                 Cvar_SetValueQuick(&r_glsl, 1);
3054                 r_loadnormalmap = true;
3055                 r_loadgloss = true;
3056                 r_loadfog = false;
3057 #ifdef GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
3058                 if (vid.support.arb_uniform_buffer_object)
3059                         qglGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &r_uniformbufferalignment);
3060 #endif
3061                         break;
3062         }
3063
3064         R_AnimCache_Free();
3065         R_FrameData_Reset();
3066         R_BufferData_Reset();
3067
3068         r_numqueries = 0;
3069         r_maxqueries = 0;
3070         memset(r_queries, 0, sizeof(r_queries));
3071
3072         r_qwskincache = NULL;
3073         r_qwskincache_size = 0;
3074
3075         // due to caching of texture_t references, the collision cache must be reset
3076         Collision_Cache_Reset(true);
3077
3078         // set up r_skinframe loading system for textures
3079         memset(&r_skinframe, 0, sizeof(r_skinframe));
3080         r_skinframe.loadsequence = 1;
3081         Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
3082
3083         r_main_texturepool = R_AllocTexturePool();
3084         R_BuildBlankTextures();
3085         R_BuildNoTexture();
3086         if (vid.support.arb_texture_cube_map)
3087         {
3088                 R_BuildWhiteCube();
3089                 R_BuildNormalizationCube();
3090         }
3091         r_texture_fogattenuation = NULL;
3092         r_texture_fogheighttexture = NULL;
3093         r_texture_gammaramps = NULL;
3094         //r_texture_fogintensity = NULL;
3095         memset(&r_fb, 0, sizeof(r_fb));
3096         Mem_ExpandableArray_NewArray(&r_fb.rendertargets, r_main_mempool, sizeof(r_rendertarget_t), 128);
3097         r_glsl_permutation = NULL;
3098         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3099         Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256);
3100         memset(&r_svbsp, 0, sizeof (r_svbsp));
3101
3102         memset(r_texture_cubemaps, 0, sizeof(r_texture_cubemaps));
3103         r_texture_numcubemaps = 0;
3104
3105         r_refdef.fogmasktable_density = 0;
3106
3107 #ifdef __ANDROID__
3108         // For Steelstorm Android
3109         // FIXME CACHE the program and reload
3110         // FIXME see possible combinations for SS:BR android
3111         Con_DPrintf("Compiling most used shaders for SS:BR android... START\n");
3112         R_SetupShader_SetPermutationGLSL(0, 12);
3113         R_SetupShader_SetPermutationGLSL(0, 13);
3114         R_SetupShader_SetPermutationGLSL(0, 8388621);
3115         R_SetupShader_SetPermutationGLSL(3, 0);
3116         R_SetupShader_SetPermutationGLSL(3, 2048);
3117         R_SetupShader_SetPermutationGLSL(5, 0);
3118         R_SetupShader_SetPermutationGLSL(5, 2);
3119         R_SetupShader_SetPermutationGLSL(5, 2048);
3120         R_SetupShader_SetPermutationGLSL(5, 8388608);
3121         R_SetupShader_SetPermutationGLSL(11, 1);
3122         R_SetupShader_SetPermutationGLSL(11, 2049);
3123         R_SetupShader_SetPermutationGLSL(11, 8193);
3124         R_SetupShader_SetPermutationGLSL(11, 10241);
3125         Con_DPrintf("Compiling most used shaders for SS:BR android... END\n");
3126 #endif
3127 }
3128
3129 static void gl_main_shutdown(void)
3130 {
3131         R_RenderTarget_FreeUnused(true);
3132         Mem_ExpandableArray_FreeArray(&r_fb.rendertargets);
3133         R_AnimCache_Free();
3134         R_FrameData_Reset();
3135         R_BufferData_Reset();
3136
3137         R_Main_FreeViewCache();
3138
3139         switch(vid.renderpath)
3140         {
3141         case RENDERPATH_GL20:
3142         case RENDERPATH_GLES2:
3143 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
3144                 if (r_maxqueries)
3145                         qglDeleteQueriesARB(r_maxqueries, r_queries);
3146 #endif
3147                 break;
3148         }
3149
3150         r_numqueries = 0;
3151         r_maxqueries = 0;
3152         memset(r_queries, 0, sizeof(r_queries));
3153
3154         r_qwskincache = NULL;
3155         r_qwskincache_size = 0;
3156
3157         // clear out the r_skinframe state
3158         Mem_ExpandableArray_FreeArray(&r_skinframe.array);
3159         memset(&r_skinframe, 0, sizeof(r_skinframe));
3160
3161         if (r_svbsp.nodes)
3162                 Mem_Free(r_svbsp.nodes);
3163         memset(&r_svbsp, 0, sizeof (r_svbsp));
3164         R_FreeTexturePool(&r_main_texturepool);
3165         loadingscreentexture = NULL;
3166         r_texture_blanknormalmap = NULL;
3167         r_texture_white = NULL;
3168         r_texture_grey128 = NULL;
3169         r_texture_black = NULL;
3170         r_texture_whitecube = NULL;
3171         r_texture_normalizationcube = NULL;
3172         r_texture_fogattenuation = NULL;
3173         r_texture_fogheighttexture = NULL;
3174         r_texture_gammaramps = NULL;
3175         r_texture_numcubemaps = 0;
3176         //r_texture_fogintensity = NULL;
3177         memset(&r_fb, 0, sizeof(r_fb));
3178         R_GLSL_Restart_f();
3179
3180         r_glsl_permutation = NULL;
3181         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3182         Mem_ExpandableArray_FreeArray(&r_glsl_permutationarray);
3183 }
3184
3185 static void gl_main_newmap(void)
3186 {
3187         // FIXME: move this code to client
3188         char *entities, entname[MAX_QPATH];
3189         if (r_qwskincache)
3190                 Mem_Free(r_qwskincache);
3191         r_qwskincache = NULL;
3192         r_qwskincache_size = 0;
3193         if (cl.worldmodel)
3194         {
3195                 dpsnprintf(entname, sizeof(entname), "%s.ent", cl.worldnamenoextension);
3196                 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
3197                 {
3198                         CL_ParseEntityLump(entities);
3199                         Mem_Free(entities);
3200                         return;
3201                 }
3202                 if (cl.worldmodel->brush.entities)
3203                         CL_ParseEntityLump(cl.worldmodel->brush.entities);
3204         }
3205         R_Main_FreeViewCache();
3206
3207         R_FrameData_Reset();
3208         R_BufferData_Reset();
3209 }
3210
3211 void GL_Main_Init(void)
3212 {
3213         int i;
3214         r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
3215         R_InitShaderModeInfo();
3216
3217         Cmd_AddCommand("r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
3218         Cmd_AddCommand("r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
3219         // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
3220         if (gamemode == GAME_NEHAHRA)
3221         {
3222                 Cvar_RegisterVariable (&gl_fogenable);
3223                 Cvar_RegisterVariable (&gl_fogdensity);
3224                 Cvar_RegisterVariable (&gl_fogred);
3225                 Cvar_RegisterVariable (&gl_foggreen);
3226                 Cvar_RegisterVariable (&gl_fogblue);
3227                 Cvar_RegisterVariable (&gl_fogstart);
3228                 Cvar_RegisterVariable (&gl_fogend);
3229                 Cvar_RegisterVariable (&gl_skyclip);
3230         }
3231         Cvar_RegisterVariable(&r_motionblur);
3232         Cvar_RegisterVariable(&r_damageblur);
3233         Cvar_RegisterVariable(&r_motionblur_averaging);
3234         Cvar_RegisterVariable(&r_motionblur_randomize);
3235         Cvar_RegisterVariable(&r_motionblur_minblur);
3236         Cvar_RegisterVariable(&r_motionblur_maxblur);
3237         Cvar_RegisterVariable(&r_motionblur_velocityfactor);
3238         Cvar_RegisterVariable(&r_motionblur_velocityfactor_minspeed);
3239         Cvar_RegisterVariable(&r_motionblur_velocityfactor_maxspeed);
3240         Cvar_RegisterVariable(&r_motionblur_mousefactor);
3241         Cvar_RegisterVariable(&r_motionblur_mousefactor_minspeed);
3242         Cvar_RegisterVariable(&r_motionblur_mousefactor_maxspeed);
3243         Cvar_RegisterVariable(&r_equalize_entities_fullbright);
3244         Cvar_RegisterVariable(&r_equalize_entities_minambient);
3245         Cvar_RegisterVariable(&r_equalize_entities_by);
3246         Cvar_RegisterVariable(&r_equalize_entities_to);
3247         Cvar_RegisterVariable(&r_depthfirst);
3248         Cvar_RegisterVariable(&r_useinfinitefarclip);
3249         Cvar_RegisterVariable(&r_farclip_base);
3250         Cvar_RegisterVariable(&r_farclip_world);
3251         Cvar_RegisterVariable(&r_nearclip);
3252         Cvar_RegisterVariable(&r_deformvertexes);
3253         Cvar_RegisterVariable(&r_transparent);
3254         Cvar_RegisterVariable(&r_transparent_alphatocoverage);
3255         Cvar_RegisterVariable(&r_transparent_sortsurfacesbynearest);
3256         Cvar_RegisterVariable(&r_transparent_useplanardistance);
3257         Cvar_RegisterVariable(&r_showoverdraw);
3258         Cvar_RegisterVariable(&r_showbboxes);
3259         Cvar_RegisterVariable(&r_showbboxes_client);
3260         Cvar_RegisterVariable(&r_showsurfaces);
3261         Cvar_RegisterVariable(&r_showtris);
3262         Cvar_RegisterVariable(&r_shownormals);
3263         Cvar_RegisterVariable(&r_showlighting);
3264         Cvar_RegisterVariable(&r_showshadowvolumes);
3265         Cvar_RegisterVariable(&r_showcollisionbrushes);
3266         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
3267         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
3268         Cvar_RegisterVariable(&r_showdisabledepthtest);
3269         Cvar_RegisterVariable(&r_showspriteedges);
3270         Cvar_RegisterVariable(&r_showparticleedges);
3271         Cvar_RegisterVariable(&r_drawportals);
3272         Cvar_RegisterVariable(&r_drawentities);
3273         Cvar_RegisterVariable(&r_draw2d);
3274         Cvar_RegisterVariable(&r_drawworld);
3275         Cvar_RegisterVariable(&r_cullentities_trace);
3276         Cvar_RegisterVariable(&r_cullentities_trace_entityocclusion);
3277         Cvar_RegisterVariable(&r_cullentities_trace_samples);
3278         Cvar_RegisterVariable(&r_cullentities_trace_tempentitysamples);
3279         Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
3280         Cvar_RegisterVariable(&r_cullentities_trace_expand);
3281         Cvar_RegisterVariable(&r_cullentities_trace_pad);
3282         Cvar_RegisterVariable(&r_cullentities_trace_delay);
3283         Cvar_RegisterVariable(&r_cullentities_trace_eyejitter);
3284         Cvar_RegisterVariable(&r_sortentities);
3285         Cvar_RegisterVariable(&r_drawviewmodel);
3286         Cvar_RegisterVariable(&r_drawexteriormodel);
3287         Cvar_RegisterVariable(&r_speeds);
3288         Cvar_RegisterVariable(&r_fullbrights);
3289         Cvar_RegisterVariable(&r_wateralpha);
3290         Cvar_RegisterVariable(&r_dynamic);
3291         Cvar_RegisterVariable(&r_fakelight);
3292         Cvar_RegisterVariable(&r_fakelight_intensity);
3293         Cvar_RegisterVariable(&r_fullbright_directed);
3294         Cvar_RegisterVariable(&r_fullbright_directed_ambient);
3295         Cvar_RegisterVariable(&r_fullbright_directed_diffuse);
3296         Cvar_RegisterVariable(&r_fullbright_directed_pitch);
3297         Cvar_RegisterVariable(&r_fullbright_directed_pitch_relative);
3298         Cvar_RegisterVariable(&r_fullbright);
3299         Cvar_RegisterVariable(&r_shadows);
3300         Cvar_RegisterVariable(&r_shadows_darken);
3301         Cvar_RegisterVariable(&r_shadows_drawafterrtlighting);
3302         Cvar_RegisterVariable(&r_shadows_castfrombmodels);
3303         Cvar_RegisterVariable(&r_shadows_throwdistance);
3304         Cvar_RegisterVariable(&r_shadows_throwdirection);
3305         Cvar_RegisterVariable(&r_shadows_focus);
3306         Cvar_RegisterVariable(&r_shadows_shadowmapscale);
3307         Cvar_RegisterVariable(&r_shadows_shadowmapbias);
3308         Cvar_RegisterVariable(&r_q1bsp_skymasking);
3309         Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
3310         Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
3311         Cvar_RegisterVariable(&r_polygonoffset_decals_factor);
3312         Cvar_RegisterVariable(&r_polygonoffset_decals_offset);
3313         Cvar_RegisterVariable(&r_fog_exp2);
3314         Cvar_RegisterVariable(&r_fog_clear);
3315         Cvar_RegisterVariable(&r_drawfog);
3316         Cvar_RegisterVariable(&r_transparentdepthmasking);
3317         Cvar_RegisterVariable(&r_transparent_sortmindist);
3318         Cvar_RegisterVariable(&r_transparent_sortmaxdist);
3319         Cvar_RegisterVariable(&r_transparent_sortarraysize);
3320         Cvar_RegisterVariable(&r_texture_dds_load);
3321         Cvar_RegisterVariable(&r_texture_dds_save);
3322         Cvar_RegisterVariable(&r_textureunits);
3323         Cvar_RegisterVariable(&gl_combine);
3324         Cvar_RegisterVariable(&r_usedepthtextures);
3325         Cvar_RegisterVariable(&r_viewfbo);
3326         Cvar_RegisterVariable(&r_rendertarget_debug);
3327         Cvar_RegisterVariable(&r_viewscale);
3328         Cvar_RegisterVariable(&r_viewscale_fpsscaling);
3329         Cvar_RegisterVariable(&r_viewscale_fpsscaling_min);
3330         Cvar_RegisterVariable(&r_viewscale_fpsscaling_multiply);
3331         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepsize);
3332         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepmax);
3333         Cvar_RegisterVariable(&r_viewscale_fpsscaling_target);
3334         Cvar_RegisterVariable(&r_glsl);
3335         Cvar_RegisterVariable(&r_glsl_deluxemapping);
3336         Cvar_RegisterVariable(&r_glsl_offsetmapping);
3337         Cvar_RegisterVariable(&r_glsl_offsetmapping_steps);
3338         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
3339         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_steps);
3340         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_refinesteps);
3341         Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
3342         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod);
3343         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod_distance);
3344         Cvar_RegisterVariable(&r_glsl_postprocess);
3345         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1);
3346         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2);
3347         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3);
3348         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4);
3349         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1_enable);
3350         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2_enable);
3351         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3_enable);
3352         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable);
3353         Cvar_RegisterVariable(&r_celshading);
3354         Cvar_RegisterVariable(&r_celoutlines);
3355
3356         Cvar_RegisterVariable(&r_water);
3357         Cvar_RegisterVariable(&r_water_cameraentitiesonly);
3358         Cvar_RegisterVariable(&r_water_resolutionmultiplier);
3359         Cvar_RegisterVariable(&r_water_clippingplanebias);
3360         Cvar_RegisterVariable(&r_water_refractdistort);
3361         Cvar_RegisterVariable(&r_water_reflectdistort);
3362         Cvar_RegisterVariable(&r_water_scissormode);
3363         Cvar_RegisterVariable(&r_water_lowquality);
3364         Cvar_RegisterVariable(&r_water_hideplayer);
3365
3366         Cvar_RegisterVariable(&r_lerpsprites);
3367         Cvar_RegisterVariable(&r_lerpmodels);
3368         Cvar_RegisterVariable(&r_lerplightstyles);
3369         Cvar_RegisterVariable(&r_waterscroll);
3370         Cvar_RegisterVariable(&r_bloom);
3371         Cvar_RegisterVariable(&r_bloom_colorscale);
3372         Cvar_RegisterVariable(&r_bloom_brighten);
3373         Cvar_RegisterVariable(&r_bloom_blur);
3374         Cvar_RegisterVariable(&r_bloom_resolution);
3375         Cvar_RegisterVariable(&r_bloom_colorexponent);
3376         Cvar_RegisterVariable(&r_bloom_colorsubtract);
3377         Cvar_RegisterVariable(&r_bloom_scenebrightness);
3378         Cvar_RegisterVariable(&r_hdr_scenebrightness);
3379         Cvar_RegisterVariable(&r_hdr_glowintensity);
3380         Cvar_RegisterVariable(&r_hdr_irisadaptation);
3381         Cvar_RegisterVariable(&r_hdr_irisadaptation_multiplier);
3382         Cvar_RegisterVariable(&r_hdr_irisadaptation_minvalue);
3383         Cvar_RegisterVariable(&r_hdr_irisadaptation_maxvalue);
3384         Cvar_RegisterVariable(&r_hdr_irisadaptation_value);
3385         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_up);
3386         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_down);
3387         Cvar_RegisterVariable(&r_hdr_irisadaptation_radius);
3388         Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
3389         Cvar_RegisterVariable(&developer_texturelogging);
3390         Cvar_RegisterVariable(&gl_lightmaps);
3391         Cvar_RegisterVariable(&r_test);
3392         Cvar_RegisterVariable(&r_batch_multidraw);
3393         Cvar_RegisterVariable(&r_batch_multidraw_mintriangles);
3394         Cvar_RegisterVariable(&r_batch_debugdynamicvertexpath);
3395         Cvar_RegisterVariable(&r_glsl_skeletal);
3396         Cvar_RegisterVariable(&r_glsl_saturation);
3397         Cvar_RegisterVariable(&r_glsl_saturation_redcompensate);
3398         Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas);
3399         Cvar_RegisterVariable(&r_framedatasize);
3400         for (i = 0;i < R_BUFFERDATA_COUNT;i++)
3401                 Cvar_RegisterVariable(&r_buffermegs[i]);
3402         Cvar_RegisterVariable(&r_batch_dynamicbuffer);
3403         if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
3404                 Cvar_SetValue("r_fullbrights", 0);
3405 #ifdef DP_MOBILETOUCH
3406         // GLES devices have terrible depth precision in general, so...
3407         Cvar_SetValueQuick(&r_nearclip, 4);
3408         Cvar_SetValueQuick(&r_farclip_base, 4096);
3409         Cvar_SetValueQuick(&r_farclip_world, 0);
3410         Cvar_SetValueQuick(&r_useinfinitefarclip, 0);
3411 #endif
3412         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
3413 }
3414
3415 void Render_Init(void)
3416 {
3417         gl_backend_init();
3418         R_Textures_Init();
3419         GL_Main_Init();
3420         Font_Init();
3421         GL_Draw_Init();
3422         R_Shadow_Init();
3423         R_Sky_Init();
3424         GL_Surf_Init();
3425         Sbar_Init();
3426         R_Particles_Init();
3427         R_Explosion_Init();
3428         R_LightningBeams_Init();
3429         Mod_RenderInit();
3430 }
3431
3432 /*
3433 ===============
3434 GL_Init
3435 ===============
3436 */
3437 #ifndef USE_GLES2
3438 extern char *ENGINE_EXTENSIONS;
3439 void GL_Init (void)
3440 {
3441         gl_renderer = (const char *)qglGetString(GL_RENDERER);
3442         gl_vendor = (const char *)qglGetString(GL_VENDOR);
3443         gl_version = (const char *)qglGetString(GL_VERSION);
3444         gl_extensions = (const char *)qglGetString(GL_EXTENSIONS);
3445
3446         if (!gl_extensions)
3447                 gl_extensions = "";
3448         if (!gl_platformextensions)
3449                 gl_platformextensions = "";
3450
3451         Con_Printf("GL_VENDOR: %s\n", gl_vendor);
3452         Con_Printf("GL_RENDERER: %s\n", gl_renderer);
3453         Con_Printf("GL_VERSION: %s\n", gl_version);
3454         Con_DPrintf("GL_EXTENSIONS: %s\n", gl_extensions);
3455         Con_DPrintf("%s_EXTENSIONS: %s\n", gl_platform, gl_platformextensions);
3456
3457         VID_CheckExtensions();
3458
3459         // LordHavoc: report supported extensions
3460 #ifdef CONFIG_MENU
3461         Con_DPrintf("\nQuakeC extensions for server and client: %s\nQuakeC extensions for menu: %s\n", vm_sv_extensions, vm_m_extensions );
3462 #else
3463         Con_DPrintf("\nQuakeC extensions for server and client: %s\n", vm_sv_extensions );
3464 #endif
3465
3466         // clear to black (loading plaque will be seen over this)
3467         GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 128);
3468 }
3469 #endif
3470
3471 int R_CullBox(const vec3_t mins, const vec3_t maxs)
3472 {
3473         int i;
3474         mplane_t *p;
3475         if (r_trippy.integer)
3476                 return false;
3477         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
3478         {
3479                 p = r_refdef.view.frustum + i;
3480                 switch(p->signbits)
3481                 {
3482                 default:
3483                 case 0:
3484                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3485                                 return true;
3486                         break;
3487                 case 1:
3488                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3489                                 return true;
3490                         break;
3491                 case 2:
3492                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3493                                 return true;
3494                         break;
3495                 case 3:
3496                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3497                                 return true;
3498                         break;
3499                 case 4:
3500                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3501                                 return true;
3502                         break;
3503                 case 5:
3504                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3505                                 return true;
3506                         break;
3507                 case 6:
3508                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3509                                 return true;
3510                         break;
3511                 case 7:
3512                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3513                                 return true;
3514                         break;
3515                 }
3516         }
3517         return false;
3518 }
3519
3520 int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
3521 {
3522         int i;
3523         const mplane_t *p;
3524         if (r_trippy.integer)
3525                 return false;
3526         for (i = 0;i < numplanes;i++)
3527         {
3528                 p = planes + i;
3529                 switch(p->signbits)
3530                 {
3531                 default:
3532                 case 0:
3533                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3534                                 return true;
3535                         break;
3536                 case 1:
3537                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3538                                 return true;
3539                         break;
3540                 case 2:
3541                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3542                                 return true;
3543                         break;
3544                 case 3:
3545                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3546                                 return true;
3547                         break;
3548                 case 4:
3549                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3550                                 return true;
3551                         break;
3552                 case 5:
3553                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3554                                 return true;
3555                         break;
3556                 case 6:
3557                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3558                                 return true;
3559                         break;
3560                 case 7:
3561                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3562                                 return true;
3563                         break;
3564                 }
3565         }
3566         return false;
3567 }
3568
3569 //==================================================================================
3570
3571 // LordHavoc: this stores temporary data used within the same frame
3572
3573 typedef struct r_framedata_mem_s
3574 {
3575         struct r_framedata_mem_s *purge; // older mem block to free on next frame
3576         size_t size; // how much usable space
3577         size_t current; // how much space in use
3578         size_t mark; // last "mark" location, temporary memory can be freed by returning to this
3579         size_t wantedsize; // how much space was allocated
3580         unsigned char *data; // start of real data (16byte aligned)
3581 }
3582 r_framedata_mem_t;
3583
3584 static r_framedata_mem_t *r_framedata_mem;
3585
3586 void R_FrameData_Reset(void)
3587 {
3588         while (r_framedata_mem)
3589         {
3590                 r_framedata_mem_t *next = r_framedata_mem->purge;
3591                 Mem_Free(r_framedata_mem);
3592                 r_framedata_mem = next;
3593         }
3594 }
3595
3596 static void R_FrameData_Resize(qboolean mustgrow)
3597 {
3598         size_t wantedsize;
3599         wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
3600         wantedsize = bound(65536, wantedsize, 1000*1024*1024);
3601         if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize || mustgrow)
3602         {
3603                 r_framedata_mem_t *newmem = (r_framedata_mem_t *)Mem_Alloc(r_main_mempool, wantedsize);
3604                 newmem->wantedsize = wantedsize;
3605                 newmem->data = (unsigned char *)(((size_t)(newmem+1) + 15) & ~15);
3606                 newmem->size = (unsigned char *)newmem + wantedsize - newmem->data;
3607                 newmem->current = 0;
3608                 newmem->mark = 0;
3609                 newmem->purge = r_framedata_mem;
3610                 r_framedata_mem = newmem;
3611         }
3612 }
3613
3614 void R_FrameData_NewFrame(void)
3615 {
3616         R_FrameData_Resize(false);
3617         if (!r_framedata_mem)
3618                 return;
3619         // if we ran out of space on the last frame, free the old memory now
3620         while (r_framedata_mem->purge)
3621         {
3622                 // repeatedly remove the second item in the list, leaving only head
3623                 r_framedata_mem_t *next = r_framedata_mem->purge->purge;
3624                 Mem_Free(r_framedata_mem->purge);
3625                 r_framedata_mem->purge = next;
3626         }
3627         // reset the current mem pointer
3628         r_framedata_mem->current = 0;
3629         r_framedata_mem->mark = 0;
3630 }
3631
3632 void *R_FrameData_Alloc(size_t size)
3633 {
3634         void *data;
3635         float newvalue;
3636
3637         // align to 16 byte boundary - the data pointer is already aligned, so we
3638         // only need to ensure the size of every allocation is also aligned
3639         size = (size + 15) & ~15;
3640
3641         while (!r_framedata_mem || r_framedata_mem->current + size > r_framedata_mem->size)
3642         {
3643                 // emergency - we ran out of space, allocate more memory
3644                 // note: this has no upper-bound, we'll fail to allocate memory eventually and just die
3645                 newvalue = r_framedatasize.value * 2.0f;
3646                 // 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
3647                 if (sizeof(size_t) >= 8)
3648                         newvalue = bound(0.25f, newvalue, (float)(1ll << 42));
3649                 else
3650                         newvalue = bound(0.25f, newvalue, (float)(1 << 10));
3651                 // this might not be a growing it, but we'll allocate another buffer every time
3652                 Cvar_SetValueQuick(&r_framedatasize, newvalue);
3653                 R_FrameData_Resize(true);
3654         }
3655
3656         data = r_framedata_mem->data + r_framedata_mem->current;
3657         r_framedata_mem->current += size;
3658
3659         // count the usage for stats
3660         r_refdef.stats[r_stat_framedatacurrent] = max(r_refdef.stats[r_stat_framedatacurrent], (int)r_framedata_mem->current);
3661         r_refdef.stats[r_stat_framedatasize] = max(r_refdef.stats[r_stat_framedatasize], (int)r_framedata_mem->size);
3662
3663         return (void *)data;
3664 }
3665
3666 void *R_FrameData_Store(size_t size, void *data)
3667 {
3668         void *d = R_FrameData_Alloc(size);
3669         if (d && data)
3670                 memcpy(d, data, size);
3671         return d;
3672 }
3673
3674 void R_FrameData_SetMark(void)
3675 {
3676         if (!r_framedata_mem)
3677                 return;
3678         r_framedata_mem->mark = r_framedata_mem->current;
3679 }
3680
3681 void R_FrameData_ReturnToMark(void)
3682 {
3683         if (!r_framedata_mem)
3684                 return;
3685         r_framedata_mem->current = r_framedata_mem->mark;
3686 }
3687
3688 //==================================================================================
3689
3690 // avoid reusing the same buffer objects on consecutive frames
3691 #define R_BUFFERDATA_CYCLE 3
3692
3693 typedef struct r_bufferdata_buffer_s
3694 {
3695         struct r_bufferdata_buffer_s *purge; // older buffer to free on next frame
3696         size_t size; // how much usable space
3697         size_t current; // how much space in use
3698         r_meshbuffer_t *buffer; // the buffer itself
3699 }
3700 r_bufferdata_buffer_t;
3701
3702 static int r_bufferdata_cycle = 0; // incremented and wrapped each frame
3703 static r_bufferdata_buffer_t *r_bufferdata_buffer[R_BUFFERDATA_CYCLE][R_BUFFERDATA_COUNT];
3704
3705 /// frees all dynamic buffers
3706 void R_BufferData_Reset(void)
3707 {
3708         int cycle, type;
3709         r_bufferdata_buffer_t **p, *mem;
3710         for (cycle = 0;cycle < R_BUFFERDATA_CYCLE;cycle++)
3711         {
3712                 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3713                 {
3714                         // free all buffers
3715                         p = &r_bufferdata_buffer[cycle][type];
3716                         while (*p)
3717                         {
3718                                 mem = *p;
3719                                 *p = (*p)->purge;
3720                                 if (mem->buffer)
3721                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3722                                 Mem_Free(mem);
3723                         }
3724                 }
3725         }
3726 }
3727
3728 // resize buffer as needed (this actually makes a new one, the old one will be recycled next frame)
3729 static void R_BufferData_Resize(r_bufferdata_type_t type, qboolean mustgrow, size_t minsize)
3730 {
3731         r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3732         size_t size;
3733         float newvalue = r_buffermegs[type].value;
3734
3735         // increase the cvar if we have to (but only if we already have a mem)
3736         if (mustgrow && mem)
3737                 newvalue *= 2.0f;
3738         newvalue = bound(0.25f, newvalue, 256.0f);
3739         while (newvalue * 1024*1024 < minsize)
3740                 newvalue *= 2.0f;
3741
3742         // clamp the cvar to valid range
3743         newvalue = bound(0.25f, newvalue, 256.0f);
3744         if (r_buffermegs[type].value != newvalue)
3745                 Cvar_SetValueQuick(&r_buffermegs[type], newvalue);
3746
3747         // calculate size in bytes
3748         size = (size_t)(newvalue * 1024*1024);
3749         size = bound(131072, size, 256*1024*1024);
3750
3751         // allocate a new buffer if the size is different (purge old one later)
3752         // or if we were told we must grow the buffer
3753         if (!mem || mem->size != size || mustgrow)
3754         {
3755                 mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem));
3756                 mem->size = size;
3757                 mem->current = 0;
3758                 if (type == R_BUFFERDATA_VERTEX)
3759                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbuffervertex", false, false, true, false);
3760                 else if (type == R_BUFFERDATA_INDEX16)
3761                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex16", true, false, true, true);
3762                 else if (type == R_BUFFERDATA_INDEX32)
3763                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex32", true, false, true, false);
3764                 else if (type == R_BUFFERDATA_UNIFORM)
3765                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferuniform", false, true, true, false);
3766                 mem->purge = r_bufferdata_buffer[r_bufferdata_cycle][type];
3767                 r_bufferdata_buffer[r_bufferdata_cycle][type] = mem;
3768         }
3769 }
3770
3771 void R_BufferData_NewFrame(void)
3772 {
3773         int type;
3774         r_bufferdata_buffer_t **p, *mem;
3775         // cycle to the next frame's buffers
3776         r_bufferdata_cycle = (r_bufferdata_cycle + 1) % R_BUFFERDATA_CYCLE;
3777         // if we ran out of space on the last time we used these buffers, free the old memory now
3778         for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3779         {
3780                 if (r_bufferdata_buffer[r_bufferdata_cycle][type])
3781                 {
3782                         R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072);
3783                         // free all but the head buffer, this is how we recycle obsolete
3784                         // buffers after they are no longer in use
3785                         p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge;
3786                         while (*p)
3787                         {
3788                                 mem = *p;
3789                                 *p = (*p)->purge;
3790                                 if (mem->buffer)
3791                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3792                                 Mem_Free(mem);
3793                         }
3794                         // reset the current offset
3795                         r_bufferdata_buffer[r_bufferdata_cycle][type]->current = 0;
3796                 }
3797         }
3798 }
3799
3800 r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset)
3801 {
3802         r_bufferdata_buffer_t *mem;
3803         int offset = 0;
3804         int padsize;
3805
3806         *returnbufferoffset = 0;
3807
3808         // align size to a byte boundary appropriate for the buffer type, this
3809         // makes all allocations have aligned start offsets
3810         if (type == R_BUFFERDATA_UNIFORM)
3811                 padsize = (datasize + r_uniformbufferalignment - 1) & ~(r_uniformbufferalignment - 1);
3812         else
3813                 padsize = (datasize + 15) & ~15;
3814
3815         // if we ran out of space in this buffer we must allocate a new one
3816         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)
3817                 R_BufferData_Resize(type, true, padsize);
3818
3819         // if the resize did not give us enough memory, fail
3820         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)
3821                 Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
3822
3823         mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3824         offset = (int)mem->current;
3825         mem->current += padsize;
3826
3827         // upload the data to the buffer at the chosen offset
3828         if (offset == 0)
3829                 R_Mesh_UpdateMeshBuffer(mem->buffer, NULL, mem->size, false, 0);
3830         R_Mesh_UpdateMeshBuffer(mem->buffer, data, datasize, true, offset);
3831
3832         // count the usage for stats
3833         r_refdef.stats[r_stat_bufferdatacurrent_vertex + type] = max(r_refdef.stats[r_stat_bufferdatacurrent_vertex + type], (int)mem->current);
3834         r_refdef.stats[r_stat_bufferdatasize_vertex + type] = max(r_refdef.stats[r_stat_bufferdatasize_vertex + type], (int)mem->size);
3835
3836         // return the buffer offset
3837         *returnbufferoffset = offset;
3838
3839         return mem->buffer;
3840 }
3841
3842 //==================================================================================
3843
3844 // LordHavoc: animcache originally written by Echon, rewritten since then
3845
3846 /**
3847  * Animation cache prevents re-generating mesh data for an animated model
3848  * multiple times in one frame for lighting, shadowing, reflections, etc.
3849  */
3850
3851 void R_AnimCache_Free(void)
3852 {
3853 }
3854
3855 void R_AnimCache_ClearCache(void)
3856 {
3857         int i;
3858         entity_render_t *ent;
3859
3860         for (i = 0;i < r_refdef.scene.numentities;i++)
3861         {
3862                 ent = r_refdef.scene.entities[i];
3863                 ent->animcache_vertex3f = NULL;
3864                 ent->animcache_vertex3f_vertexbuffer = NULL;
3865                 ent->animcache_vertex3f_bufferoffset = 0;
3866                 ent->animcache_normal3f = NULL;
3867                 ent->animcache_normal3f_vertexbuffer = NULL;
3868                 ent->animcache_normal3f_bufferoffset = 0;
3869                 ent->animcache_svector3f = NULL;
3870                 ent->animcache_svector3f_vertexbuffer = NULL;
3871                 ent->animcache_svector3f_bufferoffset = 0;
3872                 ent->animcache_tvector3f = NULL;
3873                 ent->animcache_tvector3f_vertexbuffer = NULL;
3874                 ent->animcache_tvector3f_bufferoffset = 0;
3875                 ent->animcache_vertexmesh = NULL;
3876                 ent->animcache_vertexmesh_vertexbuffer = NULL;
3877                 ent->animcache_vertexmesh_bufferoffset = 0;
3878                 ent->animcache_skeletaltransform3x4 = NULL;
3879                 ent->animcache_skeletaltransform3x4buffer = NULL;
3880                 ent->animcache_skeletaltransform3x4offset = 0;
3881                 ent->animcache_skeletaltransform3x4size = 0;
3882         }
3883 }
3884
3885 static void R_AnimCache_UpdateEntityMeshBuffers(entity_render_t *ent, int numvertices)
3886 {
3887         int i;
3888
3889         // check if we need the meshbuffers
3890         if (!vid.useinterleavedarrays)
3891                 return;
3892
3893         if (!ent->animcache_vertexmesh && ent->animcache_normal3f)
3894                 ent->animcache_vertexmesh = (r_vertexmesh_t *)R_FrameData_Alloc(sizeof(r_vertexmesh_t)*numvertices);
3895         // TODO: upload vertexbuffer?
3896         if (ent->animcache_vertexmesh)
3897         {
3898                 r_refdef.stats[r_stat_animcache_vertexmesh_count] += 1;
3899                 r_refdef.stats[r_stat_animcache_vertexmesh_vertices] += numvertices;
3900                 r_refdef.stats[r_stat_animcache_vertexmesh_maxvertices] = max(r_refdef.stats[r_stat_animcache_vertexmesh_maxvertices], numvertices);
3901                 memcpy(ent->animcache_vertexmesh, ent->model->surfmesh.data_vertexmesh, sizeof(r_vertexmesh_t)*numvertices);
3902                 for (i = 0;i < numvertices;i++)
3903                         memcpy(ent->animcache_vertexmesh[i].vertex3f, ent->animcache_vertex3f + 3*i, sizeof(float[3]));
3904                 if (ent->animcache_svector3f)
3905                         for (i = 0;i < numvertices;i++)
3906                                 memcpy(ent->animcache_vertexmesh[i].svector3f, ent->animcache_svector3f + 3*i, sizeof(float[3]));
3907                 if (ent->animcache_tvector3f)
3908                         for (i = 0;i < numvertices;i++)
3909                                 memcpy(ent->animcache_vertexmesh[i].tvector3f, ent->animcache_tvector3f + 3*i, sizeof(float[3]));
3910                 if (ent->animcache_normal3f)
3911                         for (i = 0;i < numvertices;i++)
3912                                 memcpy(ent->animcache_vertexmesh[i].normal3f, ent->animcache_normal3f + 3*i, sizeof(float[3]));
3913         }
3914 }
3915
3916 qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
3917 {
3918         dp_model_t *model = ent->model;
3919         int numvertices;
3920
3921         // see if this ent is worth caching
3922         if (!model || !model->Draw || !model->AnimateVertices)
3923                 return false;
3924         // nothing to cache if it contains no animations and has no skeleton
3925         if (!model->surfmesh.isanimated && !(model->num_bones && ent->skeleton && ent->skeleton->relativetransforms))
3926                 return false;
3927         // see if it is already cached for gpuskeletal
3928         if (ent->animcache_skeletaltransform3x4)
3929                 return false;
3930         // see if it is already cached as a mesh
3931         if (ent->animcache_vertex3f)
3932         {
3933                 // check if we need to add normals or tangents
3934                 if (ent->animcache_normal3f)
3935                         wantnormals = false;
3936                 if (ent->animcache_svector3f)
3937                         wanttangents = false;
3938                 if (!wantnormals && !wanttangents)
3939                         return false;
3940         }
3941
3942         // check which kind of cache we need to generate
3943         if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
3944         {
3945                 // cache the skeleton so the vertex shader can use it
3946                 r_refdef.stats[r_stat_animcache_skeletal_count] += 1;
3947                 r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones;
3948                 r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones);
3949                 ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones);
3950                 Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4); 
3951                 // note: this can fail if the buffer is at the grow limit
3952                 ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones;
3953                 ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset);
3954         }
3955         else if (ent->animcache_vertex3f)
3956         {
3957                 // mesh was already cached but we may need to add normals/tangents
3958                 // (this only happens with multiple views, reflections, cameras, etc)
3959                 if (wantnormals || wanttangents)
3960                 {
3961                         numvertices = model->surfmesh.num_vertices;
3962                         if (wantnormals)
3963                                 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3964                         if (wanttangents)
3965                         {
3966                                 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3967                                 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3968                         }
3969                         model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
3970                         R_AnimCache_UpdateEntityMeshBuffers(ent, model->surfmesh.num_vertices);
3971                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3972                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3973                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3974                 }
3975         }
3976         else
3977         {
3978                 // generate mesh cache
3979                 numvertices = model->surfmesh.num_vertices;
3980                 ent->animcache_vertex3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3981                 if (wantnormals)
3982                         ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3983                 if (wanttangents)
3984                 {
3985                         ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3986                         ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3987                 }
3988                 model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
3989                 R_AnimCache_UpdateEntityMeshBuffers(ent, model->surfmesh.num_vertices);
3990                 if (wantnormals || wanttangents)
3991                 {
3992                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3993                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3994                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3995                 }
3996                 r_refdef.stats[r_stat_animcache_shape_count] += 1;
3997                 r_refdef.stats[r_stat_animcache_shape_vertices] += numvertices;
3998                 r_refdef.stats[r_stat_animcache_shape_maxvertices] = max(r_refdef.stats[r_stat_animcache_shape_maxvertices], numvertices);
3999         }
4000         return true;
4001 }
4002
4003 void R_AnimCache_CacheVisibleEntities(void)
4004 {
4005         int i;
4006
4007         // TODO: thread this
4008         // NOTE: R_PrepareRTLights() also caches entities
4009
4010         for (i = 0;i < r_refdef.scene.numentities;i++)
4011                 if (r_refdef.viewcache.entityvisible[i])
4012                         R_AnimCache_GetEntity(r_refdef.scene.entities[i], true, true);
4013 }
4014
4015 //==================================================================================
4016
4017 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)
4018 {
4019         int i;
4020         vec3_t eyemins, eyemaxs;
4021         vec3_t boxmins, boxmaxs;
4022         vec3_t padmins, padmaxs;
4023         vec3_t start;
4024         vec3_t end;
4025         dp_model_t *model = r_refdef.scene.worldmodel;
4026         static vec3_t positions[] = {
4027                 { 0.5f, 0.5f, 0.5f },
4028                 { 0.0f, 0.0f, 0.0f },
4029                 { 0.0f, 0.0f, 1.0f },
4030                 { 0.0f, 1.0f, 0.0f },
4031                 { 0.0f, 1.0f, 1.0f },
4032                 { 1.0f, 0.0f, 0.0f },
4033                 { 1.0f, 0.0f, 1.0f },
4034                 { 1.0f, 1.0f, 0.0f },
4035                 { 1.0f, 1.0f, 1.0f },
4036         };
4037
4038         // sample count can be set to -1 to skip this logic, for flicker-prone objects
4039         if (numsamples < 0)
4040                 return true;
4041
4042         // view origin is not used for culling in portal/reflection/refraction renders or isometric views
4043         if (!r_refdef.view.usevieworiginculling)
4044                 return true;
4045
4046         if (!r_cullentities_trace_entityocclusion.integer && (!model || !model->brush.TraceLineOfSight))
4047                 return true;
4048
4049         // expand the eye box a little
4050         eyemins[0] = eye[0] - eyejitter;
4051         eyemaxs[0] = eye[0] + eyejitter;
4052         eyemins[1] = eye[1] - eyejitter;
4053         eyemaxs[1] = eye[1] + eyejitter;
4054         eyemins[2] = eye[2] - eyejitter;
4055         eyemaxs[2] = eye[2] + eyejitter;
4056         // expand the box a little
4057         boxmins[0] = (entboxenlarge + 1) * entboxmins[0] - entboxenlarge * entboxmaxs[0] - entboxexpand;
4058         boxmaxs[0] = (entboxenlarge + 1) * entboxmaxs[0] - entboxenlarge * entboxmins[0] + entboxexpand;
4059         boxmins[1] = (entboxenlarge + 1) * entboxmins[1] - entboxenlarge * entboxmaxs[1] - entboxexpand;
4060         boxmaxs[1] = (entboxenlarge + 1) * entboxmaxs[1] - entboxenlarge * entboxmins[1] + entboxexpand;
4061         boxmins[2] = (entboxenlarge + 1) * entboxmins[2] - entboxenlarge * entboxmaxs[2] - entboxexpand;
4062         boxmaxs[2] = (entboxenlarge + 1) * entboxmaxs[2] - entboxenlarge * entboxmins[2] + entboxexpand;
4063         // make an even larger box for the acceptable area
4064         padmins[0] = boxmins[0] - pad;
4065         padmaxs[0] = boxmaxs[0] + pad;
4066         padmins[1] = boxmins[1] - pad;
4067         padmaxs[1] = boxmaxs[1] + pad;
4068         padmins[2] = boxmins[2] - pad;
4069         padmaxs[2] = boxmaxs[2] + pad;
4070
4071         // return true if eye overlaps enlarged box
4072         if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs))
4073                 return true;
4074
4075         // try specific positions in the box first - note that these can be cached
4076         if (r_cullentities_trace_entityocclusion.integer)
4077         {
4078                 for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++)
4079                 {
4080                         VectorCopy(eye, start);
4081                         end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0];
4082                         end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1];
4083                         end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2];
4084                         //trace_t trace = CL_TraceLine(start, end, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, 0.0f, true, false, NULL, true, true);
4085                         trace_t trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
4086                         // not picky - if the trace ended anywhere in the box we're good
4087                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4088                                 return true;
4089                 }
4090         }
4091         else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4092                 return true;
4093
4094         // try various random positions
4095         for (i = 0; i < numsamples; i++)
4096         {
4097                 VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
4098                 VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
4099                 if (r_cullentities_trace_entityocclusion.integer)
4100                 {
4101                         trace_t trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
4102                         // not picky - if the trace ended anywhere in the box we're good
4103                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4104                                 return true;
4105                 }
4106                 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4107                         return true;
4108         }
4109
4110         return false;
4111 }
4112
4113
4114 static void R_View_UpdateEntityVisible (void)
4115 {
4116         int i;
4117         int renderimask;
4118         int samples;
4119         entity_render_t *ent;
4120
4121         if (r_refdef.envmap || r_fb.water.hideplayer)
4122                 renderimask = RENDER_EXTERIORMODEL | RENDER_VIEWMODEL;
4123         else if (chase_active.integer || r_fb.water.renderingscene)
4124                 renderimask = RENDER_VIEWMODEL;
4125         else
4126                 renderimask = RENDER_EXTERIORMODEL;
4127         if (!r_drawviewmodel.integer)
4128                 renderimask |= RENDER_VIEWMODEL;
4129         if (!r_drawexteriormodel.integer)
4130                 renderimask |= RENDER_EXTERIORMODEL;
4131         memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
4132         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
4133         {
4134                 // worldmodel can check visibility
4135                 for (i = 0;i < r_refdef.scene.numentities;i++)
4136                 {
4137                         ent = r_refdef.scene.entities[i];
4138                         if (!(ent->flags & renderimask))
4139                         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)))
4140                         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))
4141                                 r_refdef.viewcache.entityvisible[i] = true;
4142                 }
4143         }
4144         else
4145         {
4146                 // no worldmodel or it can't check visibility
4147                 for (i = 0;i < r_refdef.scene.numentities;i++)
4148                 {
4149                         ent = r_refdef.scene.entities[i];
4150                         if (!(ent->flags & renderimask))
4151                         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)))
4152                                 r_refdef.viewcache.entityvisible[i] = true;
4153                 }
4154         }
4155         if (r_cullentities_trace.integer)
4156         {
4157                 for (i = 0;i < r_refdef.scene.numentities;i++)
4158                 {
4159                         if (!r_refdef.viewcache.entityvisible[i])
4160                                 continue;
4161                         ent = r_refdef.scene.entities[i];
4162                         if (!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
4163                         {
4164                                 samples = ent->last_trace_visibility == 0 ? r_cullentities_trace_tempentitysamples.integer : r_cullentities_trace_samples.integer;
4165                                 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))
4166                                         ent->last_trace_visibility = realtime;
4167                                 if (ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
4168                                         r_refdef.viewcache.entityvisible[i] = 0;
4169                         }
4170                 }
4171         }
4172 }
4173
4174 /// only used if skyrendermasked, and normally returns false
4175 static int R_DrawBrushModelsSky (void)
4176 {
4177         int i, sky;
4178         entity_render_t *ent;
4179
4180         sky = false;
4181         for (i = 0;i < r_refdef.scene.numentities;i++)
4182         {
4183                 if (!r_refdef.viewcache.entityvisible[i])
4184                         continue;
4185                 ent = r_refdef.scene.entities[i];
4186                 if (!ent->model || !ent->model->DrawSky)
4187                         continue;
4188                 ent->model->DrawSky(ent);
4189                 sky = true;
4190         }
4191         return sky;
4192 }
4193
4194 static void R_DrawNoModel(entity_render_t *ent);
4195 static void R_DrawModels(void)
4196 {
4197         int i;
4198         entity_render_t *ent;
4199
4200         for (i = 0;i < r_refdef.scene.numentities;i++)
4201         {
4202                 if (!r_refdef.viewcache.entityvisible[i])
4203                         continue;
4204                 ent = r_refdef.scene.entities[i];
4205                 r_refdef.stats[r_stat_entities]++;
4206                 /*
4207                 if (ent->model && !strncmp(ent->model->name, "models/proto_", 13))
4208                 {
4209                         vec3_t f, l, u, o;
4210                         Matrix4x4_ToVectors(&ent->matrix, f, l, u, o);
4211                         Con_Printf("R_DrawModels\n");
4212                         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]);
4213                         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);
4214                         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);
4215                 }
4216                 */
4217                 if (ent->model && ent->model->Draw != NULL)
4218                         ent->model->Draw(ent);
4219                 else
4220                         R_DrawNoModel(ent);
4221         }
4222 }
4223
4224 static void R_DrawModelsDepth(void)
4225 {
4226         int i;
4227         entity_render_t *ent;
4228
4229         for (i = 0;i < r_refdef.scene.numentities;i++)
4230         {
4231                 if (!r_refdef.viewcache.entityvisible[i])
4232                         continue;
4233                 ent = r_refdef.scene.entities[i];
4234                 if (ent->model && ent->model->DrawDepth != NULL)
4235                         ent->model->DrawDepth(ent);
4236         }
4237 }
4238
4239 static void R_DrawModelsDebug(void)
4240 {
4241         int i;
4242         entity_render_t *ent;
4243
4244         for (i = 0;i < r_refdef.scene.numentities;i++)
4245         {
4246                 if (!r_refdef.viewcache.entityvisible[i])
4247                         continue;
4248                 ent = r_refdef.scene.entities[i];
4249                 if (ent->model && ent->model->DrawDebug != NULL)
4250                         ent->model->DrawDebug(ent);
4251         }
4252 }
4253
4254 static void R_DrawModelsAddWaterPlanes(void)
4255 {
4256         int i;
4257         entity_render_t *ent;
4258
4259         for (i = 0;i < r_refdef.scene.numentities;i++)
4260         {
4261                 if (!r_refdef.viewcache.entityvisible[i])
4262                         continue;
4263                 ent = r_refdef.scene.entities[i];
4264                 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
4265                         ent->model->DrawAddWaterPlanes(ent);
4266         }
4267 }
4268
4269 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}};
4270
4271 void R_HDR_UpdateIrisAdaptation(const vec3_t point)
4272 {
4273         if (r_hdr_irisadaptation.integer)
4274         {
4275                 vec3_t p;
4276                 vec3_t ambient;
4277                 vec3_t diffuse;
4278                 vec3_t diffusenormal;
4279                 vec3_t forward;
4280                 vec_t brightness = 0.0f;
4281                 vec_t goal;
4282                 vec_t current;
4283                 vec_t d;
4284                 int c;
4285                 VectorCopy(r_refdef.view.forward, forward);
4286                 for (c = 0;c < (int)(sizeof(irisvecs)/sizeof(irisvecs[0]));c++)
4287                 {
4288                         p[0] = point[0] + irisvecs[c][0] * r_hdr_irisadaptation_radius.value;
4289                         p[1] = point[1] + irisvecs[c][1] * r_hdr_irisadaptation_radius.value;
4290                         p[2] = point[2] + irisvecs[c][2] * r_hdr_irisadaptation_radius.value;
4291                         R_CompleteLightPoint(ambient, diffuse, diffusenormal, p, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity);
4292                         d = DotProduct(forward, diffusenormal);
4293                         brightness += VectorLength(ambient);
4294                         if (d > 0)
4295                                 brightness += d * VectorLength(diffuse);
4296                 }
4297                 brightness *= 1.0f / c;
4298                 brightness += 0.00001f; // make sure it's never zero
4299                 goal = r_hdr_irisadaptation_multiplier.value / brightness;
4300                 goal = bound(r_hdr_irisadaptation_minvalue.value, goal, r_hdr_irisadaptation_maxvalue.value);
4301                 current = r_hdr_irisadaptation_value.value;
4302                 if (current < goal)
4303                         current = min(current + r_hdr_irisadaptation_fade_up.value * cl.realframetime, goal);
4304                 else if (current > goal)
4305                         current = max(current - r_hdr_irisadaptation_fade_down.value * cl.realframetime, goal);
4306                 if (fabs(r_hdr_irisadaptation_value.value - current) > 0.0001f)
4307                         Cvar_SetValueQuick(&r_hdr_irisadaptation_value, current);
4308         }
4309         else if (r_hdr_irisadaptation_value.value != 1.0f)
4310                 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, 1.0f);
4311 }
4312
4313 static void R_View_SetFrustum(const int *scissor)
4314 {
4315         int i;
4316         double fpx = +1, fnx = -1, fpy = +1, fny = -1;
4317         vec3_t forward, left, up, origin, v;
4318
4319         if(scissor)
4320         {
4321                 // flipped x coordinates (because x points left here)
4322                 fpx =  1.0 - 2.0 * (scissor[0]              - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4323                 fnx =  1.0 - 2.0 * (scissor[0] + scissor[2] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4324                 // non-flipped y coordinates
4325                 fny = -1.0 + 2.0 * (scissor[1]              - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4326                 fpy = -1.0 + 2.0 * (scissor[1] + scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4327         }
4328
4329         // we can't trust r_refdef.view.forward and friends in reflected scenes
4330         Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin);
4331
4332 #if 0
4333         r_refdef.view.frustum[0].normal[0] = 0 - 1.0 / r_refdef.view.frustum_x;
4334         r_refdef.view.frustum[0].normal[1] = 0 - 0;
4335         r_refdef.view.frustum[0].normal[2] = -1 - 0;
4336         r_refdef.view.frustum[1].normal[0] = 0 + 1.0 / r_refdef.view.frustum_x;
4337         r_refdef.view.frustum[1].normal[1] = 0 + 0;
4338         r_refdef.view.frustum[1].normal[2] = -1 + 0;
4339         r_refdef.view.frustum[2].normal[0] = 0 - 0;
4340         r_refdef.view.frustum[2].normal[1] = 0 - 1.0 / r_refdef.view.frustum_y;
4341         r_refdef.view.frustum[2].normal[2] = -1 - 0;
4342         r_refdef.view.frustum[3].normal[0] = 0 + 0;
4343         r_refdef.view.frustum[3].normal[1] = 0 + 1.0 / r_refdef.view.frustum_y;
4344         r_refdef.view.frustum[3].normal[2] = -1 + 0;
4345 #endif
4346
4347 #if 0
4348         zNear = r_refdef.nearclip;
4349         nudge = 1.0 - 1.0 / (1<<23);
4350         r_refdef.view.frustum[4].normal[0] = 0 - 0;
4351         r_refdef.view.frustum[4].normal[1] = 0 - 0;
4352         r_refdef.view.frustum[4].normal[2] = -1 - -nudge;
4353         r_refdef.view.frustum[4].dist = 0 - -2 * zNear * nudge;
4354         r_refdef.view.frustum[5].normal[0] = 0 + 0;
4355         r_refdef.view.frustum[5].normal[1] = 0 + 0;
4356         r_refdef.view.frustum[5].normal[2] = -1 + -nudge;
4357         r_refdef.view.frustum[5].dist = 0 + -2 * zNear * nudge;
4358 #endif
4359
4360
4361
4362 #if 0
4363         r_refdef.view.frustum[0].normal[0] = m[3] - m[0];
4364         r_refdef.view.frustum[0].normal[1] = m[7] - m[4];
4365         r_refdef.view.frustum[0].normal[2] = m[11] - m[8];
4366         r_refdef.view.frustum[0].dist = m[15] - m[12];
4367
4368         r_refdef.view.frustum[1].normal[0] = m[3] + m[0];
4369         r_refdef.view.frustum[1].normal[1] = m[7] + m[4];
4370         r_refdef.view.frustum[1].normal[2] = m[11] + m[8];
4371         r_refdef.view.frustum[1].dist = m[15] + m[12];
4372
4373         r_refdef.view.frustum[2].normal[0] = m[3] - m[1];
4374         r_refdef.view.frustum[2].normal[1] = m[7] - m[5];
4375         r_refdef.view.frustum[2].normal[2] = m[11] - m[9];
4376         r_refdef.view.frustum[2].dist = m[15] - m[13];
4377
4378         r_refdef.view.frustum[3].normal[0] = m[3] + m[1];
4379         r_refdef.view.frustum[3].normal[1] = m[7] + m[5];
4380         r_refdef.view.frustum[3].normal[2] = m[11] + m[9];
4381         r_refdef.view.frustum[3].dist = m[15] + m[13];
4382
4383         r_refdef.view.frustum[4].normal[0] = m[3] - m[2];
4384         r_refdef.view.frustum[4].normal[1] = m[7] - m[6];
4385         r_refdef.view.frustum[4].normal[2] = m[11] - m[10];
4386         r_refdef.view.frustum[4].dist = m[15] - m[14];
4387
4388         r_refdef.view.frustum[5].normal[0] = m[3] + m[2];
4389         r_refdef.view.frustum[5].normal[1] = m[7] + m[6];
4390         r_refdef.view.frustum[5].normal[2] = m[11] + m[10];
4391         r_refdef.view.frustum[5].dist = m[15] + m[14];
4392 #endif
4393
4394         if (r_refdef.view.useperspective)
4395         {
4396                 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
4397                 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]);
4398                 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]);
4399                 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]);
4400                 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]);
4401
4402                 // then the normals from the corners relative to origin
4403                 CrossProduct(r_refdef.view.frustumcorner[2], r_refdef.view.frustumcorner[0], r_refdef.view.frustum[0].normal);
4404                 CrossProduct(r_refdef.view.frustumcorner[1], r_refdef.view.frustumcorner[3], r_refdef.view.frustum[1].normal);
4405                 CrossProduct(r_refdef.view.frustumcorner[0], r_refdef.view.frustumcorner[1], r_refdef.view.frustum[2].normal);
4406                 CrossProduct(r_refdef.view.frustumcorner[3], r_refdef.view.frustumcorner[2], r_refdef.view.frustum[3].normal);
4407
4408                 // in a NORMAL view, forward cross left == up
4409                 // in a REFLECTED view, forward cross left == down
4410                 // so our cross products above need to be adjusted for a left handed coordinate system
4411                 CrossProduct(forward, left, v);
4412                 if(DotProduct(v, up) < 0)
4413                 {
4414                         VectorNegate(r_refdef.view.frustum[0].normal, r_refdef.view.frustum[0].normal);
4415                         VectorNegate(r_refdef.view.frustum[1].normal, r_refdef.view.frustum[1].normal);
4416                         VectorNegate(r_refdef.view.frustum[2].normal, r_refdef.view.frustum[2].normal);
4417                         VectorNegate(r_refdef.view.frustum[3].normal, r_refdef.view.frustum[3].normal);
4418                 }
4419
4420                 // Leaving those out was a mistake, those were in the old code, and they
4421                 // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix
4422                 // I couldn't reproduce it after adding those normalizations. --blub
4423                 VectorNormalize(r_refdef.view.frustum[0].normal);
4424                 VectorNormalize(r_refdef.view.frustum[1].normal);
4425                 VectorNormalize(r_refdef.view.frustum[2].normal);
4426                 VectorNormalize(r_refdef.view.frustum[3].normal);
4427
4428                 // make the corners absolute
4429                 VectorAdd(r_refdef.view.frustumcorner[0], r_refdef.view.origin, r_refdef.view.frustumcorner[0]);
4430                 VectorAdd(r_refdef.view.frustumcorner[1], r_refdef.view.origin, r_refdef.view.frustumcorner[1]);
4431                 VectorAdd(r_refdef.view.frustumcorner[2], r_refdef.view.origin, r_refdef.view.frustumcorner[2]);
4432                 VectorAdd(r_refdef.view.frustumcorner[3], r_refdef.view.origin, r_refdef.view.frustumcorner[3]);
4433
4434                 // one more normal
4435                 VectorCopy(forward, r_refdef.view.frustum[4].normal);
4436
4437                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal);
4438                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal);
4439                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal);
4440                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal);
4441                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip;
4442         }
4443         else
4444         {
4445                 VectorScale(left, -1.0f, r_refdef.view.frustum[0].normal);
4446                 VectorScale(left,  1.0f, r_refdef.view.frustum[1].normal);
4447                 VectorScale(up, -1.0f, r_refdef.view.frustum[2].normal);
4448                 VectorScale(up,  1.0f, r_refdef.view.frustum[3].normal);
4449                 VectorScale(forward, -1.0f, r_refdef.view.frustum[4].normal);
4450                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal) - r_refdef.view.ortho_x;
4451                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal) - r_refdef.view.ortho_x;
4452                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal) - r_refdef.view.ortho_y;
4453                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal) - r_refdef.view.ortho_y;
4454                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) - r_refdef.farclip;
4455         }
4456         r_refdef.view.numfrustumplanes = 5;
4457
4458         if (r_refdef.view.useclipplane)
4459         {
4460                 r_refdef.view.numfrustumplanes = 6;
4461                 r_refdef.view.frustum[5] = r_refdef.view.clipplane;
4462         }
4463
4464         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
4465                 PlaneClassify(r_refdef.view.frustum + i);
4466
4467         // LordHavoc: note to all quake engine coders, Quake had a special case
4468         // for 90 degrees which assumed a square view (wrong), so I removed it,
4469         // Quake2 has it disabled as well.
4470
4471         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
4472         //RotatePointAroundVector( r_refdef.view.frustum[0].normal, up, forward, -(90 - r_refdef.fov_x / 2));
4473         //r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, frustum[0].normal);
4474         //PlaneClassify(&frustum[0]);
4475
4476         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
4477         //RotatePointAroundVector( r_refdef.view.frustum[1].normal, up, forward, (90 - r_refdef.fov_x / 2));
4478         //r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, frustum[1].normal);
4479         //PlaneClassify(&frustum[1]);
4480
4481         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
4482         //RotatePointAroundVector( r_refdef.view.frustum[2].normal, left, forward, -(90 - r_refdef.fov_y / 2));
4483         //r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, frustum[2].normal);
4484         //PlaneClassify(&frustum[2]);
4485
4486         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
4487         //RotatePointAroundVector( r_refdef.view.frustum[3].normal, left, forward, (90 - r_refdef.fov_y / 2));
4488         //r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, frustum[3].normal);
4489         //PlaneClassify(&frustum[3]);
4490
4491         // nearclip plane
4492         //VectorCopy(forward, r_refdef.view.frustum[4].normal);
4493         //r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, frustum[4].normal) + r_nearclip.value;
4494         //PlaneClassify(&frustum[4]);
4495 }
4496
4497 static void R_View_UpdateWithScissor(const int *myscissor)
4498 {
4499         R_Main_ResizeViewCache();
4500         R_View_SetFrustum(myscissor);
4501         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4502         R_View_UpdateEntityVisible();
4503 }
4504
4505 static void R_View_Update(void)
4506 {
4507         R_Main_ResizeViewCache();
4508         R_View_SetFrustum(NULL);
4509         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4510         R_View_UpdateEntityVisible();
4511 }
4512
4513 float viewscalefpsadjusted = 1.0f;
4514
4515 static void R_GetScaledViewSize(int width, int height, int *outwidth, int *outheight)
4516 {
4517         float scale = r_viewscale.value * sqrt(viewscalefpsadjusted);
4518         scale = bound(0.03125f, scale, 1.0f);
4519         *outwidth = (int)ceil(width * scale);
4520         *outheight = (int)ceil(height * scale);
4521 }
4522
4523 void R_SetupView(qboolean allowwaterclippingplane, int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4524 {
4525         const float *customclipplane = NULL;
4526         float plane[4];
4527         int /*rtwidth,*/ rtheight;
4528         if (r_refdef.view.useclipplane && allowwaterclippingplane)
4529         {
4530                 // LadyHavoc: couldn't figure out how to make this approach work the same in DPSOFTRAST
4531                 vec_t dist = r_refdef.view.clipplane.dist - r_water_clippingplanebias.value;
4532                 vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
4533                 if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
4534                         dist = r_refdef.view.clipplane.dist;
4535                 plane[0] = r_refdef.view.clipplane.normal[0];
4536                 plane[1] = r_refdef.view.clipplane.normal[1];
4537                 plane[2] = r_refdef.view.clipplane.normal[2];
4538                 plane[3] = -dist;
4539         }
4540
4541         //rtwidth = viewfbo ? R_TextureWidth(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.width;
4542         rtheight = viewfbo ? R_TextureHeight(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.height;
4543
4544         if (!r_refdef.view.useperspective)
4545                 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);
4546         else if (vid.stencil && r_useinfinitefarclip.integer)
4547                 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);
4548         else
4549                 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);
4550         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4551         R_SetViewport(&r_refdef.view.viewport);
4552 }
4553
4554 void R_EntityMatrix(const matrix4x4_t *matrix)
4555 {
4556         if (gl_modelmatrixchanged || memcmp(matrix, &gl_modelmatrix, sizeof(matrix4x4_t)))
4557         {
4558                 gl_modelmatrixchanged = false;
4559                 gl_modelmatrix = *matrix;
4560                 Matrix4x4_Concat(&gl_modelviewmatrix, &gl_viewmatrix, &gl_modelmatrix);
4561                 Matrix4x4_Concat(&gl_modelviewprojectionmatrix, &gl_projectionmatrix, &gl_modelviewmatrix);
4562                 Matrix4x4_ToArrayFloatGL(&gl_modelviewmatrix, gl_modelview16f);
4563                 Matrix4x4_ToArrayFloatGL(&gl_modelviewprojectionmatrix, gl_modelviewprojection16f);
4564                 CHECKGLERROR
4565                 switch(vid.renderpath)
4566                 {
4567                 case RENDERPATH_GL20:
4568                 case RENDERPATH_GLES2:
4569                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
4570                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
4571                         break;
4572                 }
4573         }
4574 }
4575
4576 void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2)
4577 {
4578         r_viewport_t viewport;
4579
4580         CHECKGLERROR
4581
4582         // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
4583         R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, vid.height - viewheight - viewy, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
4584         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4585         R_SetViewport(&viewport);
4586         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
4587         GL_Color(1, 1, 1, 1);
4588         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4589         GL_BlendFunc(GL_ONE, GL_ZERO);
4590         GL_ScissorTest(false);
4591         GL_DepthMask(false);
4592         GL_DepthRange(0, 1);
4593         GL_DepthTest(false);
4594         GL_DepthFunc(GL_LEQUAL);
4595         R_EntityMatrix(&identitymatrix);
4596         R_Mesh_ResetTextureState();
4597         GL_PolygonOffset(0, 0);
4598         R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
4599         switch(vid.renderpath)
4600         {
4601         case RENDERPATH_GL20:
4602         case RENDERPATH_GLES2:
4603                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4604                 break;
4605         }
4606         GL_CullFace(GL_NONE);
4607
4608         CHECKGLERROR
4609 }
4610
4611 void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4612 {
4613         R_ResetViewRendering2D_Common(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight, 1.0f, 1.0f);
4614 }
4615
4616 void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4617 {
4618         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
4619         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4620         GL_Color(1, 1, 1, 1);
4621         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4622         GL_BlendFunc(GL_ONE, GL_ZERO);
4623         GL_ScissorTest(true);
4624         GL_DepthMask(true);
4625         GL_DepthRange(0, 1);
4626         GL_DepthTest(true);
4627         GL_DepthFunc(GL_LEQUAL);
4628         R_EntityMatrix(&identitymatrix);
4629         R_Mesh_ResetTextureState();
4630         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4631         R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
4632         switch(vid.renderpath)
4633         {
4634         case RENDERPATH_GL20:
4635         case RENDERPATH_GLES2:
4636                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4637                 break;
4638         }
4639         GL_CullFace(r_refdef.view.cullface_back);
4640 }
4641
4642 /*
4643 ================
4644 R_RenderView_UpdateViewVectors
4645 ================
4646 */
4647 void R_RenderView_UpdateViewVectors(void)
4648 {
4649         // break apart the view matrix into vectors for various purposes
4650         // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
4651         // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc
4652         Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
4653         VectorNegate(r_refdef.view.left, r_refdef.view.right);
4654         // make an inverted copy of the view matrix for tracking sprites
4655         Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
4656 }
4657
4658 void R_RenderTarget_FreeUnused(qboolean force)
4659 {
4660         int i, j, end;
4661         end = Mem_ExpandableArray_IndexRange(&r_fb.rendertargets);
4662         for (i = 0; i < end; i++)
4663         {
4664                 r_rendertarget_t *r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4665                 // free resources for rendertargets that have not been used for a while
4666                 // (note: this check is run after the frame render, so any targets used
4667                 // this frame will not be affected even at low framerates)
4668                 if (r && (realtime - r->lastusetime > 0.2 || force))
4669                 {
4670                         if (r->fbo)
4671                                 R_Mesh_DestroyFramebufferObject(r->fbo);
4672                         for (j = 0; j < sizeof(r->colortexture) / sizeof(r->colortexture[0]); j++)
4673                                 if (r->colortexture[j])
4674                                         R_FreeTexture(r->colortexture[j]);
4675                         if (r->depthtexture)
4676                                 R_FreeTexture(r->depthtexture);
4677                         Mem_ExpandableArray_FreeRecord(&r_fb.rendertargets, r);
4678                 }
4679         }
4680 }
4681
4682 static void R_CalcTexCoordsForView(float x, float y, float w, float h, float tw, float th, float *texcoord2f)
4683 {
4684         float iw = 1.0f / tw, ih = 1.0f / th, x1, y1, x2, y2;
4685         x1 = x * iw;
4686         x2 = (x + w) * iw;
4687         y1 = (th - y) * ih;
4688         y2 = (th - y - h) * ih;
4689         texcoord2f[0] = x1;
4690         texcoord2f[2] = x2;
4691         texcoord2f[4] = x2;
4692         texcoord2f[6] = x1;
4693         texcoord2f[1] = y1;
4694         texcoord2f[3] = y1;
4695         texcoord2f[5] = y2;
4696         texcoord2f[7] = y2;
4697 }
4698
4699 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)
4700 {
4701         int i, j, end;
4702         r_rendertarget_t *r = NULL;
4703         char vabuf[256];
4704         // first try to reuse an existing slot if possible
4705         end = Mem_ExpandableArray_IndexRange(&r_fb.rendertargets);
4706         for (i = 0; i < end; i++)
4707         {
4708                 r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4709                 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)
4710                         break;
4711         }
4712         if (i == end)
4713         {
4714                 // no unused exact match found, so we have to make one in the first unused slot
4715                 r = (r_rendertarget_t *)Mem_ExpandableArray_AllocRecord(&r_fb.rendertargets);
4716                 r->texturewidth = texturewidth;
4717                 r->textureheight = textureheight;
4718                 r->colortextype[0] = colortextype0;
4719                 r->colortextype[1] = colortextype1;
4720                 r->colortextype[2] = colortextype2;
4721                 r->colortextype[3] = colortextype3;
4722                 r->depthtextype = depthtextype;
4723                 r->depthisrenderbuffer = depthisrenderbuffer;
4724                 for (j = 0; j < 4; j++)
4725                         if (r->colortextype[j])
4726                                 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);
4727                 if (r->depthtextype)
4728                 {
4729                         if (r->depthisrenderbuffer)
4730                                 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);
4731                         else
4732                                 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);
4733                 }
4734                 r->fbo = R_Mesh_CreateFramebufferObject(r->depthtexture, r->colortexture[0], r->colortexture[1], r->colortexture[2], r->colortexture[3]);
4735         }
4736         r_refdef.stats[r_stat_rendertargets_used]++;
4737         r_refdef.stats[r_stat_rendertargets_pixels] += r->texturewidth * r->textureheight;
4738         r->lastusetime = realtime;
4739         R_CalcTexCoordsForView(0, 0, r->texturewidth, r->textureheight, r->texturewidth, r->textureheight, r->texcoord2f);
4740         return r;
4741 }
4742
4743 static void R_Water_StartFrame(void)
4744 {
4745         int waterwidth, waterheight;
4746
4747         if (vid.width > (int)vid.maxtexturesize_2d || vid.height > (int)vid.maxtexturesize_2d)
4748                 return;
4749
4750         // set waterwidth and waterheight to the water resolution that will be
4751         // used (often less than the screen resolution for faster rendering)
4752         waterwidth = (int)bound(1, r_refdef.view.width * r_water_resolutionmultiplier.value, r_refdef.view.width);
4753         waterheight = (int)bound(1, r_refdef.view.height * r_water_resolutionmultiplier.value, r_refdef.view.height);
4754         R_GetScaledViewSize(waterwidth, waterheight, &waterwidth, &waterheight);
4755
4756         if (!r_water.integer || r_showsurfaces.integer)
4757                 waterwidth = waterheight = 0;
4758
4759         // set up variables that will be used in shader setup
4760         r_fb.water.waterwidth = waterwidth;
4761         r_fb.water.waterheight = waterheight;
4762         r_fb.water.texturewidth = waterwidth;
4763         r_fb.water.textureheight = waterheight;
4764         r_fb.water.camerawidth = waterwidth;
4765         r_fb.water.cameraheight = waterheight;
4766         r_fb.water.screenscale[0] = 0.5f;
4767         r_fb.water.screenscale[1] = 0.5f;
4768         r_fb.water.screencenter[0] = 0.5f;
4769         r_fb.water.screencenter[1] = 0.5f;
4770         r_fb.water.enabled = waterwidth != 0;
4771
4772         r_fb.water.maxwaterplanes = MAX_WATERPLANES;
4773         r_fb.water.numwaterplanes = 0;
4774 }
4775
4776 void R_Water_AddWaterPlane(msurface_t *surface, int entno)
4777 {
4778         int planeindex, bestplaneindex, vertexindex;
4779         vec3_t mins, maxs, normal, center, v, n;
4780         vec_t planescore, bestplanescore;
4781         mplane_t plane;
4782         r_waterstate_waterplane_t *p;
4783         texture_t *t = R_GetCurrentTexture(surface->texture);
4784
4785         rsurface.texture = t;
4786         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, 1, ((const msurface_t **)&surface));
4787         // if the model has no normals, it's probably off-screen and they were not generated, so don't add it anyway
4788         if (!rsurface.batchnormal3f || rsurface.batchnumvertices < 1)
4789                 return;
4790         // average the vertex normals, find the surface bounds (after deformvertexes)
4791         Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f, v);
4792         Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f, n);
4793         VectorCopy(n, normal);
4794         VectorCopy(v, mins);
4795         VectorCopy(v, maxs);
4796         for (vertexindex = 1;vertexindex < rsurface.batchnumvertices;vertexindex++)
4797         {
4798                 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f + vertexindex*3, v);
4799                 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f + vertexindex*3, n);
4800                 VectorAdd(normal, n, normal);
4801                 mins[0] = min(mins[0], v[0]);
4802                 mins[1] = min(mins[1], v[1]);
4803                 mins[2] = min(mins[2], v[2]);
4804                 maxs[0] = max(maxs[0], v[0]);
4805                 maxs[1] = max(maxs[1], v[1]);
4806                 maxs[2] = max(maxs[2], v[2]);
4807         }
4808         VectorNormalize(normal);
4809         VectorMAM(0.5f, mins, 0.5f, maxs, center);
4810
4811         VectorCopy(normal, plane.normal);
4812         VectorNormalize(plane.normal);
4813         plane.dist = DotProduct(center, plane.normal);
4814         PlaneClassify(&plane);
4815         if (PlaneDiff(r_refdef.view.origin, &plane) < 0)
4816         {
4817                 // skip backfaces (except if nocullface is set)
4818 //              if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE))
4819 //                      return;
4820                 VectorNegate(plane.normal, plane.normal);
4821                 plane.dist *= -1;
4822                 PlaneClassify(&plane);
4823         }
4824
4825
4826         // find a matching plane if there is one
4827         bestplaneindex = -1;
4828         bestplanescore = 1048576.0f;
4829         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4830         {
4831                 if(p->camera_entity == t->camera_entity)
4832                 {
4833                         planescore = 1.0f - DotProduct(plane.normal, p->plane.normal) + fabs(plane.dist - p->plane.dist) * 0.001f;
4834                         if (bestplaneindex < 0 || bestplanescore > planescore)
4835                         {
4836                                 bestplaneindex = planeindex;
4837                                 bestplanescore = planescore;
4838                         }
4839                 }
4840         }
4841         planeindex = bestplaneindex;
4842
4843         // if this surface does not fit any known plane rendered this frame, add one
4844         if (planeindex < 0 || bestplanescore > 0.001f)
4845         {
4846                 if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
4847                 {
4848                         // store the new plane
4849                         planeindex = r_fb.water.numwaterplanes++;
4850                         p = r_fb.water.waterplanes + planeindex;
4851                         p->plane = plane;
4852                         // clear materialflags and pvs
4853                         p->materialflags = 0;
4854                         p->pvsvalid = false;
4855                         p->camera_entity = t->camera_entity;
4856                         VectorCopy(mins, p->mins);
4857                         VectorCopy(maxs, p->maxs);
4858                 }
4859                 else
4860                 {
4861                         // We're totally screwed.
4862                         return;
4863                 }
4864         }
4865         else
4866         {
4867                 // merge mins/maxs when we're adding this surface to the plane
4868                 p = r_fb.water.waterplanes + planeindex;
4869                 p->mins[0] = min(p->mins[0], mins[0]);
4870                 p->mins[1] = min(p->mins[1], mins[1]);
4871                 p->mins[2] = min(p->mins[2], mins[2]);
4872                 p->maxs[0] = max(p->maxs[0], maxs[0]);
4873                 p->maxs[1] = max(p->maxs[1], maxs[1]);
4874                 p->maxs[2] = max(p->maxs[2], maxs[2]);
4875         }
4876         // merge this surface's materialflags into the waterplane
4877         p->materialflags |= t->currentmaterialflags;
4878         if(!(p->materialflags & MATERIALFLAG_CAMERA))
4879         {
4880                 // merge this surface's PVS into the waterplane
4881                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
4882                  && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
4883                 {
4884                         r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
4885                         p->pvsvalid = true;
4886                 }
4887         }
4888 }
4889
4890 extern cvar_t r_drawparticles;
4891 extern cvar_t r_drawdecals;
4892
4893 static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int viewx, int viewy, int viewwidth, int viewheight)
4894 {
4895         int myscissor[4];
4896         r_refdef_view_t originalview;
4897         r_refdef_view_t myview;
4898         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;
4899         r_waterstate_waterplane_t *p;
4900         vec3_t visorigin;
4901         r_rendertarget_t *rt;
4902
4903         originalview = r_refdef.view;
4904
4905         // lowquality hack, temporarily shut down some cvars and restore afterwards
4906         qualityreduction = r_water_lowquality.integer;
4907         if (qualityreduction > 0)
4908         {
4909                 if (qualityreduction >= 1)
4910                 {
4911                         old_r_shadows = r_shadows.integer;
4912                         old_r_worldrtlight = r_shadow_realtime_world.integer;
4913                         old_r_dlight = r_shadow_realtime_dlight.integer;
4914                         Cvar_SetValueQuick(&r_shadows, 0);
4915                         Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
4916                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, 0);
4917                 }
4918                 if (qualityreduction >= 2)
4919                 {
4920                         old_r_dynamic = r_dynamic.integer;
4921                         old_r_particles = r_drawparticles.integer;
4922                         old_r_decals = r_drawdecals.integer;
4923                         Cvar_SetValueQuick(&r_dynamic, 0);
4924                         Cvar_SetValueQuick(&r_drawparticles, 0);
4925                         Cvar_SetValueQuick(&r_drawdecals, 0);
4926                 }
4927         }
4928
4929         for (planeindex = 0, p = r_fb.water.waterplanes; planeindex < r_fb.water.numwaterplanes; planeindex++, p++)
4930         {
4931                 p->rt_reflection = NULL;
4932                 p->rt_refraction = NULL;
4933                 p->rt_camera = NULL;
4934         }
4935
4936         // render views
4937         r_refdef.view = originalview;
4938         r_refdef.view.showdebug = false;
4939         r_refdef.view.width = r_fb.water.waterwidth;
4940         r_refdef.view.height = r_fb.water.waterheight;
4941         r_refdef.view.useclipplane = true;
4942         myview = r_refdef.view;
4943         r_fb.water.renderingscene = true;
4944         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4945         {
4946                 if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
4947                         continue;
4948
4949                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
4950                 {
4951                         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);
4952                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4953                                 goto error;
4954                         r_refdef.view = myview;
4955                         Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
4956                         Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
4957                         if(r_water_scissormode.integer)
4958                         {
4959                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4960                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4961                                 {
4962                                         p->rt_reflection = NULL;
4963                                         p->rt_refraction = NULL;
4964                                         p->rt_camera = NULL;
4965                                         continue;
4966                                 }
4967                         }
4968
4969                         r_refdef.view.clipplane = p->plane;
4970                         // reflected view origin may be in solid, so don't cull with it
4971                         r_refdef.view.usevieworiginculling = false;
4972                         // reverse the cullface settings for this render
4973                         r_refdef.view.cullface_front = GL_FRONT;
4974                         r_refdef.view.cullface_back = GL_BACK;
4975                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4976                         {
4977                                 r_refdef.view.usecustompvs = true;
4978                                 if (p->pvsvalid)
4979                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4980                                 else
4981                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4982                         }
4983
4984                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 2) && !chase_active.integer);
4985                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4986                         GL_ScissorTest(false);
4987                         R_ClearScreen(r_refdef.fogenabled);
4988                         GL_ScissorTest(true);
4989                         if(r_water_scissormode.integer & 2)
4990                                 R_View_UpdateWithScissor(myscissor);
4991                         else
4992                                 R_View_Update();
4993                         R_AnimCache_CacheVisibleEntities();
4994                         if(r_water_scissormode.integer & 1)
4995                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4996                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4997
4998                         r_fb.water.hideplayer = false;
4999                         p->rt_reflection = rt;
5000                 }
5001
5002                 // render the normal view scene and copy into texture
5003                 // (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)
5004                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
5005                 {
5006                         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);
5007                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
5008                                 goto error;
5009                         r_refdef.view = myview;
5010                         if(r_water_scissormode.integer)
5011                         {
5012                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
5013                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
5014                                 {
5015                                         p->rt_reflection = NULL;
5016                                         p->rt_refraction = NULL;
5017                                         p->rt_camera = NULL;
5018                                         continue;
5019                                 }
5020                         }
5021
5022                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
5023
5024                         r_refdef.view.clipplane = p->plane;
5025                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5026                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5027
5028                         if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity)
5029                         {
5030                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5031                                 r_fb.water.hideplayer = false; // we don't want to hide the player model from these ones
5032                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5033                                 R_RenderView_UpdateViewVectors();
5034                                 if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5035                                 {
5036                                         r_refdef.view.usecustompvs = true;
5037                                         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);
5038                                 }
5039                         }
5040
5041                         PlaneClassify(&r_refdef.view.clipplane);
5042
5043                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5044                         GL_ScissorTest(false);
5045                         R_ClearScreen(r_refdef.fogenabled);
5046                         GL_ScissorTest(true);
5047                         if(r_water_scissormode.integer & 2)
5048                                 R_View_UpdateWithScissor(myscissor);
5049                         else
5050                                 R_View_Update();
5051                         R_AnimCache_CacheVisibleEntities();
5052                         if(r_water_scissormode.integer & 1)
5053                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
5054                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5055
5056                         r_fb.water.hideplayer = false;
5057                         p->rt_refraction = rt;
5058                 }
5059                 else if (p->materialflags & MATERIALFLAG_CAMERA)
5060                 {
5061                         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);
5062                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
5063                                 goto error;
5064                         r_refdef.view = myview;
5065
5066                         r_refdef.view.clipplane = p->plane;
5067                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5068                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5069
5070                         r_refdef.view.width = r_fb.water.camerawidth;
5071                         r_refdef.view.height = r_fb.water.cameraheight;
5072                         r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0);
5073                         r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0);
5074                         r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView
5075                         r_refdef.view.ortho_y = 90; // abused as angle by VM_CL_R_SetView
5076
5077                         if(p->camera_entity)
5078                         {
5079                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5080                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5081                         }
5082
5083                         // note: all of the view is used for displaying... so
5084                         // there is no use in scissoring
5085
5086                         // reverse the cullface settings for this render
5087                         r_refdef.view.cullface_front = GL_FRONT;
5088                         r_refdef.view.cullface_back = GL_BACK;
5089                         // also reverse the view matrix
5090                         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
5091                         R_RenderView_UpdateViewVectors();
5092                         if(p->camera_entity && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5093                         {
5094                                 r_refdef.view.usecustompvs = true;
5095                                 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);
5096                         }
5097                         
5098                         // camera needs no clipplane
5099                         r_refdef.view.useclipplane = false;
5100                         // TODO: is the camera origin always valid?  if so we don't need to clear this
5101                         r_refdef.view.usevieworiginculling = false;
5102
5103                         PlaneClassify(&r_refdef.view.clipplane);
5104
5105                         r_fb.water.hideplayer = false;
5106
5107                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5108                         GL_ScissorTest(false);
5109                         R_ClearScreen(r_refdef.fogenabled);
5110                         GL_ScissorTest(true);
5111                         R_View_Update();
5112                         R_AnimCache_CacheVisibleEntities();
5113                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5114
5115                         r_fb.water.hideplayer = false;
5116                         p->rt_camera = rt;
5117                 }
5118
5119         }
5120         r_fb.water.renderingscene = false;
5121         r_refdef.view = originalview;
5122         R_ResetViewRendering3D(fbo, depthtexture, colortexture, viewx, viewy, viewwidth, viewheight);
5123         R_View_Update();
5124         R_AnimCache_CacheVisibleEntities();
5125         goto finish;
5126 error:
5127         r_refdef.view = originalview;
5128         r_fb.water.renderingscene = false;
5129         Cvar_SetValueQuick(&r_water, 0);
5130         Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed!  Turned off r_water.\n");
5131 finish:
5132         // lowquality hack, restore cvars
5133         if (qualityreduction > 0)
5134         {
5135                 if (qualityreduction >= 1)
5136                 {
5137                         Cvar_SetValueQuick(&r_shadows, old_r_shadows);
5138                         Cvar_SetValueQuick(&r_shadow_realtime_world, old_r_worldrtlight);
5139                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, old_r_dlight);
5140                 }
5141                 if (qualityreduction >= 2)
5142                 {
5143                         Cvar_SetValueQuick(&r_dynamic, old_r_dynamic);
5144                         Cvar_SetValueQuick(&r_drawparticles, old_r_particles);
5145                         Cvar_SetValueQuick(&r_drawdecals, old_r_decals);
5146                 }
5147         }
5148 }
5149
5150 static void R_Bloom_StartFrame(void)
5151 {
5152         int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight;
5153         int viewwidth, viewheight;
5154         textype_t textype = TEXTYPE_COLORBUFFER;
5155
5156         // clear the pointers to rendertargets from last frame as they're stale
5157         r_fb.rt_screen = NULL;
5158         r_fb.rt_bloom = NULL;
5159
5160         switch (vid.renderpath)
5161         {
5162         case RENDERPATH_GL20:
5163                 r_fb.usedepthtextures = r_usedepthtextures.integer != 0;
5164                 if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
5165                 if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
5166                 // for simplicity, bloom requires FBO render to texture, which basically all video drivers support now
5167                 if (!vid.support.ext_framebuffer_object)
5168                         return;
5169                 break;
5170         case RENDERPATH_GLES2:
5171                 r_fb.usedepthtextures = false;
5172                 break;
5173         }
5174
5175         if (r_viewscale_fpsscaling.integer)
5176         {
5177                 double actualframetime;
5178                 double targetframetime;
5179                 double adjust;
5180                 actualframetime = r_refdef.lastdrawscreentime;
5181                 targetframetime = (1.0 / r_viewscale_fpsscaling_target.value);
5182                 adjust = (targetframetime - actualframetime) * r_viewscale_fpsscaling_multiply.value;
5183                 adjust = bound(-r_viewscale_fpsscaling_stepmax.value, adjust, r_viewscale_fpsscaling_stepmax.value);
5184                 if (r_viewscale_fpsscaling_stepsize.value > 0)
5185                         adjust = (int)(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5186                 viewscalefpsadjusted += adjust;
5187                 viewscalefpsadjusted = bound(r_viewscale_fpsscaling_min.value, viewscalefpsadjusted, 1.0f);
5188         }
5189         else
5190                 viewscalefpsadjusted = 1.0f;
5191
5192         R_GetScaledViewSize(r_refdef.view.width, r_refdef.view.height, &viewwidth, &viewheight);
5193
5194         // set bloomwidth and bloomheight to the bloom resolution that will be
5195         // used (often less than the screen resolution for faster rendering)
5196         r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, vid.width);
5197         r_fb.bloomheight = r_fb.bloomwidth * vid.height / vid.width;
5198         r_fb.bloomheight = bound(1, r_fb.bloomheight, vid.height);
5199         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d);
5200         r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d);
5201
5202         // calculate desired texture sizes
5203         screentexturewidth = viewwidth;
5204         screentextureheight = viewheight;
5205         bloomtexturewidth = r_fb.bloomwidth;
5206         bloomtextureheight = r_fb.bloomheight;
5207
5208         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))
5209         {
5210                 Cvar_SetValueQuick(&r_bloom, 0);
5211                 Cvar_SetValueQuick(&r_motionblur, 0);
5212                 Cvar_SetValueQuick(&r_damageblur, 0);
5213         }
5214
5215         // allocate motionblur ghost texture if needed - this is the only persistent texture and is only useful on the main view
5216         if (r_refdef.view.ismain && (r_fb.screentexturewidth != screentexturewidth || r_fb.screentextureheight != screentextureheight || r_fb.textype != textype))
5217         {
5218                 if (r_fb.ghosttexture)
5219                         R_FreeTexture(r_fb.ghosttexture);
5220                 r_fb.ghosttexture = NULL;
5221
5222                 r_fb.screentexturewidth = screentexturewidth;
5223                 r_fb.screentextureheight = screentextureheight;
5224                 r_fb.textype = textype;
5225
5226                 if (r_fb.screentexturewidth && r_fb.screentextureheight)
5227                 {
5228                         if (r_motionblur.value > 0 || r_damageblur.value > 0)
5229                                 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);
5230                         r_fb.ghosttexture_valid = false;
5231                 }
5232         }
5233
5234         if (r_bloom.integer)
5235         {
5236                 // bloom texture is a different resolution
5237                 r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, r_refdef.view.width);
5238                 r_fb.bloomheight = r_fb.bloomwidth * r_refdef.view.height / r_refdef.view.width;
5239                 r_fb.bloomheight = bound(1, r_fb.bloomheight, r_refdef.view.height);
5240         }
5241         else
5242                 r_fb.bloomwidth = r_fb.bloomheight = 0;
5243
5244         r_fb.rt_screen = R_RenderTarget_Get(screentexturewidth, screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5245
5246         r_refdef.view.clear = true;
5247 }
5248
5249 static void R_Bloom_MakeTexture(void)
5250 {
5251         int x, range, dir;
5252         float xoffset, yoffset, r, brighten;
5253         float colorscale = r_bloom_colorscale.value;
5254         r_viewport_t bloomviewport;
5255         r_rendertarget_t *prev, *cur;
5256         textype_t textype = r_fb.rt_screen->colortextype[0];
5257
5258         r_refdef.stats[r_stat_bloom]++;
5259
5260         R_Viewport_InitOrtho(&bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
5261
5262         // scale down screen texture to the bloom texture size
5263         CHECKGLERROR
5264         prev = r_fb.rt_screen;
5265         cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5266         R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5267         R_SetViewport(&bloomviewport);
5268         GL_CullFace(GL_NONE);
5269         GL_DepthTest(false);
5270         GL_BlendFunc(GL_ONE, GL_ZERO);
5271         GL_Color(colorscale, colorscale, colorscale, 1);
5272         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5273         // TODO: do boxfilter scale-down in shader?
5274         R_SetupShader_Generic(prev->colortexture[0], NULL, GL_MODULATE, 1, false, true, true);
5275         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5276         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5277         // we now have a properly scaled bloom image
5278
5279         // multiply bloom image by itself as many times as desired to darken it
5280         // TODO: if people actually use this it could be done more quickly in the previous shader pass
5281         for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
5282         {
5283                 prev = cur;
5284                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5285                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5286                 x *= 2;
5287                 r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1
5288                 if(x <= 2)
5289                         GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 128);
5290                 GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
5291                 GL_Color(1,1,1,1); // no fix factor supported here
5292                 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5293                 R_SetupShader_Generic(prev->colortexture[0], NULL, GL_MODULATE, 1, false, true, false);
5294                 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5295                 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5296         }
5297
5298         range = r_bloom_blur.integer * r_fb.bloomwidth / 320;
5299         brighten = r_bloom_brighten.value;
5300         brighten = sqrt(brighten);
5301         if(range >= 1)
5302                 brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
5303
5304         for (dir = 0;dir < 2;dir++)
5305         {
5306                 prev = cur;
5307                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5308                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5309                 // blend on at multiple vertical offsets to achieve a vertical blur
5310                 // TODO: do offset blends using GLSL
5311                 // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
5312                 GL_BlendFunc(GL_ONE, GL_ZERO);
5313                 R_SetupShader_Generic(prev->colortexture[0], NULL, GL_MODULATE, 1, false, true, false);
5314                 for (x = -range;x <= range;x++)
5315                 {
5316                         if (!dir){xoffset = 0;yoffset = x;}
5317                         else {xoffset = x;yoffset = 0;}
5318                         xoffset /= (float)prev->texturewidth;
5319                         yoffset /= (float)prev->textureheight;
5320                         // compute a texcoord array with the specified x and y offset
5321                         r_fb.offsettexcoord2f[0] = xoffset+prev->texcoord2f[0];
5322                         r_fb.offsettexcoord2f[1] = yoffset+prev->texcoord2f[1];
5323                         r_fb.offsettexcoord2f[2] = xoffset+prev->texcoord2f[2];
5324                         r_fb.offsettexcoord2f[3] = yoffset+prev->texcoord2f[3];
5325                         r_fb.offsettexcoord2f[4] = xoffset+prev->texcoord2f[4];
5326                         r_fb.offsettexcoord2f[5] = yoffset+prev->texcoord2f[5];
5327                         r_fb.offsettexcoord2f[6] = xoffset+prev->texcoord2f[6];
5328                         r_fb.offsettexcoord2f[7] = yoffset+prev->texcoord2f[7];
5329                         // this r value looks like a 'dot' particle, fading sharply to
5330                         // black at the edges
5331                         // (probably not realistic but looks good enough)
5332                         //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
5333                         //r = brighten/(range*2+1);
5334                         r = brighten / (range * 2 + 1);
5335                         if(range >= 1)
5336                                 r *= (1 - x*x/(float)((range+1)*(range+1)));
5337                         if (r <= 0)
5338                                 continue;
5339                         GL_Color(r, r, r, 1);
5340                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f);
5341                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5342                         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5343                         GL_BlendFunc(GL_ONE, GL_ONE);
5344                 }
5345         }
5346
5347         // now we have the bloom image, so keep track of it
5348         r_fb.rt_bloom = cur;
5349 }
5350
5351 static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5352 {
5353         dpuint64 permutation;
5354         float uservecs[4][4];
5355         rtexture_t *viewtexture;
5356         rtexture_t *bloomtexture;
5357
5358         R_EntityMatrix(&identitymatrix);
5359
5360         if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
5361         {
5362                 // declare variables
5363                 float blur_factor, blur_mouseaccel, blur_velocity;
5364                 static float blur_average; 
5365                 static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
5366
5367                 // set a goal for the factoring
5368                 blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value) 
5369                         / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
5370                 blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value) 
5371                         / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
5372                 blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value) 
5373                         + (blur_mouseaccel * r_motionblur_mousefactor.value));
5374
5375                 // from the goal, pick an averaged value between goal and last value
5376                 cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
5377                 blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
5378
5379                 // enforce minimum amount of blur 
5380                 blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
5381
5382                 //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
5383
5384                 // calculate values into a standard alpha
5385                 cl.motionbluralpha = 1 - exp(-
5386                                 (
5387                                         (r_motionblur.value * blur_factor / 80)
5388                                         +
5389                                         (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
5390                                 )
5391                                 /
5392                                 max(0.0001, cl.time - cl.oldtime) // fps independent
5393                                 );
5394
5395                 // randomization for the blur value to combat persistent ghosting
5396                 cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
5397                 cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
5398
5399                 // apply the blur
5400                 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5401                 if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
5402                 {
5403                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5404                         GL_Color(1, 1, 1, cl.motionbluralpha);
5405                         R_CalcTexCoordsForView(0, 0, viewwidth, viewheight, viewwidth, viewheight, r_fb.ghosttexcoord2f);
5406                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.ghosttexcoord2f);
5407                         R_SetupShader_Generic(r_fb.ghosttexture, NULL, GL_MODULATE, 1, false, true, true);
5408                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5409                         r_refdef.stats[r_stat_bloom_drawpixels] += viewwidth * viewheight;
5410                 }
5411
5412                 // updates old view angles for next pass
5413                 VectorCopy(cl.viewangles, blur_oldangles);
5414
5415                 // copy view into the ghost texture
5416                 R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, viewx, viewy, viewwidth, viewheight);
5417                 r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight;
5418                 r_fb.ghosttexture_valid = true;
5419         }
5420
5421         if (r_fb.bloomwidth)
5422         {
5423                 // make the bloom texture
5424                 R_Bloom_MakeTexture();
5425         }
5426
5427 #if _MSC_VER >= 1400
5428 #define sscanf sscanf_s
5429 #endif
5430         memset(uservecs, 0, sizeof(uservecs));
5431         if (r_glsl_postprocess_uservec1_enable.integer)
5432                 sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
5433         if (r_glsl_postprocess_uservec2_enable.integer)
5434                 sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
5435         if (r_glsl_postprocess_uservec3_enable.integer)
5436                 sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
5437         if (r_glsl_postprocess_uservec4_enable.integer)
5438                 sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
5439
5440         // render to the screen fbo
5441         R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5442         GL_Color(1, 1, 1, 1);
5443         GL_BlendFunc(GL_ONE, GL_ZERO);
5444
5445         viewtexture = r_fb.rt_screen->colortexture[0];
5446         bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL;
5447
5448         if (r_rendertarget_debug.integer >= 0)
5449         {
5450                 r_rendertarget_t *rt = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, r_rendertarget_debug.integer);
5451                 if (rt && rt->colortexture[0])
5452                 {
5453                         viewtexture = rt->colortexture[0];
5454                         bloomtexture = NULL;
5455                 }
5456         }
5457
5458         R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.rt_screen->texcoord2f, bloomtexture ? r_fb.rt_bloom->texcoord2f : NULL);
5459         switch(vid.renderpath)
5460         {
5461         case RENDERPATH_GL20:
5462         case RENDERPATH_GLES2:
5463                 permutation =
5464                         (r_fb.bloomwidth ? SHADERPERMUTATION_BLOOM : 0)
5465                         | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
5466                         | (!vid_gammatables_trivial ? SHADERPERMUTATION_GAMMARAMPS : 0)
5467                         | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
5468                         | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
5469                 R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation);
5470                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First     , viewtexture);
5471                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second    , bloomtexture);
5472                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps       );
5473                 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]);
5474                 if (r_glsl_permutation->loc_PixelSize               >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize         , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
5475                 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]);
5476                 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]);
5477                 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]);
5478                 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]);
5479                 if (r_glsl_permutation->loc_Saturation              >= 0) qglUniform1f(r_glsl_permutation->loc_Saturation        , r_glsl_saturation.value);
5480                 if (r_glsl_permutation->loc_PixelToScreenTexCoord   >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
5481                 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);
5482                 break;
5483         }
5484         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5485         r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height;
5486 }
5487
5488 matrix4x4_t r_waterscrollmatrix;
5489
5490 void R_UpdateFog(void)
5491 {
5492         // Nehahra fog
5493         if (gamemode == GAME_NEHAHRA)
5494         {
5495                 if (gl_fogenable.integer)
5496                 {
5497                         r_refdef.oldgl_fogenable = true;
5498                         r_refdef.fog_density = gl_fogdensity.value;
5499                         r_refdef.fog_red = gl_fogred.value;
5500                         r_refdef.fog_green = gl_foggreen.value;
5501                         r_refdef.fog_blue = gl_fogblue.value;
5502                         r_refdef.fog_alpha = 1;
5503                         r_refdef.fog_start = 0;
5504                         r_refdef.fog_end = gl_skyclip.value;
5505                         r_refdef.fog_height = 1<<30;
5506                         r_refdef.fog_fadedepth = 128;
5507                 }
5508                 else if (r_refdef.oldgl_fogenable)
5509                 {
5510                         r_refdef.oldgl_fogenable = false;
5511                         r_refdef.fog_density = 0;
5512                         r_refdef.fog_red = 0;
5513                         r_refdef.fog_green = 0;
5514                         r_refdef.fog_blue = 0;
5515                         r_refdef.fog_alpha = 0;
5516                         r_refdef.fog_start = 0;
5517                         r_refdef.fog_end = 0;
5518                         r_refdef.fog_height = 1<<30;
5519                         r_refdef.fog_fadedepth = 128;
5520                 }
5521         }
5522
5523         // fog parms
5524         r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1);
5525         r_refdef.fog_start = max(0, r_refdef.fog_start);
5526         r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end);
5527
5528         if (r_refdef.fog_density && r_drawfog.integer)
5529         {
5530                 r_refdef.fogenabled = true;
5531                 // this is the point where the fog reaches 0.9986 alpha, which we
5532                 // consider a good enough cutoff point for the texture
5533                 // (0.9986 * 256 == 255.6)
5534                 if (r_fog_exp2.integer)
5535                         r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start;
5536                 else
5537                         r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start;
5538                 r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end);
5539                 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
5540                 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
5541                 if (strcmp(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename))
5542                         R_BuildFogHeightTexture();
5543                 // fog color was already set
5544                 // update the fog texture
5545                 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)
5546                         R_BuildFogTexture();
5547                 r_refdef.fog_height_texcoordscale = 1.0f / max(0.125f, r_refdef.fog_fadedepth);
5548                 r_refdef.fog_height_tablescale = r_refdef.fog_height_tablesize * r_refdef.fog_height_texcoordscale;
5549         }
5550         else
5551                 r_refdef.fogenabled = false;
5552
5553         // fog color
5554         if (r_refdef.fog_density)
5555         {
5556                 r_refdef.fogcolor[0] = r_refdef.fog_red;
5557                 r_refdef.fogcolor[1] = r_refdef.fog_green;
5558                 r_refdef.fogcolor[2] = r_refdef.fog_blue;
5559
5560                 Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height);
5561                 r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3];
5562                 r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0;
5563                 r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth);
5564
5565                 {
5566                         vec3_t fogvec;
5567                         VectorCopy(r_refdef.fogcolor, fogvec);
5568                         //   color.rgb *= ContrastBoost * SceneBrightness;
5569                         VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
5570                         r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
5571                         r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f);
5572                         r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f);
5573                 }
5574         }
5575 }
5576
5577 void R_UpdateVariables(void)
5578 {
5579         R_Textures_Frame();
5580
5581         r_refdef.scene.ambientintensity = r_ambient.value * (1.0f / 64.0f);
5582
5583         r_refdef.farclip = r_farclip_base.value;
5584         if (r_refdef.scene.worldmodel)
5585                 r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2;
5586         r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
5587
5588         if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
5589                 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
5590         r_refdef.polygonfactor = 0;
5591         r_refdef.polygonoffset = 0;
5592         r_refdef.shadowpolygonfactor = r_refdef.polygonfactor + r_shadow_polygonfactor.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
5593         r_refdef.shadowpolygonoffset = r_refdef.polygonoffset + r_shadow_polygonoffset.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
5594
5595         r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
5596         r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil;
5597         r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer;
5598         r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil;
5599         r_refdef.scene.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
5600         if (FAKELIGHT_ENABLED)
5601         {
5602                 r_refdef.scene.lightmapintensity *= r_fakelight_intensity.value;
5603         }
5604         else if (r_refdef.scene.worldmodel)
5605         {
5606                 r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
5607         }
5608         if (r_showsurfaces.integer)
5609         {
5610                 r_refdef.scene.rtworld = false;
5611                 r_refdef.scene.rtworldshadows = false;
5612                 r_refdef.scene.rtdlight = false;
5613                 r_refdef.scene.rtdlightshadows = false;
5614                 r_refdef.scene.lightmapintensity = 0;
5615         }
5616
5617         r_gpuskeletal = false;
5618         switch(vid.renderpath)
5619         {
5620         case RENDERPATH_GL20:
5621                 r_gpuskeletal = vid.support.arb_uniform_buffer_object && r_glsl_skeletal.integer && !r_showsurfaces.integer; // FIXME add r_showsurfaces support to GLSL skeletal!
5622         case RENDERPATH_GLES2:
5623                 if(!vid_gammatables_trivial)
5624                 {
5625                         if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
5626                         {
5627                                 // build GLSL gamma texture
5628 #define RAMPWIDTH 256
5629                                 unsigned short ramp[RAMPWIDTH * 3];
5630                                 unsigned char rampbgr[RAMPWIDTH][4];
5631                                 int i;
5632
5633                                 r_texture_gammaramps_serial = vid_gammatables_serial;
5634
5635                                 VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
5636                                 for(i = 0; i < RAMPWIDTH; ++i)
5637                                 {
5638                                         rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5639                                         rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5640                                         rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
5641                                         rampbgr[i][3] = 0;
5642                                 }
5643                                 if (r_texture_gammaramps)
5644                                 {
5645                                         R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1);
5646                                 }
5647                                 else
5648                                 {
5649                                         r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
5650                                 }
5651                         }
5652                 }
5653                 else
5654                 {
5655                         // remove GLSL gamma texture
5656                 }
5657                 break;
5658         }
5659 }
5660
5661 static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT;
5662 static r_refdef_scene_t r_scenes_store[ RST_COUNT ];
5663 /*
5664 ================
5665 R_SelectScene
5666 ================
5667 */
5668 void R_SelectScene( r_refdef_scene_type_t scenetype ) {
5669         if( scenetype != r_currentscenetype ) {
5670                 // store the old scenetype
5671                 r_scenes_store[ r_currentscenetype ] = r_refdef.scene;
5672                 r_currentscenetype = scenetype;
5673                 // move in the new scene
5674                 r_refdef.scene = r_scenes_store[ r_currentscenetype ];
5675         }
5676 }
5677
5678 /*
5679 ================
5680 R_GetScenePointer
5681 ================
5682 */
5683 r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype )
5684 {
5685         // of course, we could also add a qboolean that provides a lock state and a ReleaseScenePointer function..
5686         if( scenetype == r_currentscenetype ) {
5687                 return &r_refdef.scene;
5688         } else {
5689                 return &r_scenes_store[ scenetype ];
5690         }
5691 }
5692
5693 static int R_SortEntities_Compare(const void *ap, const void *bp)
5694 {
5695         const entity_render_t *a = *(const entity_render_t **)ap;
5696         const entity_render_t *b = *(const entity_render_t **)bp;
5697
5698         // 1. compare model
5699         if(a->model < b->model)
5700                 return -1;
5701         if(a->model > b->model)
5702                 return +1;
5703
5704         // 2. compare skin
5705         // TODO possibly calculate the REAL skinnum here first using
5706         // skinscenes?
5707         if(a->skinnum < b->skinnum)
5708                 return -1;
5709         if(a->skinnum > b->skinnum)
5710                 return +1;
5711
5712         // everything we compared is equal
5713         return 0;
5714 }
5715 static void R_SortEntities(void)
5716 {
5717         // below or equal 2 ents, sorting never gains anything
5718         if(r_refdef.scene.numentities <= 2)
5719                 return;
5720         // sort
5721         qsort(r_refdef.scene.entities, r_refdef.scene.numentities, sizeof(*r_refdef.scene.entities), R_SortEntities_Compare);
5722 }
5723
5724 /*
5725 ================
5726 R_RenderView
5727 ================
5728 */
5729 extern cvar_t r_shadow_bouncegrid;
5730 extern cvar_t v_isometric;
5731 extern void V_MakeViewIsometric(void);
5732 void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5733 {
5734         matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
5735         int viewfbo = 0;
5736         rtexture_t *viewdepthtexture = NULL;
5737         rtexture_t *viewcolortexture = NULL;
5738         int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
5739
5740         // finish any 2D rendering that was queued
5741         DrawQ_Finish();
5742
5743         if (r_timereport_active)
5744                 R_TimeReport("start");
5745         r_textureframe++; // used only by R_GetCurrentTexture
5746         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5747
5748         if(R_CompileShader_CheckStaticParms())
5749                 R_GLSL_Restart_f();
5750
5751         if (!r_drawentities.integer)
5752                 r_refdef.scene.numentities = 0;
5753         else if (r_sortentities.integer)
5754                 R_SortEntities();
5755
5756         R_AnimCache_ClearCache();
5757
5758         /* adjust for stereo display */
5759         if(R_Stereo_Active())
5760         {
5761                 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);
5762                 Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);
5763         }
5764
5765         if (r_refdef.view.isoverlay)
5766         {
5767                 // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
5768                 R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
5769                 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
5770                 R_TimeReport("depthclear");
5771
5772                 r_refdef.view.showdebug = false;
5773
5774                 r_fb.water.enabled = false;
5775                 r_fb.water.numwaterplanes = 0;
5776
5777                 R_RenderScene(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5778
5779                 r_refdef.view.matrix = originalmatrix;
5780
5781                 CHECKGLERROR
5782                 return;
5783         }
5784
5785         if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/)
5786         {
5787                 r_refdef.view.matrix = originalmatrix;
5788                 return;
5789         }
5790
5791         r_refdef.view.usevieworiginculling = !r_trippy.value && r_refdef.view.useperspective;
5792         if (v_isometric.integer && r_refdef.view.ismain)
5793                 V_MakeViewIsometric();
5794
5795         r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value;
5796
5797         if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D)
5798                 // in sRGB fallback, behave similar to true sRGB: convert this
5799                 // value from linear to sRGB
5800                 r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale);
5801
5802         R_RenderView_UpdateViewVectors();
5803
5804         R_Shadow_UpdateWorldLightSelection();
5805
5806         // this will set up r_fb.rt_screen
5807         R_Bloom_StartFrame();
5808
5809         // apply bloom brightness offset
5810         if(r_fb.rt_bloom)
5811                 r_refdef.view.colorscale *= r_bloom_scenebrightness.value;
5812
5813         // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
5814         if (r_fb.rt_screen)
5815         {
5816                 viewfbo = r_fb.rt_screen->fbo;
5817                 viewdepthtexture = r_fb.rt_screen->depthtexture;
5818                 viewcolortexture = r_fb.rt_screen->colortexture[0];
5819                 viewx = 0;
5820                 viewy = 0;
5821                 viewwidth = width;
5822                 viewheight = height;
5823         }
5824
5825         R_Water_StartFrame();
5826
5827         CHECKGLERROR
5828         if (r_timereport_active)
5829                 R_TimeReport("viewsetup");
5830
5831         R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5832
5833         // clear the whole fbo every frame - otherwise the driver will consider
5834         // it to be an inter-frame texture and stall in multi-gpu configurations
5835         if (r_fb.rt_screen)
5836                 GL_ScissorTest(false);
5837         R_ClearScreen(r_refdef.fogenabled);
5838         if (r_timereport_active)
5839                 R_TimeReport("viewclear");
5840
5841         r_refdef.view.clear = true;
5842
5843         r_refdef.view.showdebug = true;
5844
5845         R_View_Update();
5846         if (r_timereport_active)
5847                 R_TimeReport("visibility");
5848
5849         R_AnimCache_CacheVisibleEntities();
5850         if (r_timereport_active)
5851                 R_TimeReport("animcache");
5852
5853         R_Shadow_UpdateBounceGridTexture();
5854         if (r_timereport_active && r_shadow_bouncegrid.integer)
5855                 R_TimeReport("bouncegrid");
5856
5857         r_fb.water.numwaterplanes = 0;
5858         if (r_fb.water.enabled)
5859                 R_RenderWaterPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5860
5861         // for the actual view render we use scissoring a fair amount, so scissor
5862         // test needs to be on
5863         if (r_fb.rt_screen)
5864                 GL_ScissorTest(true);
5865         GL_Scissor(viewx, viewy, viewwidth, viewheight);
5866         R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5867         r_fb.water.numwaterplanes = 0;
5868
5869         // postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring
5870         GL_ScissorTest(false);
5871
5872         R_BlendView(fbo, depthtexture, colortexture, x, y, width, height);
5873         if (r_timereport_active)
5874                 R_TimeReport("blendview");
5875
5876         r_refdef.view.matrix = originalmatrix;
5877
5878         CHECKGLERROR
5879
5880         // go back to 2d rendering
5881         DrawQ_Start();
5882 }
5883
5884 void R_RenderWaterPlanes(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5885 {
5886         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
5887         {
5888                 r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity);
5889                 if (r_timereport_active)
5890                         R_TimeReport("waterworld");
5891         }
5892
5893         // don't let sound skip if going slow
5894         if (r_refdef.scene.extraupdate)
5895                 S_ExtraUpdate ();
5896
5897         R_DrawModelsAddWaterPlanes();
5898         if (r_timereport_active)
5899                 R_TimeReport("watermodels");
5900
5901         if (r_fb.water.numwaterplanes)
5902         {
5903                 R_Water_ProcessPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5904                 if (r_timereport_active)
5905                         R_TimeReport("waterscenes");
5906         }
5907 }
5908
5909 extern cvar_t cl_locs_show;
5910 static void R_DrawLocs(void);
5911 static void R_DrawEntityBBoxes(prvm_prog_t *prog);
5912 static void R_DrawModelDecals(void);
5913 extern cvar_t cl_decals_newsystem;
5914 extern qboolean r_shadow_usingdeferredprepass;
5915 extern int r_shadow_shadowmapatlas_modelshadows_size;
5916 void R_RenderScene(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5917 {
5918         qboolean shadowmapping = false;
5919
5920         if (r_timereport_active)
5921                 R_TimeReport("beginscene");
5922
5923         r_refdef.stats[r_stat_renders]++;
5924
5925         R_UpdateFog();
5926
5927         // don't let sound skip if going slow
5928         if (r_refdef.scene.extraupdate)
5929                 S_ExtraUpdate ();
5930
5931         R_MeshQueue_BeginScene();
5932
5933         R_SkyStartFrame();
5934
5935         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);
5936
5937         if (r_timereport_active)
5938                 R_TimeReport("skystartframe");
5939
5940         if (cl.csqc_vidvars.drawworld)
5941         {
5942                 // don't let sound skip if going slow
5943                 if (r_refdef.scene.extraupdate)
5944                         S_ExtraUpdate ();
5945
5946                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawSky)
5947                 {
5948                         r_refdef.scene.worldmodel->DrawSky(r_refdef.scene.worldentity);
5949                         if (r_timereport_active)
5950                                 R_TimeReport("worldsky");
5951                 }
5952
5953                 if (R_DrawBrushModelsSky() && r_timereport_active)
5954                         R_TimeReport("bmodelsky");
5955
5956                 if (skyrendermasked && skyrenderlater)
5957                 {
5958                         // we have to force off the water clipping plane while rendering sky
5959                         R_SetupView(false, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5960                         R_Sky();
5961                         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5962                         if (r_timereport_active)
5963                                 R_TimeReport("sky");
5964                 }
5965         }
5966
5967         // save the framebuffer info for R_Shadow_RenderMode_Reset during this view render
5968         r_shadow_viewfbo = viewfbo;
5969         r_shadow_viewdepthtexture = viewdepthtexture;
5970         r_shadow_viewcolortexture = viewcolortexture;
5971         r_shadow_viewx = viewx;
5972         r_shadow_viewy = viewy;
5973         r_shadow_viewwidth = viewwidth;
5974         r_shadow_viewheight = viewheight;
5975
5976         R_Shadow_PrepareModelShadows();
5977         R_Shadow_PrepareLights();
5978         if (r_timereport_active)
5979                 R_TimeReport("preparelights");
5980
5981         // render all the shadowmaps that will be used for this view
5982         shadowmapping = R_Shadow_ShadowMappingEnabled();
5983         if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
5984         {
5985                 R_Shadow_DrawShadowMaps();
5986                 if (r_timereport_active)
5987                         R_TimeReport("shadowmaps");
5988         }
5989
5990         // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
5991         if (r_shadow_usingdeferredprepass)
5992                 R_Shadow_DrawPrepass();
5993
5994         // now we begin the forward pass of the view render
5995         if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
5996         {
5997                 r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
5998                 if (r_timereport_active)
5999                         R_TimeReport("worlddepth");
6000         }
6001         if (r_depthfirst.integer >= 2)
6002         {
6003                 R_DrawModelsDepth();
6004                 if (r_timereport_active)
6005                         R_TimeReport("modeldepth");
6006         }
6007
6008         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
6009         {
6010                 r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
6011                 if (r_timereport_active)
6012                         R_TimeReport("world");
6013         }
6014
6015         // don't let sound skip if going slow
6016         if (r_refdef.scene.extraupdate)
6017                 S_ExtraUpdate ();
6018
6019         R_DrawModels();
6020         if (r_timereport_active)
6021                 R_TimeReport("models");
6022
6023         // don't let sound skip if going slow
6024         if (r_refdef.scene.extraupdate)
6025                 S_ExtraUpdate ();
6026
6027         if ((r_shadows.integer == 1 || (r_shadows.integer > 0 && !shadowmapping)) && !r_shadows_drawafterrtlighting.integer && r_refdef.scene.lightmapintensity > 0)
6028         {
6029                 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
6030                 R_Shadow_DrawModelShadows();
6031                 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
6032                 // don't let sound skip if going slow
6033                 if (r_refdef.scene.extraupdate)
6034                         S_ExtraUpdate ();
6035         }
6036
6037         if (!r_shadow_usingdeferredprepass)
6038         {
6039                 R_Shadow_DrawLights();
6040                 if (r_timereport_active)
6041                         R_TimeReport("rtlights");
6042         }
6043
6044         // don't let sound skip if going slow
6045         if (r_refdef.scene.extraupdate)
6046                 S_ExtraUpdate ();
6047
6048         if ((r_shadows.integer == 1 || (r_shadows.integer > 0 && !shadowmapping)) && r_shadows_drawafterrtlighting.integer && r_refdef.scene.lightmapintensity > 0)
6049         {
6050                 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
6051                 R_Shadow_DrawModelShadows();
6052                 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
6053                 // don't let sound skip if going slow
6054                 if (r_refdef.scene.extraupdate)
6055                         S_ExtraUpdate ();
6056         }
6057
6058         if (cl.csqc_vidvars.drawworld)
6059         {
6060                 if (cl_decals_newsystem.integer)
6061                 {
6062                         R_DrawModelDecals();
6063                         if (r_timereport_active)
6064                                 R_TimeReport("modeldecals");
6065                 }
6066                 else
6067                 {
6068                         R_DrawDecals();
6069                         if (r_timereport_active)
6070                                 R_TimeReport("decals");
6071                 }
6072
6073                 R_DrawParticles();
6074                 if (r_timereport_active)
6075                         R_TimeReport("particles");
6076
6077                 R_DrawExplosions();
6078                 if (r_timereport_active)
6079                         R_TimeReport("explosions");
6080         }
6081
6082         if (r_refdef.view.showdebug)
6083         {
6084                 if (cl_locs_show.integer)
6085                 {
6086                         R_DrawLocs();
6087                         if (r_timereport_active)
6088                                 R_TimeReport("showlocs");
6089                 }
6090
6091                 if (r_drawportals.integer)
6092                 {
6093                         R_DrawPortals();
6094                         if (r_timereport_active)
6095                                 R_TimeReport("portals");
6096                 }
6097
6098                 if (r_showbboxes_client.value > 0)
6099                 {
6100                         R_DrawEntityBBoxes(CLVM_prog);
6101                         if (r_timereport_active)
6102                                 R_TimeReport("clbboxes");
6103                 }
6104                 if (r_showbboxes.value > 0)
6105                 {
6106                         R_DrawEntityBBoxes(SVVM_prog);
6107                         if (r_timereport_active)
6108                                 R_TimeReport("svbboxes");
6109                 }
6110         }
6111
6112         if (r_transparent.integer)
6113         {
6114                 R_MeshQueue_RenderTransparent();
6115                 if (r_timereport_active)
6116                         R_TimeReport("drawtrans");
6117         }
6118
6119         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))
6120         {
6121                 r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity);
6122                 if (r_timereport_active)
6123                         R_TimeReport("worlddebug");
6124                 R_DrawModelsDebug();
6125                 if (r_timereport_active)
6126                         R_TimeReport("modeldebug");
6127         }
6128
6129         if (cl.csqc_vidvars.drawworld)
6130         {
6131                 R_Shadow_DrawCoronas();
6132                 if (r_timereport_active)
6133                         R_TimeReport("coronas");
6134         }
6135
6136         // don't let sound skip if going slow
6137         if (r_refdef.scene.extraupdate)
6138                 S_ExtraUpdate ();
6139 }
6140
6141 static const unsigned short bboxelements[36] =
6142 {
6143         5, 1, 3, 5, 3, 7,
6144         6, 2, 0, 6, 0, 4,
6145         7, 3, 2, 7, 2, 6,
6146         4, 0, 1, 4, 1, 5,
6147         4, 5, 7, 4, 7, 6,
6148         1, 0, 2, 1, 2, 3,
6149 };
6150
6151 #define BBOXEDGES 13
6152 static const float bboxedges[BBOXEDGES][6] = 
6153 {
6154         // whole box
6155         { 0, 0, 0, 1, 1, 1 },
6156         // bottom edges
6157         { 0, 0, 0, 0, 1, 0 },
6158         { 0, 0, 0, 1, 0, 0 },
6159         { 0, 1, 0, 1, 1, 0 },
6160         { 1, 0, 0, 1, 1, 0 },
6161         // top edges
6162         { 0, 0, 1, 0, 1, 1 },
6163         { 0, 0, 1, 1, 0, 1 },
6164         { 0, 1, 1, 1, 1, 1 },
6165         { 1, 0, 1, 1, 1, 1 },
6166         // vertical edges
6167         { 0, 0, 0, 0, 0, 1 },
6168         { 1, 0, 0, 1, 0, 1 },
6169         { 0, 1, 0, 0, 1, 1 },
6170         { 1, 1, 0, 1, 1, 1 },
6171 };
6172
6173 static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
6174 {
6175         int numvertices = BBOXEDGES * 8;
6176         float vertex3f[BBOXEDGES * 8 * 3], color4f[BBOXEDGES * 8 * 4];
6177         int numtriangles = BBOXEDGES * 12;
6178         unsigned short elements[BBOXEDGES * 36];
6179         int i, edge;
6180         float *v, *c, f1, f2, edgemins[3], edgemaxs[3];
6181
6182         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6183
6184         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6185         GL_DepthMask(false);
6186         GL_DepthRange(0, 1);
6187         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
6188
6189         for (edge = 0; edge < BBOXEDGES; edge++)
6190         {
6191                 for (i = 0; i < 3; i++)
6192                 {
6193                         edgemins[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][i] - 0.25f;
6194                         edgemaxs[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][3 + i] + 0.25f;
6195                 }
6196                 vertex3f[edge * 24 + 0] = edgemins[0]; vertex3f[edge * 24 + 1] = edgemins[1]; vertex3f[edge * 24 + 2] = edgemins[2];
6197                 vertex3f[edge * 24 + 3] = edgemaxs[0]; vertex3f[edge * 24 + 4] = edgemins[1]; vertex3f[edge * 24 + 5] = edgemins[2];
6198                 vertex3f[edge * 24 + 6] = edgemins[0]; vertex3f[edge * 24 + 7] = edgemaxs[1]; vertex3f[edge * 24 + 8] = edgemins[2];
6199                 vertex3f[edge * 24 + 9] = edgemaxs[0]; vertex3f[edge * 24 + 10] = edgemaxs[1]; vertex3f[edge * 24 + 11] = edgemins[2];
6200                 vertex3f[edge * 24 + 12] = edgemins[0]; vertex3f[edge * 24 + 13] = edgemins[1]; vertex3f[edge * 24 + 14] = edgemaxs[2];
6201                 vertex3f[edge * 24 + 15] = edgemaxs[0]; vertex3f[edge * 24 + 16] = edgemins[1]; vertex3f[edge * 24 + 17] = edgemaxs[2];
6202                 vertex3f[edge * 24 + 18] = edgemins[0]; vertex3f[edge * 24 + 19] = edgemaxs[1]; vertex3f[edge * 24 + 20] = edgemaxs[2];
6203                 vertex3f[edge * 24 + 21] = edgemaxs[0]; vertex3f[edge * 24 + 22] = edgemaxs[1]; vertex3f[edge * 24 + 23] = edgemaxs[2];
6204                 for (i = 0; i < 36; i++)
6205                         elements[edge * 36 + i] = edge * 8 + bboxelements[i];
6206         }
6207         R_FillColors(color4f, numvertices, cr, cg, cb, ca);
6208         if (r_refdef.fogenabled)
6209         {
6210                 for (i = 0, v = vertex3f, c = color4f; i < numvertices; i++, v += 3, c += 4)
6211                 {
6212                         f1 = RSurf_FogVertex(v);
6213                         f2 = 1 - f1;
6214                         c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
6215                         c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
6216                         c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
6217                 }
6218         }
6219         R_Mesh_PrepareVertices_Generic_Arrays(numvertices, vertex3f, color4f, NULL);
6220         R_Mesh_ResetTextureState();
6221         R_SetupShader_Generic_NoTexture(false, false);
6222         R_Mesh_Draw(0, numvertices, 0, numtriangles, NULL, NULL, 0, elements, NULL, 0);
6223 }
6224
6225 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6226 {
6227         // hacky overloading of the parameters
6228         prvm_prog_t *prog = (prvm_prog_t *)rtlight;
6229         int i;
6230         float color[4];
6231         prvm_edict_t *edict;
6232
6233         GL_CullFace(GL_NONE);
6234         R_SetupShader_Generic_NoTexture(false, false);
6235
6236         for (i = 0;i < numsurfaces;i++)
6237         {
6238                 edict = PRVM_EDICT_NUM(surfacelist[i]);
6239                 switch ((int)PRVM_serveredictfloat(edict, solid))
6240                 {
6241                         case SOLID_NOT:      Vector4Set(color, 1, 1, 1, 0.05);break;
6242                         case SOLID_TRIGGER:  Vector4Set(color, 1, 0, 1, 0.10);break;
6243                         case SOLID_BBOX:     Vector4Set(color, 0, 1, 0, 0.10);break;
6244                         case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
6245                         case SOLID_BSP:      Vector4Set(color, 0, 0, 1, 0.05);break;
6246                         case SOLID_CORPSE:   Vector4Set(color, 1, 0.5, 0, 0.05);break;
6247                         default:             Vector4Set(color, 0, 0, 0, 0.50);break;
6248                 }
6249                 if (prog == CLVM_prog)
6250                         color[3] *= r_showbboxes_client.value;
6251                 else
6252                         color[3] *= r_showbboxes.value;
6253                 color[3] = bound(0, color[3], 1);
6254                 GL_DepthTest(!r_showdisabledepthtest.integer);
6255                 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
6256         }
6257 }
6258
6259 static void R_DrawEntityBBoxes(prvm_prog_t *prog)
6260 {
6261         int i;
6262         prvm_edict_t *edict;
6263         vec3_t center;
6264
6265         if (prog == NULL)
6266                 return;
6267
6268         for (i = 0; i < prog->num_edicts; i++)
6269         {
6270                 edict = PRVM_EDICT_NUM(i);
6271                 if (edict->priv.server->free)
6272                         continue;
6273                 // exclude the following for now, as they don't live in world coordinate space and can't be solid:
6274                 if (PRVM_serveredictedict(edict, tag_entity) != 0)
6275                         continue;
6276                 if (PRVM_serveredictedict(edict, viewmodelforclient) != 0)
6277                         continue;
6278                 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
6279                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)prog);
6280         }
6281 }
6282
6283 static const int nomodelelement3i[24] =
6284 {
6285         5, 2, 0,
6286         5, 1, 2,
6287         5, 0, 3,
6288         5, 3, 1,
6289         0, 2, 4,
6290         2, 1, 4,
6291         3, 0, 4,
6292         1, 3, 4
6293 };
6294
6295 static const unsigned short nomodelelement3s[24] =
6296 {
6297         5, 2, 0,
6298         5, 1, 2,
6299         5, 0, 3,
6300         5, 3, 1,
6301         0, 2, 4,
6302         2, 1, 4,
6303         3, 0, 4,
6304         1, 3, 4
6305 };
6306
6307 static const float nomodelvertex3f[6*3] =
6308 {
6309         -16,   0,   0,
6310          16,   0,   0,
6311           0, -16,   0,
6312           0,  16,   0,
6313           0,   0, -16,
6314           0,   0,  16
6315 };
6316
6317 static const float nomodelcolor4f[6*4] =
6318 {
6319         0.0f, 0.0f, 0.5f, 1.0f,
6320         0.0f, 0.0f, 0.5f, 1.0f,
6321         0.0f, 0.5f, 0.0f, 1.0f,
6322         0.0f, 0.5f, 0.0f, 1.0f,
6323         0.5f, 0.0f, 0.0f, 1.0f,
6324         0.5f, 0.0f, 0.0f, 1.0f
6325 };
6326
6327 static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6328 {
6329         int i;
6330         float f1, f2, *c;
6331         float color4f[6*4];
6332
6333         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);
6334
6335         // this is only called once per entity so numsurfaces is always 1, and
6336         // surfacelist is always {0}, so this code does not handle batches
6337
6338         if (rsurface.ent_flags & RENDER_ADDITIVE)
6339         {
6340                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
6341                 GL_DepthMask(false);
6342         }
6343         else if (ent->alpha < 1)
6344         {
6345                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6346                 GL_DepthMask(false);
6347         }
6348         else
6349         {
6350                 GL_BlendFunc(GL_ONE, GL_ZERO);
6351                 GL_DepthMask(true);
6352         }
6353         GL_DepthRange(0, (rsurface.ent_flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
6354         GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
6355         GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
6356         GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
6357         memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
6358         for (i = 0, c = color4f;i < 6;i++, c += 4)
6359         {
6360                 c[0] *= ent->render_fullbright[0] * r_refdef.view.colorscale;
6361                 c[1] *= ent->render_fullbright[1] * r_refdef.view.colorscale;
6362                 c[2] *= ent->render_fullbright[2] * r_refdef.view.colorscale;
6363                 c[3] *= ent->alpha;
6364         }
6365         if (r_refdef.fogenabled)
6366         {
6367                 for (i = 0, c = color4f;i < 6;i++, c += 4)
6368                 {
6369                         f1 = RSurf_FogVertex(nomodelvertex3f + 3*i);
6370                         f2 = 1 - f1;
6371                         c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
6372                         c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
6373                         c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
6374                 }
6375         }
6376 //      R_Mesh_ResetTextureState();
6377         R_SetupShader_Generic_NoTexture(false, false);
6378         R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
6379         R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
6380 }
6381
6382 void R_DrawNoModel(entity_render_t *ent)
6383 {
6384         vec3_t org;
6385         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
6386         if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1))
6387                 R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
6388         else
6389                 R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
6390 }
6391
6392 void R_CalcBeam_Vertex3f (float *vert, const float *org1, const float *org2, float width)
6393 {
6394         vec3_t right1, right2, diff, normal;
6395
6396         VectorSubtract (org2, org1, normal);
6397
6398         // calculate 'right' vector for start
6399         VectorSubtract (r_refdef.view.origin, org1, diff);
6400         CrossProduct (normal, diff, right1);
6401         VectorNormalize (right1);
6402
6403         // calculate 'right' vector for end
6404         VectorSubtract (r_refdef.view.origin, org2, diff);
6405         CrossProduct (normal, diff, right2);
6406         VectorNormalize (right2);
6407
6408         vert[ 0] = org1[0] + width * right1[0];
6409         vert[ 1] = org1[1] + width * right1[1];
6410         vert[ 2] = org1[2] + width * right1[2];
6411         vert[ 3] = org1[0] - width * right1[0];
6412         vert[ 4] = org1[1] - width * right1[1];
6413         vert[ 5] = org1[2] - width * right1[2];
6414         vert[ 6] = org2[0] - width * right2[0];
6415         vert[ 7] = org2[1] - width * right2[1];
6416         vert[ 8] = org2[2] - width * right2[2];
6417         vert[ 9] = org2[0] + width * right2[0];
6418         vert[10] = org2[1] + width * right2[1];
6419         vert[11] = org2[2] + width * right2[2];
6420 }
6421
6422 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)
6423 {
6424         vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
6425         vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
6426         vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
6427         vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
6428         vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
6429         vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
6430         vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
6431         vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
6432         vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
6433         vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
6434         vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
6435         vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
6436 }
6437
6438 static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
6439 {
6440         int i;
6441         float *vertex3f;
6442         float v[3];
6443         VectorSet(v, x, y, z);
6444         for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
6445                 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
6446                         break;
6447         if (i == mesh->numvertices)
6448         {
6449                 if (mesh->numvertices < mesh->maxvertices)
6450                 {
6451                         VectorCopy(v, vertex3f);
6452                         mesh->numvertices++;
6453                 }
6454                 return mesh->numvertices;
6455         }
6456         else
6457                 return i;
6458 }
6459
6460 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
6461 {
6462         int i;
6463         int *e, element[3];
6464         element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6465         element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6466         e = mesh->element3i + mesh->numtriangles * 3;
6467         for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
6468         {
6469                 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
6470                 if (mesh->numtriangles < mesh->maxtriangles)
6471                 {
6472                         *e++ = element[0];
6473                         *e++ = element[1];
6474                         *e++ = element[2];
6475                         mesh->numtriangles++;
6476                 }
6477                 element[1] = element[2];
6478         }
6479 }
6480
6481 static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
6482 {
6483         int i;
6484         int *e, element[3];
6485         element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6486         element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6487         e = mesh->element3i + mesh->numtriangles * 3;
6488         for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
6489         {
6490                 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
6491                 if (mesh->numtriangles < mesh->maxtriangles)
6492                 {
6493                         *e++ = element[0];
6494                         *e++ = element[1];
6495                         *e++ = element[2];
6496                         mesh->numtriangles++;
6497                 }
6498                 element[1] = element[2];
6499         }
6500 }
6501
6502 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
6503 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
6504 {
6505         int planenum, planenum2;
6506         int w;
6507         int tempnumpoints;
6508         mplane_t *plane, *plane2;
6509         double maxdist;
6510         double temppoints[2][256*3];
6511         // figure out how large a bounding box we need to properly compute this brush
6512         maxdist = 0;
6513         for (w = 0;w < numplanes;w++)
6514                 maxdist = max(maxdist, fabs(planes[w].dist));
6515         // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
6516         maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
6517         for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
6518         {
6519                 w = 0;
6520                 tempnumpoints = 4;
6521                 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
6522                 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
6523                 {
6524                         if (planenum2 == planenum)
6525                                 continue;
6526                         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);
6527                         w = !w;
6528                 }
6529                 if (tempnumpoints < 3)
6530                         continue;
6531                 // generate elements forming a triangle fan for this polygon
6532                 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
6533         }
6534 }
6535
6536 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)
6537 {
6538         texturelayer_t *layer;
6539         layer = t->currentlayers + t->currentnumlayers++;
6540         layer->type = type;
6541         layer->depthmask = depthmask;
6542         layer->blendfunc1 = blendfunc1;
6543         layer->blendfunc2 = blendfunc2;
6544         layer->texture = texture;
6545         layer->texmatrix = *matrix;
6546         layer->color[0] = r;
6547         layer->color[1] = g;
6548         layer->color[2] = b;
6549         layer->color[3] = a;
6550 }
6551
6552 static qboolean R_TestQ3WaveFunc(q3wavefunc_t func, const float *parms)
6553 {
6554         if(parms[0] == 0 && parms[1] == 0)
6555                 return false;
6556         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6557                 if(rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)] == 0)
6558                         return false;
6559         return true;
6560 }
6561
6562 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
6563 {
6564         double index, f;
6565         index = parms[2] + rsurface.shadertime * parms[3];
6566         index -= floor(index);
6567         switch (func & ((1 << Q3WAVEFUNC_USER_SHIFT) - 1))
6568         {
6569         default:
6570         case Q3WAVEFUNC_NONE:
6571         case Q3WAVEFUNC_NOISE:
6572         case Q3WAVEFUNC_COUNT:
6573                 f = 0;
6574                 break;
6575         case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
6576         case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
6577         case Q3WAVEFUNC_SAWTOOTH: f = index;break;
6578         case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
6579         case Q3WAVEFUNC_TRIANGLE:
6580                 index *= 4;
6581                 f = index - floor(index);
6582                 if (index < 1)
6583                 {
6584                         // f = f;
6585                 }
6586                 else if (index < 2)
6587                         f = 1 - f;
6588                 else if (index < 3)
6589                         f = -f;
6590                 else
6591                         f = -(1 - f);
6592                 break;
6593         }
6594         f = parms[0] + parms[1] * f;
6595         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6596                 f *= rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)];
6597         return (float) f;
6598 }
6599
6600 static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
6601 {
6602         int w, h, idx;
6603         float shadertime;
6604         float f;
6605         float offsetd[2];
6606         float tcmat[12];
6607         matrix4x4_t matrix, temp;
6608         // if shadertime exceeds about 9 hours (32768 seconds), just wrap it,
6609         // it's better to have one huge fixup every 9 hours than gradual
6610         // degradation over time which looks consistently bad after many hours.
6611         //
6612         // tcmod scroll in particular suffers from this degradation which can't be
6613         // effectively worked around even with floor() tricks because we don't
6614         // know if tcmod scroll is the last tcmod being applied, and for clampmap
6615         // a workaround involving floor() would be incorrect anyway...
6616         shadertime = rsurface.shadertime;
6617         if (shadertime >= 32768.0f)
6618                 shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f;
6619         switch(tcmod->tcmod)
6620         {
6621                 case Q3TCMOD_COUNT:
6622                 case Q3TCMOD_NONE:
6623                         if (currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6624                                 matrix = r_waterscrollmatrix;
6625                         else
6626                                 matrix = identitymatrix;
6627                         break;
6628                 case Q3TCMOD_ENTITYTRANSLATE:
6629                         // this is used in Q3 to allow the gamecode to control texcoord
6630                         // scrolling on the entity, which is not supported in darkplaces yet.
6631                         Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
6632                         break;
6633                 case Q3TCMOD_ROTATE:
6634                         Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
6635                         Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
6636                         Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
6637                         break;
6638                 case Q3TCMOD_SCALE:
6639                         Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
6640                         break;
6641                 case Q3TCMOD_SCROLL:
6642                         // this particular tcmod is a "bug for bug" compatible one with regards to
6643                         // Quake3, the wrapping is unnecessary with our shadetime fix but quake3
6644                         // specifically did the wrapping and so we must mimic that...
6645                         offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
6646                         offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
6647                         Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
6648                         break;
6649                 case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
6650                         w = (int) tcmod->parms[0];
6651                         h = (int) tcmod->parms[1];
6652                         f = rsurface.shadertime / (tcmod->parms[2] * w * h);
6653                         f = f - floor(f);
6654                         idx = (int) floor(f * w * h);
6655                         Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
6656                         break;
6657                 case Q3TCMOD_STRETCH:
6658                         f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
6659                         Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
6660                         break;
6661                 case Q3TCMOD_TRANSFORM:
6662                         VectorSet(tcmat +  0, tcmod->parms[0], tcmod->parms[1], 0);
6663                         VectorSet(tcmat +  3, tcmod->parms[2], tcmod->parms[3], 0);
6664                         VectorSet(tcmat +  6, 0                   , 0                , 1);
6665                         VectorSet(tcmat +  9, tcmod->parms[4], tcmod->parms[5], 0);
6666                         Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
6667                         break;
6668                 case Q3TCMOD_TURBULENT:
6669                         // this is handled in the RSurf_PrepareVertices function
6670                         matrix = identitymatrix;
6671                         break;
6672         }
6673         temp = *texmatrix;
6674         Matrix4x4_Concat(texmatrix, &matrix, &temp);
6675 }
6676
6677 static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
6678 {
6679         int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP;
6680         char name[MAX_QPATH];
6681         skinframe_t *skinframe;
6682         unsigned char pixels[296*194];
6683         strlcpy(cache->name, skinname, sizeof(cache->name));
6684         dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name);
6685         if (developer_loading.integer)
6686                 Con_Printf("loading %s\n", name);
6687         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
6688         if (!skinframe || !skinframe->base)
6689         {
6690                 unsigned char *f;
6691                 fs_offset_t filesize;
6692                 skinframe = NULL;
6693                 f = FS_LoadFile(name, tempmempool, true, &filesize);
6694                 if (f)
6695                 {
6696                         if (LoadPCX_QWSkin(f, (int)filesize, pixels, 296, 194))
6697                                 skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
6698                         Mem_Free(f);
6699                 }
6700         }
6701         cache->skinframe = skinframe;
6702 }
6703
6704 texture_t *R_GetCurrentTexture(texture_t *t)
6705 {
6706         int i, q;
6707         const entity_render_t *ent = rsurface.entity;
6708         dp_model_t *model = ent->model; // when calling this, ent must not be NULL
6709         q3shaderinfo_layer_tcmod_t *tcmod;
6710         float specularscale = 0.0f;
6711
6712         if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate)
6713                 return t->currentframe;
6714         t->update_lastrenderframe = r_textureframe;
6715         t->update_lastrenderentity = (void *)ent;
6716
6717         if(ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS)
6718                 t->camera_entity = ent->entitynumber;
6719         else
6720                 t->camera_entity = 0;
6721
6722         // switch to an alternate material if this is a q1bsp animated material
6723         {
6724                 texture_t *texture = t;
6725                 int s = rsurface.ent_skinnum;
6726                 if ((unsigned int)s >= (unsigned int)model->numskins)
6727                         s = 0;
6728                 if (model->skinscenes)
6729                 {
6730                         if (model->skinscenes[s].framecount > 1)
6731                                 s = model->skinscenes[s].firstframe + (unsigned int) (rsurface.shadertime * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
6732                         else
6733                                 s = model->skinscenes[s].firstframe;
6734                 }
6735                 if (s > 0)
6736                         t = t + s * model->num_surfaces;
6737                 if (t->animated)
6738                 {
6739                         // use an alternate animation if the entity's frame is not 0,
6740                         // and only if the texture has an alternate animation
6741                         if (t->animated == 2) // q2bsp
6742                                 t = t->anim_frames[0][ent->framegroupblend[0].frame % t->anim_total[0]];
6743                         else if (rsurface.ent_alttextures && t->anim_total[1])
6744                                 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
6745                         else
6746                                 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
6747                 }
6748                 texture->currentframe = t;
6749         }
6750
6751         // update currentskinframe to be a qw skin or animation frame
6752         if (rsurface.ent_qwskin >= 0)
6753         {
6754                 i = rsurface.ent_qwskin;
6755                 if (!r_qwskincache || r_qwskincache_size != cl.maxclients)
6756                 {
6757                         r_qwskincache_size = cl.maxclients;
6758                         if (r_qwskincache)
6759                                 Mem_Free(r_qwskincache);
6760                         r_qwskincache = (r_qwskincache_t *)Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size);
6761                 }
6762                 if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
6763                         R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
6764                 t->currentskinframe = r_qwskincache[i].skinframe;
6765                 if (t->materialshaderpass && t->currentskinframe == NULL)
6766                         t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6767         }
6768         else if (t->materialshaderpass && t->materialshaderpass->numframes >= 2)
6769                 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6770         if (t->backgroundshaderpass && t->backgroundshaderpass->numframes >= 2)
6771                 t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
6772
6773         t->currentmaterialflags = t->basematerialflags;
6774         t->currentalpha = rsurface.entity->alpha * t->basealpha;
6775         if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_novis.integer || r_trippy.integer))
6776                 t->currentalpha *= r_wateralpha.value;
6777         if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay)
6778                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later
6779         if(!r_fb.water.enabled || r_refdef.view.isoverlay)
6780                 t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA);
6781
6782         // decide on which type of lighting to use for this surface
6783         if (rsurface.entity->render_modellight_forced)
6784                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6785         if (rsurface.entity->render_rtlight_disabled)
6786                 t->currentmaterialflags |= MATERIALFLAG_NORTLIGHT;
6787         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND && !(R_BlendFuncFlags(t->customblendfunc[0], t->customblendfunc[1]) & BLENDFUNC_ALLOWS_COLORMOD))
6788         {
6789                 // some CUSTOMBLEND blendfuncs are too weird, we have to ignore colormod and view colorscale
6790                 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_NORTLIGHT;
6791                 for (q = 0; q < 3; q++)
6792                 {
6793                         t->render_glowmod[q] = rsurface.entity->glowmod[q];
6794                         t->render_modellight_lightdir[q] = q == 2;
6795                         t->render_modellight_ambient[q] = 1;
6796                         t->render_modellight_diffuse[q] = 0;
6797                         t->render_modellight_specular[q] = 0;
6798                         t->render_lightmap_ambient[q] = 0;
6799                         t->render_lightmap_diffuse[q] = 0;
6800                         t->render_lightmap_specular[q] = 0;
6801                         t->render_rtlight_diffuse[q] = 0;
6802                         t->render_rtlight_specular[q] = 0;
6803                 }
6804         }
6805         else if ((t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !(rsurface.ent_flags & RENDER_LIGHT))
6806         {
6807                 // fullbright is basically MATERIALFLAG_MODELLIGHT but with ambient locked to 1,1,1 and no shading
6808                 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_NORTLIGHT | MATERIALFLAG_MODELLIGHT;
6809                 for (q = 0; q < 3; q++)
6810                 {
6811                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6812                         t->render_modellight_ambient[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6813                         t->render_modellight_lightdir[q] = q == 2;
6814                         t->render_modellight_diffuse[q] = 0;
6815                         t->render_modellight_specular[q] = 0;
6816                         t->render_lightmap_ambient[q] = 0;
6817                         t->render_lightmap_diffuse[q] = 0;
6818                         t->render_lightmap_specular[q] = 0;
6819                         t->render_rtlight_diffuse[q] = 0;
6820                         t->render_rtlight_specular[q] = 0;
6821                 }
6822         }
6823         else if (FAKELIGHT_ENABLED)
6824         {
6825                 // no modellight if using fakelight for the map
6826                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_NORTLIGHT) & ~(MATERIALFLAG_MODELLIGHT);
6827                 for (q = 0; q < 3; q++)
6828                 {
6829                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6830                         t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6831                         t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6832                         t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6833                         t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6834                         t->render_lightmap_ambient[q] = 0;
6835                         t->render_lightmap_diffuse[q] = 0;
6836                         t->render_lightmap_specular[q] = 0;
6837                         t->render_rtlight_diffuse[q] = 0;
6838                         t->render_rtlight_specular[q] = 0;
6839                 }
6840         }
6841         else if ((rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT)) || rsurface.modeltexcoordlightmap2f == NULL)
6842         {
6843                 // ambient + single direction light (modellight)
6844                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6845                 for (q = 0; q < 3; q++)
6846                 {
6847                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6848                         t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6849                         t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6850                         t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6851                         t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6852                         t->render_lightmap_ambient[q] = 0;
6853                         t->render_lightmap_diffuse[q] = 0;
6854                         t->render_lightmap_specular[q] = 0;
6855                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6856                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6857                 }
6858         }
6859         else
6860         {
6861                 // lightmap - 2x diffuse and specular brightness because bsp files have 0-2 colors as 0-1
6862                 for (q = 0; q < 3; q++)
6863                 {
6864                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6865                         t->render_modellight_lightdir[q] = q == 2;
6866                         t->render_modellight_ambient[q] = 0;
6867                         t->render_modellight_diffuse[q] = 0;
6868                         t->render_modellight_specular[q] = 0;
6869                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6870                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6871                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6872                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6873                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6874                 }
6875         }
6876
6877         if (t->currentmaterialflags & MATERIALFLAG_VERTEXCOLOR)
6878         {
6879                 // since MATERIALFLAG_VERTEXCOLOR uses the lightmapcolor4f vertex
6880                 // attribute, we punt it to the lightmap path and hope for the best,
6881                 // but lighting doesn't work.
6882                 //
6883                 // FIXME: this is fine for effects but CSQC polygons should be subject
6884                 // to lighting.
6885                 t->currentmaterialflags &= ~MATERIALFLAG_MODELLIGHT;
6886                 for (q = 0; q < 3; q++)
6887                 {
6888                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6889                         t->render_modellight_lightdir[q] = q == 2;
6890                         t->render_modellight_ambient[q] = 0;
6891                         t->render_modellight_diffuse[q] = 0;
6892                         t->render_modellight_specular[q] = 0;
6893                         t->render_lightmap_ambient[q] = 0;
6894                         t->render_lightmap_diffuse[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6895                         t->render_lightmap_specular[q] = 0;
6896                         t->render_rtlight_diffuse[q] = 0;
6897                         t->render_rtlight_specular[q] = 0;
6898                 }
6899         }
6900
6901         for (q = 0; q < 3; q++)
6902         {
6903                 t->render_colormap_pants[q] = rsurface.entity->colormap_pantscolor[q];
6904                 t->render_colormap_shirt[q] = rsurface.entity->colormap_shirtcolor[q];
6905         }
6906
6907         if (rsurface.ent_flags & RENDER_ADDITIVE)
6908                 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6909         else if (t->currentalpha < 1)
6910                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6911         // LordHavoc: prevent bugs where code checks add or alpha at higher priority than customblend by clearing these flags
6912         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6913                 t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA);
6914         if (rsurface.ent_flags & RENDER_DOUBLESIDED)
6915                 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
6916         if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
6917                 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
6918         if (t->backgroundshaderpass)
6919                 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
6920         if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
6921         {
6922                 if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA))
6923                         t->currentmaterialflags &= ~MATERIALFLAG_BLENDED;
6924         }
6925         else
6926                 t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA);
6927         if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)))
6928         {
6929                 // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on
6930                 t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST;
6931         }
6932         if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
6933                 t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
6934
6935         // there is no tcmod
6936         if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6937         {
6938                 t->currenttexmatrix = r_waterscrollmatrix;
6939                 t->currentbackgroundtexmatrix = r_waterscrollmatrix;
6940         }
6941         else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE))
6942         {
6943                 Matrix4x4_CreateIdentity(&t->currenttexmatrix);
6944                 Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
6945         }
6946
6947         if (t->materialshaderpass)
6948                 for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
6949                         R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
6950
6951         t->colormapping = VectorLength2(t->render_colormap_pants) + VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f);
6952         if (t->currentskinframe->qpixels)
6953                 R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
6954         t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
6955         if (!t->basetexture)
6956                 t->basetexture = r_texture_notexture;
6957         t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
6958         t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
6959         t->nmaptexture = t->currentskinframe->nmap;
6960         if (!t->nmaptexture)
6961                 t->nmaptexture = r_texture_blanknormalmap;
6962         t->glosstexture = r_texture_black;
6963         t->glowtexture = t->currentskinframe->glow;
6964         t->fogtexture = t->currentskinframe->fog;
6965         t->reflectmasktexture = t->currentskinframe->reflect;
6966         if (t->backgroundshaderpass)
6967         {
6968                 for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
6969                         R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
6970                 t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
6971                 t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
6972                 t->backgroundglosstexture = r_texture_black;
6973                 t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
6974                 if (!t->backgroundnmaptexture)
6975                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6976                 // make sure that if glow is going to be used, both textures are not NULL
6977                 if (!t->backgroundglowtexture && t->glowtexture)
6978                         t->backgroundglowtexture = r_texture_black;
6979                 if (!t->glowtexture && t->backgroundglowtexture)
6980                         t->glowtexture = r_texture_black;
6981         }
6982         else
6983         {
6984                 t->backgroundbasetexture = r_texture_white;
6985                 t->backgroundnmaptexture = r_texture_blanknormalmap;
6986                 t->backgroundglosstexture = r_texture_black;
6987                 t->backgroundglowtexture = NULL;
6988         }
6989         t->specularpower = r_shadow_glossexponent.value;
6990         // TODO: store reference values for these in the texture?
6991         if (r_shadow_gloss.integer > 0)
6992         {
6993                 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
6994                 {
6995                         if (r_shadow_glossintensity.value > 0)
6996                         {
6997                                 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
6998                                 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
6999                                 specularscale = r_shadow_glossintensity.value;
7000                         }
7001                 }
7002                 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
7003                 {
7004                         t->glosstexture = r_texture_white;
7005                         t->backgroundglosstexture = r_texture_white;
7006                         specularscale = r_shadow_gloss2intensity.value;
7007                         t->specularpower = r_shadow_gloss2exponent.value;
7008                 }
7009         }
7010         specularscale *= t->specularscalemod;
7011         t->specularpower *= t->specularpowermod;
7012
7013         // lightmaps mode looks bad with dlights using actual texturing, so turn
7014         // off the colormap and glossmap, but leave the normalmap on as it still
7015         // accurately represents the shading involved
7016         if (gl_lightmaps.integer)
7017         {
7018                 t->basetexture = r_texture_grey128;
7019                 t->pantstexture = r_texture_black;
7020                 t->shirttexture = r_texture_black;
7021                 if (gl_lightmaps.integer < 2)
7022                         t->nmaptexture = r_texture_blanknormalmap;
7023                 t->glosstexture = r_texture_black;
7024                 t->glowtexture = NULL;
7025                 t->fogtexture = NULL;
7026                 t->reflectmasktexture = NULL;
7027                 t->backgroundbasetexture = NULL;
7028                 if (gl_lightmaps.integer < 2)
7029                         t->backgroundnmaptexture = r_texture_blanknormalmap;
7030                 t->backgroundglosstexture = r_texture_black;
7031                 t->backgroundglowtexture = NULL;
7032                 specularscale = 0;
7033                 t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
7034         }
7035
7036         if (specularscale != 1.0f)
7037         {
7038                 for (q = 0; q < 3; q++)
7039                 {
7040                         t->render_modellight_specular[q] *= specularscale;
7041                         t->render_lightmap_specular[q] *= specularscale;
7042                         t->render_rtlight_specular[q] *= specularscale;
7043                 }
7044         }
7045
7046         t->currentnumlayers = 0;
7047         if (t->currentmaterialflags & MATERIALFLAG_WALL)
7048         {
7049                 int blendfunc1, blendfunc2;
7050                 qboolean depthmask;
7051                 if (t->currentmaterialflags & MATERIALFLAG_ADD)
7052                 {
7053                         blendfunc1 = GL_SRC_ALPHA;
7054                         blendfunc2 = GL_ONE;
7055                 }
7056                 else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
7057                 {
7058                         blendfunc1 = GL_SRC_ALPHA;
7059                         blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
7060                 }
7061                 else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
7062                 {
7063                         blendfunc1 = t->customblendfunc[0];
7064                         blendfunc2 = t->customblendfunc[1];
7065                 }
7066                 else
7067                 {
7068                         blendfunc1 = GL_ONE;
7069                         blendfunc2 = GL_ZERO;
7070                 }
7071                 depthmask = !(t->currentmaterialflags & MATERIALFLAG_BLENDED);
7072                 if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
7073                 {
7074                         // basic lit geometry
7075                         R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE, t->basetexture, &t->currenttexmatrix, 2, 2, 2, t->currentalpha);
7076                         // add pants/shirt if needed
7077                         if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7078                                 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);
7079                         if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7080                                 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);
7081                 }
7082                 else
7083                 {
7084                         // basic lit geometry
7085                         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);
7086                         // add pants/shirt if needed
7087                         if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7088                                 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->pantstexture, &t->currenttexmatrix, 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);
7089                         if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7090                                 R_Texture_AddLayer(t, false, GL_SRC_ALPHA, GL_ONE, TEXTURELAYERTYPE_LITTEXTURE, t->shirttexture, &t->currenttexmatrix, 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);
7091                         // now add ambient passes if needed
7092                         if (VectorLength2(t->render_lightmap_ambient) >= (1.0f/1048576.0f))
7093                         {
7094                                 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);
7095                                 if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7096                                         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);
7097                                 if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7098                                         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);
7099                         }
7100                 }
7101                 if (t->glowtexture != NULL && !gl_lightmaps.integer)
7102                         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);
7103                 if (r_refdef.fogenabled && !(t->currentmaterialflags & MATERIALFLAG_ADD))
7104                 {
7105                         // if this is opaque use alpha blend which will darken the earlier
7106                         // passes cheaply.
7107                         //
7108                         // if this is an alpha blended material, all the earlier passes
7109                         // were darkened by fog already, so we only need to add the fog
7110                         // color ontop through the fog mask texture
7111                         //
7112                         // if this is an additive blended material, all the earlier passes
7113                         // were darkened by fog already, and we should not add fog color
7114                         // (because the background was not darkened, there is no fog color
7115                         // that was lost behind it).
7116                         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);
7117                 }
7118         }
7119
7120         return t;
7121 }
7122
7123 rsurfacestate_t rsurface;
7124
7125 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass)
7126 {
7127         dp_model_t *model = ent->model;
7128         //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
7129         //      return;
7130         rsurface.entity = (entity_render_t *)ent;
7131         rsurface.skeleton = ent->skeleton;
7132         memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
7133         rsurface.ent_skinnum = ent->skinnum;
7134         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;
7135         rsurface.ent_flags = ent->flags;
7136         if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
7137                 rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
7138         rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
7139         rsurface.matrix = ent->matrix;
7140         rsurface.inversematrix = ent->inversematrix;
7141         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7142         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7143         R_EntityMatrix(&rsurface.matrix);
7144         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7145         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7146         rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist * rsurface.inversematrixscale;
7147         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7148         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7149         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7150         memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
7151         rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
7152         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7153         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7154         if (ent->model->brush.submodel && !prepass)
7155         {
7156                 rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
7157                 rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
7158         }
7159         // if the animcache code decided it should use the shader path, skip the deform step
7160         rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4;
7161         rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer;
7162         rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset;
7163         rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size;
7164         rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0;
7165         if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4)
7166         {
7167                 if (ent->animcache_vertex3f)
7168                 {
7169                         r_refdef.stats[r_stat_batch_entitycache_count]++;
7170                         r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
7171                         r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
7172                         r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
7173                         rsurface.modelvertex3f = ent->animcache_vertex3f;
7174                         rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer;
7175                         rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset;
7176                         rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
7177                         rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL;
7178                         rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0;
7179                         rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
7180                         rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL;
7181                         rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0;
7182                         rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
7183                         rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL;
7184                         rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0;
7185                         rsurface.modelvertexmesh = ent->animcache_vertexmesh;
7186                         rsurface.modelvertexmesh_vertexbuffer = ent->animcache_vertexmesh_vertexbuffer;
7187                         rsurface.modelvertexmesh_bufferoffset = ent->animcache_vertexmesh_bufferoffset;
7188                 }
7189                 else if (wanttangents)
7190                 {
7191                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7192                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7193                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7194                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7195                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7196                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7197                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7198                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7199                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f);
7200                         rsurface.modelvertexmesh = NULL;
7201                         rsurface.modelvertexmesh_vertexbuffer = NULL;
7202                         rsurface.modelvertexmesh_bufferoffset = 0;
7203                         rsurface.modelvertex3f_vertexbuffer = NULL;
7204                         rsurface.modelvertex3f_bufferoffset = 0;
7205                         rsurface.modelvertex3f_vertexbuffer = 0;
7206                         rsurface.modelvertex3f_bufferoffset = 0;
7207                         rsurface.modelsvector3f_vertexbuffer = 0;
7208                         rsurface.modelsvector3f_bufferoffset = 0;
7209                         rsurface.modeltvector3f_vertexbuffer = 0;
7210                         rsurface.modeltvector3f_bufferoffset = 0;
7211                         rsurface.modelnormal3f_vertexbuffer = 0;
7212                         rsurface.modelnormal3f_bufferoffset = 0;
7213                 }
7214                 else if (wantnormals)
7215                 {
7216                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7217                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7218                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7219                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7220                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7221                         rsurface.modelsvector3f = NULL;
7222                         rsurface.modeltvector3f = NULL;
7223                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7224                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL);
7225                         rsurface.modelvertexmesh = NULL;
7226                         rsurface.modelvertexmesh_vertexbuffer = NULL;
7227                         rsurface.modelvertexmesh_bufferoffset = 0;
7228                         rsurface.modelvertex3f_vertexbuffer = NULL;
7229                         rsurface.modelvertex3f_bufferoffset = 0;
7230                         rsurface.modelvertex3f_vertexbuffer = 0;
7231                         rsurface.modelvertex3f_bufferoffset = 0;
7232                         rsurface.modelsvector3f_vertexbuffer = 0;
7233                         rsurface.modelsvector3f_bufferoffset = 0;
7234                         rsurface.modeltvector3f_vertexbuffer = 0;
7235                         rsurface.modeltvector3f_bufferoffset = 0;
7236                         rsurface.modelnormal3f_vertexbuffer = 0;
7237                         rsurface.modelnormal3f_bufferoffset = 0;
7238                 }
7239                 else
7240                 {
7241                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7242                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7243                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7244                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7245                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7246                         rsurface.modelsvector3f = NULL;
7247                         rsurface.modeltvector3f = NULL;
7248                         rsurface.modelnormal3f = NULL;
7249                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL);
7250                         rsurface.modelvertexmesh = NULL;
7251                         rsurface.modelvertexmesh_vertexbuffer = NULL;
7252                         rsurface.modelvertexmesh_bufferoffset = 0;
7253                         rsurface.modelvertex3f_vertexbuffer = NULL;
7254                         rsurface.modelvertex3f_bufferoffset = 0;
7255                         rsurface.modelvertex3f_vertexbuffer = 0;
7256                         rsurface.modelvertex3f_bufferoffset = 0;
7257                         rsurface.modelsvector3f_vertexbuffer = 0;
7258                         rsurface.modelsvector3f_bufferoffset = 0;
7259                         rsurface.modeltvector3f_vertexbuffer = 0;
7260                         rsurface.modeltvector3f_bufferoffset = 0;
7261                         rsurface.modelnormal3f_vertexbuffer = 0;
7262                         rsurface.modelnormal3f_bufferoffset = 0;
7263                 }
7264                 rsurface.modelgeneratedvertex = true;
7265         }
7266         else
7267         {
7268                 if (rsurface.entityskeletaltransform3x4)
7269                 {
7270                         r_refdef.stats[r_stat_batch_entityskeletal_count]++;
7271                         r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
7272                         r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
7273                         r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
7274                 }
7275                 else
7276                 {
7277                         r_refdef.stats[r_stat_batch_entitystatic_count]++;
7278                         r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
7279                         r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
7280                         r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
7281                 }
7282                 rsurface.modelvertex3f  = model->surfmesh.data_vertex3f;
7283                 rsurface.modelvertex3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7284                 rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f;
7285                 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
7286                 rsurface.modelsvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7287                 rsurface.modelsvector3f_bufferoffset = model->surfmesh.vbooffset_svector3f;
7288                 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
7289                 rsurface.modeltvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7290                 rsurface.modeltvector3f_bufferoffset = model->surfmesh.vbooffset_tvector3f;
7291                 rsurface.modelnormal3f  = model->surfmesh.data_normal3f;
7292                 rsurface.modelnormal3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7293                 rsurface.modelnormal3f_bufferoffset = model->surfmesh.vbooffset_normal3f;
7294                 rsurface.modelvertexmesh = model->surfmesh.data_vertexmesh;
7295                 rsurface.modelvertexmesh_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7296                 rsurface.modelvertexmesh_bufferoffset = model->surfmesh.vbooffset_vertex3f;
7297                 rsurface.modelgeneratedvertex = false;
7298         }
7299         rsurface.modellightmapcolor4f  = model->surfmesh.data_lightmapcolor4f;
7300         rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7301         rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.vbooffset_lightmapcolor4f;
7302         rsurface.modeltexcoordtexture2f  = model->surfmesh.data_texcoordtexture2f;
7303         rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7304         rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.vbooffset_texcoordtexture2f;
7305         rsurface.modeltexcoordlightmap2f  = model->surfmesh.data_texcoordlightmap2f;
7306         rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7307         rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f;
7308         rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
7309         rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7310         rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.vbooffset_skeletalindex4ub;
7311         rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
7312         rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7313         rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.vbooffset_skeletalweight4ub;
7314         rsurface.modelelement3i = model->surfmesh.data_element3i;
7315         rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
7316         rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
7317         rsurface.modelelement3s = model->surfmesh.data_element3s;
7318         rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
7319         rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
7320         rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
7321         rsurface.modelnumvertices = model->surfmesh.num_vertices;
7322         rsurface.modelnumtriangles = model->surfmesh.num_triangles;
7323         rsurface.modelsurfaces = model->data_surfaces;
7324         rsurface.batchgeneratedvertex = false;
7325         rsurface.batchfirstvertex = 0;
7326         rsurface.batchnumvertices = 0;
7327         rsurface.batchfirsttriangle = 0;
7328         rsurface.batchnumtriangles = 0;
7329         rsurface.batchvertex3f  = NULL;
7330         rsurface.batchvertex3f_vertexbuffer = NULL;
7331         rsurface.batchvertex3f_bufferoffset = 0;
7332         rsurface.batchsvector3f = NULL;
7333         rsurface.batchsvector3f_vertexbuffer = NULL;
7334         rsurface.batchsvector3f_bufferoffset = 0;
7335         rsurface.batchtvector3f = NULL;
7336         rsurface.batchtvector3f_vertexbuffer = NULL;
7337         rsurface.batchtvector3f_bufferoffset = 0;
7338         rsurface.batchnormal3f  = NULL;
7339         rsurface.batchnormal3f_vertexbuffer = NULL;
7340         rsurface.batchnormal3f_bufferoffset = 0;
7341         rsurface.batchlightmapcolor4f = NULL;
7342         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7343         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7344         rsurface.batchtexcoordtexture2f = NULL;
7345         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7346         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7347         rsurface.batchtexcoordlightmap2f = NULL;
7348         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7349         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7350         rsurface.batchskeletalindex4ub = NULL;
7351         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7352         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7353         rsurface.batchskeletalweight4ub = NULL;
7354         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7355         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7356         rsurface.batchvertexmesh = NULL;
7357         rsurface.batchvertexmesh_vertexbuffer = NULL;
7358         rsurface.batchvertexmesh_bufferoffset = 0;
7359         rsurface.batchelement3i = NULL;
7360         rsurface.batchelement3i_indexbuffer = NULL;
7361         rsurface.batchelement3i_bufferoffset = 0;
7362         rsurface.batchelement3s = NULL;
7363         rsurface.batchelement3s_indexbuffer = NULL;
7364         rsurface.batchelement3s_bufferoffset = 0;
7365         rsurface.forcecurrenttextureupdate = false;
7366 }
7367
7368 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)
7369 {
7370         rsurface.entity = r_refdef.scene.worldentity;
7371         rsurface.skeleton = NULL;
7372         rsurface.ent_skinnum = 0;
7373         rsurface.ent_qwskin = -1;
7374         rsurface.ent_flags = entflags;
7375         rsurface.shadertime = r_refdef.scene.time - shadertime;
7376         rsurface.modelnumvertices = numvertices;
7377         rsurface.modelnumtriangles = numtriangles;
7378         rsurface.matrix = *matrix;
7379         rsurface.inversematrix = *inversematrix;
7380         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7381         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7382         R_EntityMatrix(&rsurface.matrix);
7383         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7384         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7385         rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
7386         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7387         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7388         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7389         memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
7390         rsurface.frameblend[0].lerp = 1;
7391         rsurface.ent_alttextures = false;
7392         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7393         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7394         rsurface.entityskeletaltransform3x4 = NULL;
7395         rsurface.entityskeletaltransform3x4buffer = NULL;
7396         rsurface.entityskeletaltransform3x4offset = 0;
7397         rsurface.entityskeletaltransform3x4size = 0;
7398         rsurface.entityskeletalnumtransforms = 0;
7399         r_refdef.stats[r_stat_batch_entitycustom_count]++;
7400         r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
7401         r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
7402         r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
7403         if (wanttangents)
7404         {
7405                 rsurface.modelvertex3f = (float *)vertex3f;
7406                 rsurface.modelsvector3f = svector3f ? (float *)svector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7407                 rsurface.modeltvector3f = tvector3f ? (float *)tvector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7408                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7409         }
7410         else if (wantnormals)
7411         {
7412                 rsurface.modelvertex3f = (float *)vertex3f;
7413                 rsurface.modelsvector3f = NULL;
7414                 rsurface.modeltvector3f = NULL;
7415                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7416         }
7417         else
7418         {
7419                 rsurface.modelvertex3f = (float *)vertex3f;
7420                 rsurface.modelsvector3f = NULL;
7421                 rsurface.modeltvector3f = NULL;
7422                 rsurface.modelnormal3f = NULL;
7423         }
7424         rsurface.modelvertexmesh = NULL;
7425         rsurface.modelvertexmesh_vertexbuffer = NULL;
7426         rsurface.modelvertexmesh_bufferoffset = 0;
7427         rsurface.modelvertex3f_vertexbuffer = 0;
7428         rsurface.modelvertex3f_bufferoffset = 0;
7429         rsurface.modelsvector3f_vertexbuffer = 0;
7430         rsurface.modelsvector3f_bufferoffset = 0;
7431         rsurface.modeltvector3f_vertexbuffer = 0;
7432         rsurface.modeltvector3f_bufferoffset = 0;
7433         rsurface.modelnormal3f_vertexbuffer = 0;
7434         rsurface.modelnormal3f_bufferoffset = 0;
7435         rsurface.modelgeneratedvertex = true;
7436         rsurface.modellightmapcolor4f  = (float *)color4f;
7437         rsurface.modellightmapcolor4f_vertexbuffer = 0;
7438         rsurface.modellightmapcolor4f_bufferoffset = 0;
7439         rsurface.modeltexcoordtexture2f  = (float *)texcoord2f;
7440         rsurface.modeltexcoordtexture2f_vertexbuffer = 0;
7441         rsurface.modeltexcoordtexture2f_bufferoffset = 0;
7442         rsurface.modeltexcoordlightmap2f  = NULL;
7443         rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
7444         rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
7445         rsurface.modelskeletalindex4ub = NULL;
7446         rsurface.modelskeletalindex4ub_vertexbuffer = NULL;
7447         rsurface.modelskeletalindex4ub_bufferoffset = 0;
7448         rsurface.modelskeletalweight4ub = NULL;
7449         rsurface.modelskeletalweight4ub_vertexbuffer = NULL;
7450         rsurface.modelskeletalweight4ub_bufferoffset = 0;
7451         rsurface.modelelement3i = (int *)element3i;
7452         rsurface.modelelement3i_indexbuffer = NULL;
7453         rsurface.modelelement3i_bufferoffset = 0;
7454         rsurface.modelelement3s = (unsigned short *)element3s;
7455         rsurface.modelelement3s_indexbuffer = NULL;
7456         rsurface.modelelement3s_bufferoffset = 0;
7457         rsurface.modellightmapoffsets = NULL;
7458         rsurface.modelsurfaces = NULL;
7459         rsurface.batchgeneratedvertex = false;
7460         rsurface.batchfirstvertex = 0;
7461         rsurface.batchnumvertices = 0;
7462         rsurface.batchfirsttriangle = 0;
7463         rsurface.batchnumtriangles = 0;
7464         rsurface.batchvertex3f  = NULL;
7465         rsurface.batchvertex3f_vertexbuffer = NULL;
7466         rsurface.batchvertex3f_bufferoffset = 0;
7467         rsurface.batchsvector3f = NULL;
7468         rsurface.batchsvector3f_vertexbuffer = NULL;
7469         rsurface.batchsvector3f_bufferoffset = 0;
7470         rsurface.batchtvector3f = NULL;
7471         rsurface.batchtvector3f_vertexbuffer = NULL;
7472         rsurface.batchtvector3f_bufferoffset = 0;
7473         rsurface.batchnormal3f  = NULL;
7474         rsurface.batchnormal3f_vertexbuffer = NULL;
7475         rsurface.batchnormal3f_bufferoffset = 0;
7476         rsurface.batchlightmapcolor4f = NULL;
7477         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7478         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7479         rsurface.batchtexcoordtexture2f = NULL;
7480         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7481         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7482         rsurface.batchtexcoordlightmap2f = NULL;
7483         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7484         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7485         rsurface.batchskeletalindex4ub = NULL;
7486         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7487         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7488         rsurface.batchskeletalweight4ub = NULL;
7489         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7490         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7491         rsurface.batchvertexmesh = NULL;
7492         rsurface.batchvertexmesh_vertexbuffer = NULL;
7493         rsurface.batchvertexmesh_bufferoffset = 0;
7494         rsurface.batchelement3i = NULL;
7495         rsurface.batchelement3i_indexbuffer = NULL;
7496         rsurface.batchelement3i_bufferoffset = 0;
7497         rsurface.batchelement3s = NULL;
7498         rsurface.batchelement3s_indexbuffer = NULL;
7499         rsurface.batchelement3s_bufferoffset = 0;
7500         rsurface.forcecurrenttextureupdate = true;
7501
7502         if (rsurface.modelnumvertices && rsurface.modelelement3i)
7503         {
7504                 if ((wantnormals || wanttangents) && !normal3f)
7505                 {
7506                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7507                         Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
7508                 }
7509                 if (wanttangents && !svector3f)
7510                 {
7511                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7512                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7513                         Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.modelsvector3f, rsurface.modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
7514                 }
7515         }
7516 }
7517
7518 float RSurf_FogPoint(const float *v)
7519 {
7520         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7521         float FogPlaneViewDist = r_refdef.fogplaneviewdist;
7522         float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3];
7523         float FogHeightFade = r_refdef.fogheightfade;
7524         float fogfrac;
7525         unsigned int fogmasktableindex;
7526         if (r_refdef.fogplaneviewabove)
7527                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7528         else
7529                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7530         fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier);
7531         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7532 }
7533
7534 float RSurf_FogVertex(const float *v)
7535 {
7536         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7537         float FogPlaneViewDist = rsurface.fogplaneviewdist;
7538         float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3];
7539         float FogHeightFade = rsurface.fogheightfade;
7540         float fogfrac;
7541         unsigned int fogmasktableindex;
7542         if (r_refdef.fogplaneviewabove)
7543                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7544         else
7545                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7546         fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.fogmasktabledistmultiplier);
7547         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7548 }
7549
7550 static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
7551 {
7552         int i;
7553         for (i = 0;i < numelements;i++)
7554                 outelement3i[i] = inelement3i[i] + adjust;
7555 }
7556
7557 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
7558 extern cvar_t gl_vbo;
7559 void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist)
7560 {
7561         int deformindex;
7562         int firsttriangle;
7563         int numtriangles;
7564         int firstvertex;
7565         int endvertex;
7566         int numvertices;
7567         int surfacefirsttriangle;
7568         int surfacenumtriangles;
7569         int surfacefirstvertex;
7570         int surfaceendvertex;
7571         int surfacenumvertices;
7572         int batchnumsurfaces = texturenumsurfaces;
7573         int batchnumvertices;
7574         int batchnumtriangles;
7575         int needsupdate;
7576         int i, j;
7577         qboolean gaps;
7578         qboolean dynamicvertex;
7579         float amplitude;
7580         float animpos;
7581         float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
7582         float waveparms[4];
7583         unsigned char *ub;
7584         q3shaderinfo_deform_t *deform;
7585         const msurface_t *surface, *firstsurface;
7586         r_vertexmesh_t *vertexmesh;
7587         if (!texturenumsurfaces)
7588                 return;
7589         // find vertex range of this surface batch
7590         gaps = false;
7591         firstsurface = texturesurfacelist[0];
7592         firsttriangle = firstsurface->num_firsttriangle;
7593         batchnumvertices = 0;
7594         batchnumtriangles = 0;
7595         firstvertex = endvertex = firstsurface->num_firstvertex;
7596         for (i = 0;i < texturenumsurfaces;i++)
7597         {
7598                 surface = texturesurfacelist[i];
7599                 if (surface != firstsurface + i)
7600                         gaps = true;
7601                 surfacefirstvertex = surface->num_firstvertex;
7602                 surfaceendvertex = surfacefirstvertex + surface->num_vertices;
7603                 surfacenumvertices = surface->num_vertices;
7604                 surfacenumtriangles = surface->num_triangles;
7605                 if (firstvertex > surfacefirstvertex)
7606                         firstvertex = surfacefirstvertex;
7607                 if (endvertex < surfaceendvertex)
7608                         endvertex = surfaceendvertex;
7609                 batchnumvertices += surfacenumvertices;
7610                 batchnumtriangles += surfacenumtriangles;
7611         }
7612
7613         r_refdef.stats[r_stat_batch_batches]++;
7614         if (gaps)
7615                 r_refdef.stats[r_stat_batch_withgaps]++;
7616         r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces;
7617         r_refdef.stats[r_stat_batch_vertices] += batchnumvertices;
7618         r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles;
7619
7620         // we now know the vertex range used, and if there are any gaps in it
7621         rsurface.batchfirstvertex = firstvertex;
7622         rsurface.batchnumvertices = endvertex - firstvertex;
7623         rsurface.batchfirsttriangle = firsttriangle;
7624         rsurface.batchnumtriangles = batchnumtriangles;
7625
7626         // this variable holds flags for which properties have been updated that
7627         // may require regenerating vertexmesh array...
7628         needsupdate = 0;
7629
7630         // check if any dynamic vertex processing must occur
7631         dynamicvertex = false;
7632
7633         // a cvar to force the dynamic vertex path to be taken, for debugging
7634         if (r_batch_debugdynamicvertexpath.integer)
7635         {
7636                 if (!dynamicvertex)
7637                 {
7638                         r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1;
7639                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces;
7640                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices;
7641                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles;
7642                 }
7643                 dynamicvertex = true;
7644         }
7645
7646         // if there is a chance of animated vertex colors, it's a dynamic batch
7647         if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_ARRAY_VERTEXCOLOR)) && texturesurfacelist[0]->lightmapinfo)
7648         {
7649                 if (!dynamicvertex)
7650                 {
7651                         r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1;
7652                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces;
7653                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices;
7654                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles;
7655                 }
7656                 dynamicvertex = true;
7657                 needsupdate |= BATCHNEED_VERTEXMESH_VERTEXCOLOR;
7658         }
7659
7660         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
7661         {
7662                 switch (deform->deform)
7663                 {
7664                 default:
7665                 case Q3DEFORM_PROJECTIONSHADOW:
7666                 case Q3DEFORM_TEXT0:
7667                 case Q3DEFORM_TEXT1:
7668                 case Q3DEFORM_TEXT2:
7669                 case Q3DEFORM_TEXT3:
7670                 case Q3DEFORM_TEXT4:
7671                 case Q3DEFORM_TEXT5:
7672                 case Q3DEFORM_TEXT6:
7673                 case Q3DEFORM_TEXT7:
7674                 case Q3DEFORM_NONE:
7675                         break;
7676                 case Q3DEFORM_AUTOSPRITE:
7677                         if (!dynamicvertex)
7678                         {
7679                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1;
7680                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces;
7681                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices;
7682                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles;
7683                         }
7684                         dynamicvertex = true;
7685                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD;
7686                         needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7687                         break;
7688                 case Q3DEFORM_AUTOSPRITE2:
7689                         if (!dynamicvertex)
7690                         {
7691                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1;
7692                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces;
7693                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices;
7694                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles;
7695                         }
7696                         dynamicvertex = true;
7697                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7698                         needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7699                         break;
7700                 case Q3DEFORM_NORMAL:
7701                         if (!dynamicvertex)
7702                         {
7703                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1;
7704                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces;
7705                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices;
7706                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles;
7707                         }
7708                         dynamicvertex = true;
7709                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7710                         needsupdate |= BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7711                         break;
7712                 case Q3DEFORM_WAVE:
7713                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7714                                 break; // if wavefunc is a nop, ignore this transform
7715                         if (!dynamicvertex)
7716                         {
7717                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_wave] += 1;
7718                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces;
7719                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices;
7720                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles;
7721                         }
7722                         dynamicvertex = true;
7723                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7724                         needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7725                         break;
7726                 case Q3DEFORM_BULGE:
7727                         if (!dynamicvertex)
7728                         {
7729                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1;
7730                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces;
7731                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices;
7732                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles;
7733                         }
7734                         dynamicvertex = true;
7735                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7736                         needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7737                         break;
7738                 case Q3DEFORM_MOVE:
7739                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7740                                 break; // if wavefunc is a nop, ignore this transform
7741                         if (!dynamicvertex)
7742                         {
7743                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1;
7744                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces;
7745                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices;
7746                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles;
7747                         }
7748                         dynamicvertex = true;
7749                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7750                         needsupdate |= BATCHNEED_VERTEXMESH_VERTEX;
7751                         break;
7752                 }
7753         }
7754         if (rsurface.texture->materialshaderpass)
7755         {
7756                 switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
7757                 {
7758                 default:
7759                 case Q3TCGEN_TEXTURE:
7760                         break;
7761                 case Q3TCGEN_LIGHTMAP:
7762                         if (!dynamicvertex)
7763                         {
7764                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
7765                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
7766                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
7767                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
7768                         }
7769                         dynamicvertex = true;
7770                         batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7771                         needsupdate |= BATCHNEED_VERTEXMESH_LIGHTMAP;
7772                         break;
7773                 case Q3TCGEN_VECTOR:
7774                         if (!dynamicvertex)
7775                         {
7776                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
7777                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
7778                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
7779                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
7780                         }
7781                         dynamicvertex = true;
7782                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7783                         needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
7784                         break;
7785                 case Q3TCGEN_ENVIRONMENT:
7786                         if (!dynamicvertex)
7787                         {
7788                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
7789                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
7790                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
7791                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
7792                         }
7793                         dynamicvertex = true;
7794                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
7795                         needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
7796                         break;
7797                 }
7798                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
7799                 {
7800                         if (!dynamicvertex)
7801                         {
7802                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
7803                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
7804                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
7805                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
7806                         }
7807                         dynamicvertex = true;
7808                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7809                         needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
7810                 }
7811         }
7812
7813         if (!rsurface.modelvertexmesh && (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)))
7814         {
7815                 if (!dynamicvertex)
7816                 {
7817                         r_refdef.stats[r_stat_batch_dynamic_batches_because_interleavedarrays] += 1;
7818                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_interleavedarrays] += batchnumsurfaces;
7819                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_interleavedarrays] += batchnumvertices;
7820                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_interleavedarrays] += batchnumtriangles;
7821                 }
7822                 dynamicvertex = true;
7823                 needsupdate |= (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP));
7824         }
7825
7826         // when the model data has no vertex buffer (dynamic mesh), we need to
7827         // eliminate gaps
7828         if (vid.useinterleavedarrays && !rsurface.modelvertexmesh_vertexbuffer)
7829                 batchneed |= BATCHNEED_NOGAPS;
7830
7831         // the caller can specify BATCHNEED_NOGAPS to force a batch with
7832         // firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex),
7833         // we ensure this by treating the vertex batch as dynamic...
7834         if ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0))
7835         {
7836                 if (!dynamicvertex)
7837                 {
7838                         r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1;
7839                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces;
7840                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices;
7841                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles;
7842                 }
7843                 dynamicvertex = true;
7844         }
7845
7846         if (dynamicvertex)
7847         {
7848                 // when copying, we need to consider the regeneration of vertexmesh, any dependencies it may have must be set...
7849                 if (batchneed & BATCHNEED_VERTEXMESH_VERTEX)      batchneed |= BATCHNEED_ARRAY_VERTEX;
7850                 if (batchneed & BATCHNEED_VERTEXMESH_NORMAL)      batchneed |= BATCHNEED_ARRAY_NORMAL;
7851                 if (batchneed & BATCHNEED_VERTEXMESH_VECTOR)      batchneed |= BATCHNEED_ARRAY_VECTOR;
7852                 if (batchneed & BATCHNEED_VERTEXMESH_VERTEXCOLOR) batchneed |= BATCHNEED_ARRAY_VERTEXCOLOR;
7853                 if (batchneed & BATCHNEED_VERTEXMESH_TEXCOORD)    batchneed |= BATCHNEED_ARRAY_TEXCOORD;
7854                 if (batchneed & BATCHNEED_VERTEXMESH_LIGHTMAP)    batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7855                 if (batchneed & BATCHNEED_VERTEXMESH_SKELETAL)    batchneed |= BATCHNEED_ARRAY_SKELETAL;
7856         }
7857
7858         // if needsupdate, we have to do a dynamic vertex batch for sure
7859         if (needsupdate & batchneed)
7860         {
7861                 if (!dynamicvertex)
7862                 {
7863                         r_refdef.stats[r_stat_batch_dynamic_batches_because_derived] += 1;
7864                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_derived] += batchnumsurfaces;
7865                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_derived] += batchnumvertices;
7866                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_derived] += batchnumtriangles;
7867                 }
7868                 dynamicvertex = true;
7869         }
7870
7871         // see if we need to build vertexmesh from arrays
7872         if (!rsurface.modelvertexmesh && (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)))
7873         {
7874                 if (!dynamicvertex)
7875                 {
7876                         r_refdef.stats[r_stat_batch_dynamic_batches_because_interleavedarrays] += 1;
7877                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_interleavedarrays] += batchnumsurfaces;
7878                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_interleavedarrays] += batchnumvertices;
7879                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_interleavedarrays] += batchnumtriangles;
7880                 }
7881                 dynamicvertex = true;
7882         }
7883
7884         // if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data
7885         if (dynamicvertex && rsurface.entityskeletaltransform3x4)
7886                 batchneed |= BATCHNEED_ARRAY_SKELETAL;
7887
7888         rsurface.batchvertex3f = rsurface.modelvertex3f;
7889         rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer;
7890         rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
7891         rsurface.batchsvector3f = rsurface.modelsvector3f;
7892         rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer;
7893         rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
7894         rsurface.batchtvector3f = rsurface.modeltvector3f;
7895         rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer;
7896         rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
7897         rsurface.batchnormal3f = rsurface.modelnormal3f;
7898         rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer;
7899         rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
7900         rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f;
7901         rsurface.batchlightmapcolor4f_vertexbuffer  = rsurface.modellightmapcolor4f_vertexbuffer;
7902         rsurface.batchlightmapcolor4f_bufferoffset  = rsurface.modellightmapcolor4f_bufferoffset;
7903         rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f;
7904         rsurface.batchtexcoordtexture2f_vertexbuffer  = rsurface.modeltexcoordtexture2f_vertexbuffer;
7905         rsurface.batchtexcoordtexture2f_bufferoffset  = rsurface.modeltexcoordtexture2f_bufferoffset;
7906         rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
7907         rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer;
7908         rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
7909         rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub;
7910         rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer;
7911         rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset;
7912         rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub;
7913         rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer;
7914         rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset;
7915         rsurface.batchvertexmesh = rsurface.modelvertexmesh;
7916         rsurface.batchvertexmesh_vertexbuffer = rsurface.modelvertexmesh_vertexbuffer;
7917         rsurface.batchvertexmesh_bufferoffset = rsurface.modelvertexmesh_bufferoffset;
7918         rsurface.batchelement3i = rsurface.modelelement3i;
7919         rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer;
7920         rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset;
7921         rsurface.batchelement3s = rsurface.modelelement3s;
7922         rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer;
7923         rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset;
7924         rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4;
7925         rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer;
7926         rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset;
7927         rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size;
7928         rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms;
7929
7930         // if any dynamic vertex processing has to occur in software, we copy the
7931         // entire surface list together before processing to rebase the vertices
7932         // to start at 0 (otherwise we waste a lot of room in a vertex buffer).
7933         //
7934         // if any gaps exist and we do not have a static vertex buffer, we have to
7935         // copy the surface list together to avoid wasting upload bandwidth on the
7936         // vertices in the gaps.
7937         //
7938         // if gaps exist and we have a static vertex buffer, we can choose whether
7939         // to combine the index buffer ranges into one dynamic index buffer or
7940         // simply issue multiple glDrawElements calls (BATCHNEED_ALLOWMULTIDRAW).
7941         //
7942         // in many cases the batch is reduced to one draw call.
7943
7944         rsurface.batchmultidraw = false;
7945         rsurface.batchmultidrawnumsurfaces = 0;
7946         rsurface.batchmultidrawsurfacelist = NULL;
7947
7948         if (!dynamicvertex)
7949         {
7950                 // static vertex data, just set pointers...
7951                 rsurface.batchgeneratedvertex = false;
7952                 // if there are gaps, we want to build a combined index buffer,
7953                 // otherwise use the original static buffer with an appropriate offset
7954                 if (gaps)
7955                 {
7956                         r_refdef.stats[r_stat_batch_copytriangles_batches] += 1;
7957                         r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces;
7958                         r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices;
7959                         r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles;
7960                         if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer)
7961                         {
7962                                 rsurface.batchmultidraw = true;
7963                                 rsurface.batchmultidrawnumsurfaces = texturenumsurfaces;
7964                                 rsurface.batchmultidrawsurfacelist = texturesurfacelist;
7965                                 return;
7966                         }
7967                         // build a new triangle elements array for this batch
7968                         rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7969                         rsurface.batchfirsttriangle = 0;
7970                         numtriangles = 0;
7971                         for (i = 0;i < texturenumsurfaces;i++)
7972                         {
7973                                 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7974                                 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7975                                 memcpy(rsurface.batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3]));
7976                                 numtriangles += surfacenumtriangles;
7977                         }
7978                         rsurface.batchelement3i_indexbuffer = NULL;
7979                         rsurface.batchelement3i_bufferoffset = 0;
7980                         rsurface.batchelement3s = NULL;
7981                         rsurface.batchelement3s_indexbuffer = NULL;
7982                         rsurface.batchelement3s_bufferoffset = 0;
7983                         if (endvertex <= 65536)
7984                         {
7985                                 // make a 16bit (unsigned short) index array if possible
7986                                 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7987                                 for (i = 0;i < numtriangles*3;i++)
7988                                         rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7989                         }
7990                         // upload buffer data for the copytriangles batch
7991                         if (((r_batch_dynamicbuffer.integer || gl_vbo_dynamicindex.integer) && vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo)
7992                         {
7993                                 if (rsurface.batchelement3s)
7994                                         rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
7995                                 else if (rsurface.batchelement3i)
7996                                         rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
7997                         }
7998                 }
7999                 else
8000                 {
8001                         r_refdef.stats[r_stat_batch_fast_batches] += 1;
8002                         r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces;
8003                         r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices;
8004                         r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles;
8005                 }
8006                 return;
8007         }
8008
8009         // something needs software processing, do it for real...
8010         // we only directly handle separate array data in this case and then
8011         // generate interleaved data if needed...
8012         rsurface.batchgeneratedvertex = true;
8013         r_refdef.stats[r_stat_batch_dynamic_batches] += 1;
8014         r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces;
8015         r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices;
8016         r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles;
8017
8018         // now copy the vertex data into a combined array and make an index array
8019         // (this is what Quake3 does all the time)
8020         // we also apply any skeletal animation here that would have been done in
8021         // the vertex shader, because most of the dynamic vertex animation cases
8022         // need actual vertex positions and normals
8023         //if (dynamicvertex)
8024         {
8025                 rsurface.batchvertexmesh = NULL;
8026                 rsurface.batchvertexmesh_vertexbuffer = NULL;
8027                 rsurface.batchvertexmesh_bufferoffset = 0;
8028                 rsurface.batchvertex3f = NULL;
8029                 rsurface.batchvertex3f_vertexbuffer = NULL;
8030                 rsurface.batchvertex3f_bufferoffset = 0;
8031                 rsurface.batchsvector3f = NULL;
8032                 rsurface.batchsvector3f_vertexbuffer = NULL;
8033                 rsurface.batchsvector3f_bufferoffset = 0;
8034                 rsurface.batchtvector3f = NULL;
8035                 rsurface.batchtvector3f_vertexbuffer = NULL;
8036                 rsurface.batchtvector3f_bufferoffset = 0;
8037                 rsurface.batchnormal3f = NULL;
8038                 rsurface.batchnormal3f_vertexbuffer = NULL;
8039                 rsurface.batchnormal3f_bufferoffset = 0;
8040                 rsurface.batchlightmapcolor4f = NULL;
8041                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8042                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8043                 rsurface.batchtexcoordtexture2f = NULL;
8044                 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8045                 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8046                 rsurface.batchtexcoordlightmap2f = NULL;
8047                 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
8048                 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
8049                 rsurface.batchskeletalindex4ub = NULL;
8050                 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
8051                 rsurface.batchskeletalindex4ub_bufferoffset = 0;
8052                 rsurface.batchskeletalweight4ub = NULL;
8053                 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
8054                 rsurface.batchskeletalweight4ub_bufferoffset = 0;
8055                 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
8056                 rsurface.batchelement3i_indexbuffer = NULL;
8057                 rsurface.batchelement3i_bufferoffset = 0;
8058                 rsurface.batchelement3s = NULL;
8059                 rsurface.batchelement3s_indexbuffer = NULL;
8060                 rsurface.batchelement3s_bufferoffset = 0;
8061                 rsurface.batchskeletaltransform3x4buffer = NULL;
8062                 rsurface.batchskeletaltransform3x4offset = 0;
8063                 rsurface.batchskeletaltransform3x4size = 0;
8064                 // we'll only be setting up certain arrays as needed
8065                 if (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP))
8066                         rsurface.batchvertexmesh = (r_vertexmesh_t *)R_FrameData_Alloc(batchnumvertices * sizeof(r_vertexmesh_t));
8067                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
8068                         rsurface.batchvertex3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8069                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
8070                         rsurface.batchnormal3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8071                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
8072                 {
8073                         rsurface.batchsvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8074                         rsurface.batchtvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8075                 }
8076                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
8077                         rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8078                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
8079                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8080                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
8081                         rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8082                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
8083                 {
8084                         rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
8085                         rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
8086                 }
8087                 numvertices = 0;
8088                 numtriangles = 0;
8089                 for (i = 0;i < texturenumsurfaces;i++)
8090                 {
8091                         surfacefirstvertex = texturesurfacelist[i]->num_firstvertex;
8092                         surfacenumvertices = texturesurfacelist[i]->num_vertices;
8093                         surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
8094                         surfacenumtriangles = texturesurfacelist[i]->num_triangles;
8095                         // copy only the data requested
8096                         if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)) && rsurface.modelvertexmesh)
8097                                 memcpy(rsurface.batchvertexmesh + numvertices, rsurface.modelvertexmesh + surfacefirstvertex, surfacenumvertices * sizeof(rsurface.batchvertexmesh[0]));
8098                         if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
8099                         {
8100                                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
8101                                 {
8102                                         if (rsurface.batchvertex3f)
8103                                                 memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8104                                         else
8105                                                 memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8106                                 }
8107                                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
8108                                 {
8109                                         if (rsurface.modelnormal3f)
8110                                                 memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8111                                         else
8112                                                 memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8113                                 }
8114                                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
8115                                 {
8116                                         if (rsurface.modelsvector3f)
8117                                         {
8118                                                 memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8119                                                 memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8120                                         }
8121                                         else
8122                                         {
8123                                                 memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8124                                                 memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8125                                         }
8126                                 }
8127                                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
8128                                 {
8129                                         if (rsurface.modellightmapcolor4f)
8130                                                 memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
8131                                         else
8132                                                 memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4]));
8133                                 }
8134                                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
8135                                 {
8136                                         if (rsurface.modeltexcoordtexture2f)
8137                                                 memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
8138                                         else
8139                                                 memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
8140                                 }
8141                                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
8142                                 {
8143                                         if (rsurface.modeltexcoordlightmap2f)
8144                                                 memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
8145                                         else
8146                                                 memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
8147                                 }
8148                                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
8149                                 {
8150                                         if (rsurface.modelskeletalindex4ub)
8151                                         {
8152                                                 memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
8153                                                 memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
8154                                         }
8155                                         else
8156                                         {
8157                                                 memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
8158                                                 memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
8159                                                 ub = rsurface.batchskeletalweight4ub + 4*numvertices;
8160                                                 for (j = 0;j < surfacenumvertices;j++)
8161                                                         ub[j*4] = 255;
8162                                         }
8163                                 }
8164                         }
8165                         RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
8166                         numvertices += surfacenumvertices;
8167                         numtriangles += surfacenumtriangles;
8168                 }
8169
8170                 // generate a 16bit index array as well if possible
8171                 // (in general, dynamic batches fit)
8172                 if (numvertices <= 65536)
8173                 {
8174                         rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
8175                         for (i = 0;i < numtriangles*3;i++)
8176                                 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
8177                 }
8178
8179                 // since we've copied everything, the batch now starts at 0
8180                 rsurface.batchfirstvertex = 0;
8181                 rsurface.batchnumvertices = batchnumvertices;
8182                 rsurface.batchfirsttriangle = 0;
8183                 rsurface.batchnumtriangles = batchnumtriangles;
8184         }
8185
8186         // apply skeletal animation that would have been done in the vertex shader
8187         if (rsurface.batchskeletaltransform3x4)
8188         {
8189                 const unsigned char *si;
8190                 const unsigned char *sw;
8191                 const float *t[4];
8192                 const float *b = rsurface.batchskeletaltransform3x4;
8193                 float *vp, *vs, *vt, *vn;
8194                 float w[4];
8195                 float m[3][4], n[3][4];
8196                 float tp[3], ts[3], tt[3], tn[3];
8197                 r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1;
8198                 r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces;
8199                 r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices;
8200                 r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles;
8201                 si = rsurface.batchskeletalindex4ub;
8202                 sw = rsurface.batchskeletalweight4ub;
8203                 vp = rsurface.batchvertex3f;
8204                 vs = rsurface.batchsvector3f;
8205                 vt = rsurface.batchtvector3f;
8206                 vn = rsurface.batchnormal3f;
8207                 memset(m[0], 0, sizeof(m));
8208                 memset(n[0], 0, sizeof(n));
8209                 for (i = 0;i < batchnumvertices;i++)
8210                 {
8211                         t[0] = b + si[0]*12;
8212                         if (sw[0] == 255)
8213                         {
8214                                 // common case - only one matrix
8215                                 m[0][0] = t[0][ 0];
8216                                 m[0][1] = t[0][ 1];
8217                                 m[0][2] = t[0][ 2];
8218                                 m[0][3] = t[0][ 3];
8219                                 m[1][0] = t[0][ 4];
8220                                 m[1][1] = t[0][ 5];
8221                                 m[1][2] = t[0][ 6];
8222                                 m[1][3] = t[0][ 7];
8223                                 m[2][0] = t[0][ 8];
8224                                 m[2][1] = t[0][ 9];
8225                                 m[2][2] = t[0][10];
8226                                 m[2][3] = t[0][11];
8227                         }
8228                         else if (sw[2] + sw[3])
8229                         {
8230                                 // blend 4 matrices
8231                                 t[1] = b + si[1]*12;
8232                                 t[2] = b + si[2]*12;
8233                                 t[3] = b + si[3]*12;
8234                                 w[0] = sw[0] * (1.0f / 255.0f);
8235                                 w[1] = sw[1] * (1.0f / 255.0f);
8236                                 w[2] = sw[2] * (1.0f / 255.0f);
8237                                 w[3] = sw[3] * (1.0f / 255.0f);
8238                                 // blend the matrices
8239                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3];
8240                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3];
8241                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3];
8242                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3];
8243                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3];
8244                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3];
8245                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3];
8246                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3];
8247                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3];
8248                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3];
8249                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3];
8250                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3];
8251                         }
8252                         else
8253                         {
8254                                 // blend 2 matrices
8255                                 t[1] = b + si[1]*12;
8256                                 w[0] = sw[0] * (1.0f / 255.0f);
8257                                 w[1] = sw[1] * (1.0f / 255.0f);
8258                                 // blend the matrices
8259                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1];
8260                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1];
8261                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1];
8262                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1];
8263                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1];
8264                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1];
8265                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1];
8266                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1];
8267                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1];
8268                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1];
8269                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1];
8270                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1];
8271                         }
8272                         si += 4;
8273                         sw += 4;
8274                         // modify the vertex
8275                         VectorCopy(vp, tp);
8276                         vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3];
8277                         vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3];
8278                         vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3];
8279                         vp += 3;
8280                         if (vn)
8281                         {
8282                                 // the normal transformation matrix is a set of cross products...
8283                                 CrossProduct(m[1], m[2], n[0]);
8284                                 CrossProduct(m[2], m[0], n[1]);
8285                                 CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m)
8286                                 VectorCopy(vn, tn);
8287                                 vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2];
8288                                 vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2];
8289                                 vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2];
8290                                 VectorNormalize(vn);
8291                                 vn += 3;
8292                                 if (vs)
8293                                 {
8294                                         VectorCopy(vs, ts);
8295                                         vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2];
8296                                         vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2];
8297                                         vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2];
8298                                         VectorNormalize(vs);
8299                                         vs += 3;
8300                                         VectorCopy(vt, tt);
8301                                         vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2];
8302                                         vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2];
8303                                         vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2];
8304                                         VectorNormalize(vt);
8305                                         vt += 3;
8306                                 }
8307                         }
8308                 }
8309                 rsurface.batchskeletaltransform3x4 = NULL;
8310                 rsurface.batchskeletalnumtransforms = 0;
8311         }
8312
8313         // q1bsp surfaces rendered in vertex color mode have to have colors
8314         // calculated based on lightstyles
8315         if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_ARRAY_VERTEXCOLOR)) && texturesurfacelist[0]->lightmapinfo)
8316         {
8317                 // generate color arrays for the surfaces in this list
8318                 int c[4];
8319                 int scale;
8320                 int size3;
8321                 const int *offsets;
8322                 const unsigned char *lm;
8323                 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8324                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8325                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8326                 numvertices = 0;
8327                 for (i = 0;i < texturenumsurfaces;i++)
8328                 {
8329                         surface = texturesurfacelist[i];
8330                         offsets = rsurface.modellightmapoffsets + surface->num_firstvertex;
8331                         surfacenumvertices = surface->num_vertices;
8332                         if (surface->lightmapinfo->samples)
8333                         {
8334                                 for (j = 0;j < surfacenumvertices;j++)
8335                                 {
8336                                         lm = surface->lightmapinfo->samples + offsets[j];
8337                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]];
8338                                         VectorScale(lm, scale, c);
8339                                         if (surface->lightmapinfo->styles[1] != 255)
8340                                         {
8341                                                 size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
8342                                                 lm += size3;
8343                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]];
8344                                                 VectorMA(c, scale, lm, c);
8345                                                 if (surface->lightmapinfo->styles[2] != 255)
8346                                                 {
8347                                                         lm += size3;
8348                                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]];
8349                                                         VectorMA(c, scale, lm, c);
8350                                                         if (surface->lightmapinfo->styles[3] != 255)
8351                                                         {
8352                                                                 lm += size3;
8353                                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]];
8354                                                                 VectorMA(c, scale, lm, c);
8355                                                         }
8356                                                 }
8357                                         }
8358                                         c[0] >>= 7;
8359                                         c[1] >>= 7;
8360                                         c[2] >>= 7;
8361                                         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);
8362                                         numvertices++;
8363                                 }
8364                         }
8365                         else
8366                         {
8367                                 for (j = 0;j < surfacenumvertices;j++)
8368                                 {
8369                                         Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1);
8370                                         numvertices++;
8371                                 }
8372                         }
8373                 }
8374         }
8375
8376         // if vertices are deformed (sprite flares and things in maps, possibly
8377         // water waves, bulges and other deformations), modify the copied vertices
8378         // in place
8379         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
8380         {
8381                 float scale;
8382                 switch (deform->deform)
8383                 {
8384                 default:
8385                 case Q3DEFORM_PROJECTIONSHADOW:
8386                 case Q3DEFORM_TEXT0:
8387                 case Q3DEFORM_TEXT1:
8388                 case Q3DEFORM_TEXT2:
8389                 case Q3DEFORM_TEXT3:
8390                 case Q3DEFORM_TEXT4:
8391                 case Q3DEFORM_TEXT5:
8392                 case Q3DEFORM_TEXT6:
8393                 case Q3DEFORM_TEXT7:
8394                 case Q3DEFORM_NONE:
8395                         break;
8396                 case Q3DEFORM_AUTOSPRITE:
8397                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8398                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8399                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8400                         VectorNormalize(newforward);
8401                         VectorNormalize(newright);
8402                         VectorNormalize(newup);
8403 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8404 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8405 //                      rsurface.batchvertex3f_bufferoffset = 0;
8406 //                      rsurface.batchsvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f);
8407 //                      rsurface.batchsvector3f_vertexbuffer = NULL;
8408 //                      rsurface.batchsvector3f_bufferoffset = 0;
8409 //                      rsurface.batchtvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f);
8410 //                      rsurface.batchtvector3f_vertexbuffer = NULL;
8411 //                      rsurface.batchtvector3f_bufferoffset = 0;
8412 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8413 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8414 //                      rsurface.batchnormal3f_bufferoffset = 0;
8415                         // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1)
8416                         if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex))
8417                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8418                         if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex))
8419                                 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);
8420                         // a single autosprite surface can contain multiple sprites...
8421                         for (j = 0;j < batchnumvertices - 3;j += 4)
8422                         {
8423                                 VectorClear(center);
8424                                 for (i = 0;i < 4;i++)
8425                                         VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8426                                 VectorScale(center, 0.25f, center);
8427                                 VectorCopy(rsurface.batchnormal3f + 3*j, forward);
8428                                 VectorCopy(rsurface.batchsvector3f + 3*j, right);
8429                                 VectorCopy(rsurface.batchtvector3f + 3*j, up);
8430                                 for (i = 0;i < 4;i++)
8431                                 {
8432                                         VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v);
8433                                         VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.batchvertex3f + 3*(j+i));
8434                                 }
8435                         }
8436                         // if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check
8437                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8438                         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);
8439                         break;
8440                 case Q3DEFORM_AUTOSPRITE2:
8441                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8442                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8443                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8444                         VectorNormalize(newforward);
8445                         VectorNormalize(newright);
8446                         VectorNormalize(newup);
8447 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8448 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8449 //                      rsurface.batchvertex3f_bufferoffset = 0;
8450                         {
8451                                 const float *v1, *v2;
8452                                 vec3_t start, end;
8453                                 float f, l;
8454                                 struct
8455                                 {
8456                                         float length2;
8457                                         const float *v1;
8458                                         const float *v2;
8459                                 }
8460                                 shortest[2];
8461                                 memset(shortest, 0, sizeof(shortest));
8462                                 // a single autosprite surface can contain multiple sprites...
8463                                 for (j = 0;j < batchnumvertices - 3;j += 4)
8464                                 {
8465                                         VectorClear(center);
8466                                         for (i = 0;i < 4;i++)
8467                                                 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8468                                         VectorScale(center, 0.25f, center);
8469                                         // find the two shortest edges, then use them to define the
8470                                         // axis vectors for rotating around the central axis
8471                                         for (i = 0;i < 6;i++)
8472                                         {
8473                                                 v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]);
8474                                                 v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]);
8475                                                 l = VectorDistance2(v1, v2);
8476                                                 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
8477                                                 if (v1[2] != v2[2])
8478                                                         l += (1.0f / 1024.0f);
8479                                                 if (shortest[0].length2 > l || i == 0)
8480                                                 {
8481                                                         shortest[1] = shortest[0];
8482                                                         shortest[0].length2 = l;
8483                                                         shortest[0].v1 = v1;
8484                                                         shortest[0].v2 = v2;
8485                                                 }
8486                                                 else if (shortest[1].length2 > l || i == 1)
8487                                                 {
8488                                                         shortest[1].length2 = l;
8489                                                         shortest[1].v1 = v1;
8490                                                         shortest[1].v2 = v2;
8491                                                 }
8492                                         }
8493                                         VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
8494                                         VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
8495                                         // this calculates the right vector from the shortest edge
8496                                         // and the up vector from the edge midpoints
8497                                         VectorSubtract(shortest[0].v1, shortest[0].v2, right);
8498                                         VectorNormalize(right);
8499                                         VectorSubtract(end, start, up);
8500                                         VectorNormalize(up);
8501                                         // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
8502                                         VectorSubtract(rsurface.localvieworigin, center, forward);
8503                                         //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
8504                                         VectorNegate(forward, forward);
8505                                         VectorReflect(forward, 0, up, forward);
8506                                         VectorNormalize(forward);
8507                                         CrossProduct(up, forward, newright);
8508                                         VectorNormalize(newright);
8509                                         // rotate the quad around the up axis vector, this is made
8510                                         // especially easy by the fact we know the quad is flat,
8511                                         // so we only have to subtract the center position and
8512                                         // measure distance along the right vector, and then
8513                                         // multiply that by the newright vector and add back the
8514                                         // center position
8515                                         // we also need to subtract the old position to undo the
8516                                         // displacement from the center, which we do with a
8517                                         // DotProduct, the subtraction/addition of center is also
8518                                         // optimized into DotProducts here
8519                                         l = DotProduct(right, center);
8520                                         for (i = 0;i < 4;i++)
8521                                         {
8522                                                 v1 = rsurface.batchvertex3f + 3*(j+i);
8523                                                 f = DotProduct(right, v1) - l;
8524                                                 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.batchvertex3f + 3*(j+i));
8525                                         }
8526                                 }
8527                         }
8528                         if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL
8529                         {
8530 //                              rsurface.batchnormal3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8531 //                              rsurface.batchnormal3f_vertexbuffer = NULL;
8532 //                              rsurface.batchnormal3f_bufferoffset = 0;
8533                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8534                         }
8535                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8536                         {
8537 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8538 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8539 //                              rsurface.batchsvector3f_bufferoffset = 0;
8540 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8541 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8542 //                              rsurface.batchtvector3f_bufferoffset = 0;
8543                                 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);
8544                         }
8545                         break;
8546                 case Q3DEFORM_NORMAL:
8547                         // deform the normals to make reflections wavey
8548                         rsurface.batchnormal3f = (float *)R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8549                         rsurface.batchnormal3f_vertexbuffer = NULL;
8550                         rsurface.batchnormal3f_bufferoffset = 0;
8551                         for (j = 0;j < batchnumvertices;j++)
8552                         {
8553                                 float vertex[3];
8554                                 float *normal = rsurface.batchnormal3f + 3*j;
8555                                 VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
8556                                 normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f(      vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8557                                 normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8558                                 normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8559                                 VectorNormalize(normal);
8560                         }
8561                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8562                         {
8563 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8564 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8565 //                              rsurface.batchsvector3f_bufferoffset = 0;
8566 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8567 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8568 //                              rsurface.batchtvector3f_bufferoffset = 0;
8569                                 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);
8570                         }
8571                         break;
8572                 case Q3DEFORM_WAVE:
8573                         // deform vertex array to make wavey water and flags and such
8574                         waveparms[0] = deform->waveparms[0];
8575                         waveparms[1] = deform->waveparms[1];
8576                         waveparms[2] = deform->waveparms[2];
8577                         waveparms[3] = deform->waveparms[3];
8578                         if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms))
8579                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8580                         // this is how a divisor of vertex influence on deformation
8581                         animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
8582                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8583 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8584 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8585 //                      rsurface.batchvertex3f_bufferoffset = 0;
8586 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8587 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8588 //                      rsurface.batchnormal3f_bufferoffset = 0;
8589                         for (j = 0;j < batchnumvertices;j++)
8590                         {
8591                                 // if the wavefunc depends on time, evaluate it per-vertex
8592                                 if (waveparms[3])
8593                                 {
8594                                         waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos;
8595                                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8596                                 }
8597                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8598                         }
8599                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8600                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8601                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8602                         {
8603 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8604 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8605 //                              rsurface.batchsvector3f_bufferoffset = 0;
8606 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8607 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8608 //                              rsurface.batchtvector3f_bufferoffset = 0;
8609                                 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);
8610                         }
8611                         break;
8612                 case Q3DEFORM_BULGE:
8613                         // deform vertex array to make the surface have moving bulges
8614 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8615 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8616 //                      rsurface.batchvertex3f_bufferoffset = 0;
8617 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8618 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8619 //                      rsurface.batchnormal3f_bufferoffset = 0;
8620                         for (j = 0;j < batchnumvertices;j++)
8621                         {
8622                                 scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1];
8623                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8624                         }
8625                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8626                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8627                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8628                         {
8629 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8630 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8631 //                              rsurface.batchsvector3f_bufferoffset = 0;
8632 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8633 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8634 //                              rsurface.batchtvector3f_bufferoffset = 0;
8635                                 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);
8636                         }
8637                         break;
8638                 case Q3DEFORM_MOVE:
8639                         // deform vertex array
8640                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
8641                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8642                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
8643                         VectorScale(deform->parms, scale, waveparms);
8644 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8645 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8646 //                      rsurface.batchvertex3f_bufferoffset = 0;
8647                         for (j = 0;j < batchnumvertices;j++)
8648                                 VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.batchvertex3f + 3*j);
8649                         break;
8650                 }
8651         }
8652
8653         if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
8654         {
8655         // generate texcoords based on the chosen texcoord source
8656                 switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
8657                 {
8658                 default:
8659                 case Q3TCGEN_TEXTURE:
8660                         break;
8661                 case Q3TCGEN_LIGHTMAP:
8662         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8663         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8664         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8665                         if (rsurface.batchtexcoordlightmap2f)
8666                                 memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
8667                         break;
8668                 case Q3TCGEN_VECTOR:
8669         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8670         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8671         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8672                         for (j = 0;j < batchnumvertices;j++)
8673                         {
8674                                 rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
8675                                 rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
8676                         }
8677                         break;
8678                 case Q3TCGEN_ENVIRONMENT:
8679                         // make environment reflections using a spheremap
8680                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8681                         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8682                         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8683                         for (j = 0;j < batchnumvertices;j++)
8684                         {
8685                                 // identical to Q3A's method, but executed in worldspace so
8686                                 // carried models can be shiny too
8687
8688                                 float viewer[3], d, reflected[3], worldreflected[3];
8689
8690                                 VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
8691                                 // VectorNormalize(viewer);
8692
8693                                 d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
8694
8695                                 reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
8696                                 reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
8697                                 reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
8698                                 // note: this is proportinal to viewer, so we can normalize later
8699
8700                                 Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
8701                                 VectorNormalize(worldreflected);
8702
8703                                 // note: this sphere map only uses world x and z!
8704                                 // so positive and negative y will LOOK THE SAME.
8705                                 rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
8706                                 rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
8707                         }
8708                         break;
8709                 }
8710                 // the only tcmod that needs software vertex processing is turbulent, so
8711                 // check for it here and apply the changes if needed
8712                 // and we only support that as the first one
8713                 // (handling a mixture of turbulent and other tcmods would be problematic
8714                 //  without punting it entirely to a software path)
8715                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
8716                 {
8717                         amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
8718                         animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
8719         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8720         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8721         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8722                         for (j = 0;j < batchnumvertices;j++)
8723                         {
8724                                 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);
8725                                 rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1]                                ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8726                         }
8727                 }
8728         }
8729
8730         if (needsupdate & batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP))
8731         {
8732                 // convert the modified arrays to vertex structs
8733 //              rsurface.batchvertexmesh = R_FrameData_Alloc(batchnumvertices * sizeof(r_vertexmesh_t));
8734 //              rsurface.batchvertexmesh_vertexbuffer = NULL;
8735 //              rsurface.batchvertexmesh_bufferoffset = 0;
8736                 if (batchneed & BATCHNEED_VERTEXMESH_VERTEX)
8737                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8738                                 VectorCopy(rsurface.batchvertex3f + 3*j, vertexmesh->vertex3f);
8739                 if (batchneed & BATCHNEED_VERTEXMESH_NORMAL)
8740                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8741                                 VectorCopy(rsurface.batchnormal3f + 3*j, vertexmesh->normal3f);
8742                 if (batchneed & BATCHNEED_VERTEXMESH_VECTOR)
8743                 {
8744                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8745                         {
8746                                 VectorCopy(rsurface.batchsvector3f + 3*j, vertexmesh->svector3f);
8747                                 VectorCopy(rsurface.batchtvector3f + 3*j, vertexmesh->tvector3f);
8748                         }
8749                 }
8750                 if ((batchneed & BATCHNEED_VERTEXMESH_VERTEXCOLOR) && rsurface.batchlightmapcolor4f)
8751                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8752                                 Vector4Copy(rsurface.batchlightmapcolor4f + 4*j, vertexmesh->color4f);
8753                 if (batchneed & BATCHNEED_VERTEXMESH_TEXCOORD)
8754                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8755                                 Vector2Copy(rsurface.batchtexcoordtexture2f + 2*j, vertexmesh->texcoordtexture2f);
8756                 if ((batchneed & BATCHNEED_VERTEXMESH_LIGHTMAP) && rsurface.batchtexcoordlightmap2f)
8757                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8758                                 Vector2Copy(rsurface.batchtexcoordlightmap2f + 2*j, vertexmesh->texcoordlightmap2f);
8759                 if ((batchneed & BATCHNEED_VERTEXMESH_SKELETAL) && rsurface.batchskeletalindex4ub)
8760                 {
8761                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8762                         {
8763                                 Vector4Copy(rsurface.batchskeletalindex4ub + 4*j, vertexmesh->skeletalindex4ub);
8764                                 Vector4Copy(rsurface.batchskeletalweight4ub + 4*j, vertexmesh->skeletalweight4ub);
8765                         }
8766                 }
8767         }
8768
8769         // upload buffer data for the dynamic batch
8770         if (((r_batch_dynamicbuffer.integer || gl_vbo_dynamicvertex.integer || gl_vbo_dynamicindex.integer) && vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo)
8771         {
8772                 if (rsurface.batchvertexmesh)
8773                         rsurface.batchvertexmesh_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(r_vertexmesh_t), rsurface.batchvertexmesh, R_BUFFERDATA_VERTEX, &rsurface.batchvertexmesh_bufferoffset);
8774                 else
8775                 {
8776                         if (rsurface.batchvertex3f)
8777                                 rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
8778                         if (rsurface.batchsvector3f)
8779                                 rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
8780                         if (rsurface.batchtvector3f)
8781                                 rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
8782                         if (rsurface.batchnormal3f)
8783                                 rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
8784                         if (rsurface.batchlightmapcolor4f)
8785                                 rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
8786                         if (rsurface.batchtexcoordtexture2f)
8787                                 rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
8788                         if (rsurface.batchtexcoordlightmap2f)
8789                                 rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
8790                         if (rsurface.batchskeletalindex4ub)
8791                                 rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
8792                         if (rsurface.batchskeletalweight4ub)
8793                                 rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
8794                 }
8795                 if (rsurface.batchelement3s)
8796                         rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
8797                 else if (rsurface.batchelement3i)
8798                         rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
8799         }
8800 }
8801
8802 void RSurf_DrawBatch(void)
8803 {
8804         // sometimes a zero triangle surface (usually a degenerate patch) makes it
8805         // through the pipeline, killing it earlier in the pipeline would have
8806         // per-surface overhead rather than per-batch overhead, so it's best to
8807         // reject it here, before it hits glDraw.
8808         if (rsurface.batchnumtriangles == 0)
8809                 return;
8810 #if 0
8811         // batch debugging code
8812         if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f)
8813         {
8814                 int i;
8815                 int j;
8816                 int c;
8817                 const int *e;
8818                 e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3;
8819                 for (i = 0;i < rsurface.batchnumtriangles*3;i++)
8820                 {
8821                         c = e[i];
8822                         for (j = 0;j < rsurface.entity->model->num_surfaces;j++)
8823                         {
8824                                 if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
8825                                 {
8826                                         if (rsurface.modelsurfaces[j].texture != rsurface.texture)
8827                                                 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);
8828                                         break;
8829                                 }
8830                         }
8831                 }
8832         }
8833 #endif
8834         if (rsurface.batchmultidraw)
8835         {
8836                 // issue multiple draws rather than copying index data
8837                 int numsurfaces = rsurface.batchmultidrawnumsurfaces;
8838                 const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist;
8839                 int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle;
8840                 for (i = 0;i < numsurfaces;)
8841                 {
8842                         // combine consecutive surfaces as one draw
8843                         for (k = i, j = i + 1;j < numsurfaces;k = j, j++)
8844                                 if (surfacelist[j] != surfacelist[k] + 1)
8845                                         break;
8846                         firstvertex = surfacelist[i]->num_firstvertex;
8847                         endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices;
8848                         firsttriangle = surfacelist[i]->num_firsttriangle;
8849                         endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles;
8850                         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);
8851                         i = j;
8852                 }
8853         }
8854         else
8855         {
8856                 // there is only one consecutive run of index data (may have been combined)
8857                 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);
8858         }
8859 }
8860
8861 static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface)
8862 {
8863         // pick the closest matching water plane
8864         int planeindex, vertexindex, bestplaneindex = -1;
8865         float d, bestd;
8866         vec3_t vert;
8867         const float *v;
8868         r_waterstate_waterplane_t *p;
8869         qboolean prepared = false;
8870         bestd = 0;
8871         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
8872         {
8873                 if(p->camera_entity != rsurface.texture->camera_entity)
8874                         continue;
8875                 d = 0;
8876                 if(!prepared)
8877                 {
8878                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
8879                         prepared = true;
8880                         if(rsurface.batchnumvertices == 0)
8881                                 break;
8882                 }
8883                 for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
8884                 {
8885                         Matrix4x4_Transform(&rsurface.matrix, v, vert);
8886                         d += fabs(PlaneDiff(vert, &p->plane));
8887                 }
8888                 if (bestd > d || bestplaneindex < 0)
8889                 {
8890                         bestd = d;
8891                         bestplaneindex = planeindex;
8892                 }
8893         }
8894         return bestplaneindex;
8895         // NOTE: this MAY return a totally unrelated water plane; we can ignore
8896         // this situation though, as it might be better to render single larger
8897         // batches with useless stuff (backface culled for example) than to
8898         // render multiple smaller batches
8899 }
8900
8901 void RSurf_SetupDepthAndCulling(void)
8902 {
8903         // submodels are biased to avoid z-fighting with world surfaces that they
8904         // may be exactly overlapping (avoids z-fighting artifacts on certain
8905         // doors and things in Quake maps)
8906         GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
8907         GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
8908         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
8909         GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
8910 }
8911
8912 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8913 {
8914         int i, j;
8915         // transparent sky would be ridiculous
8916         if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8917                 return;
8918         R_SetupShader_Generic_NoTexture(false, false);
8919         skyrenderlater = true;
8920         RSurf_SetupDepthAndCulling();
8921         GL_DepthMask(true);
8922
8923         // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
8924         if (r_sky_scissor.integer)
8925         {
8926                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8927                 for (i = 0; i < texturenumsurfaces; i++)
8928                 {
8929                         const msurface_t *surf = texturesurfacelist[i];
8930                         const float *v;
8931                         float p[3];
8932                         float mins[3], maxs[3];
8933                         int scissor[4];
8934                         for (j = 0, v = rsurface.batchvertex3f + 3 * surf->num_firstvertex; j < surf->num_vertices; j++, v += 3)
8935                         {
8936                                 Matrix4x4_Transform(&rsurface.matrix, v, p);
8937                                 if (j > 0)
8938                                 {
8939                                         if (mins[0] > p[0]) mins[0] = p[0];
8940                                         if (mins[1] > p[1]) mins[1] = p[1];
8941                                         if (mins[2] > p[2]) mins[2] = p[2];
8942                                         if (maxs[0] < p[0]) maxs[0] = p[0];
8943                                         if (maxs[1] < p[1]) maxs[1] = p[1];
8944                                         if (maxs[2] < p[2]) maxs[2] = p[2];
8945                                 }
8946                                 else
8947                                 {
8948                                         VectorCopy(p, mins);
8949                                         VectorCopy(p, maxs);
8950                                 }
8951                         }
8952                         if (!R_ScissorForBBox(mins, maxs, scissor))
8953                         {
8954                                 if (skyscissor[2])
8955                                 {
8956                                         if (skyscissor[0] > scissor[0])
8957                                         {
8958                                                 skyscissor[2] += skyscissor[0] - scissor[0];
8959                                                 skyscissor[0] = scissor[0];
8960                                         }
8961                                         if (skyscissor[1] > scissor[1])
8962                                         {
8963                                                 skyscissor[3] += skyscissor[1] - scissor[1];
8964                                                 skyscissor[1] = scissor[1];
8965                                         }
8966                                         if (skyscissor[0] + skyscissor[2] < scissor[0] + scissor[2])
8967                                                 skyscissor[2] = scissor[0] + scissor[2] - skyscissor[0];
8968                                         if (skyscissor[1] + skyscissor[3] < scissor[1] + scissor[3])
8969                                                 skyscissor[3] = scissor[1] + scissor[3] - skyscissor[1];
8970                                 }
8971                                 else
8972                                         Vector4Copy(scissor, skyscissor);
8973                         }
8974                 }
8975         }
8976
8977         // LadyHavoc: HalfLife maps have freaky skypolys so don't use
8978         // skymasking on them, and Quake3 never did sky masking (unlike
8979         // software Quake and software Quake2), so disable the sky masking
8980         // in Quake3 maps as it causes problems with q3map2 sky tricks,
8981         // and skymasking also looks very bad when noclipping outside the
8982         // level, so don't use it then either.
8983         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)
8984         {
8985                 R_Mesh_ResetTextureState();
8986                 if (skyrendermasked)
8987                 {
8988                         R_SetupShader_DepthOrShadow(false, false, false);
8989                         // depth-only (masking)
8990                         GL_ColorMask(0, 0, 0, 0);
8991                         // just to make sure that braindead drivers don't draw
8992                         // anything despite that colormask...
8993                         GL_BlendFunc(GL_ZERO, GL_ONE);
8994                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8995                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8996                 }
8997                 else
8998                 {
8999                         R_SetupShader_Generic_NoTexture(false, false);
9000                         // fog sky
9001                         GL_BlendFunc(GL_ONE, GL_ZERO);
9002                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9003                         GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
9004                         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9005                 }
9006                 RSurf_DrawBatch();
9007                 if (skyrendermasked)
9008                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
9009         }
9010         R_Mesh_ResetTextureState();
9011         GL_Color(1, 1, 1, 1);
9012 }
9013
9014 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
9015 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
9016 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
9017 {
9018         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
9019                 return;
9020         if (prepass)
9021         {
9022                 // render screenspace normalmap to texture
9023                 GL_DepthMask(true);
9024                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false);
9025                 RSurf_DrawBatch();
9026                 return;
9027         }
9028
9029         // bind lightmap texture
9030
9031         // water/refraction/reflection/camera surfaces have to be handled specially
9032         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)))
9033         {
9034                 int start, end, startplaneindex;
9035                 for (start = 0;start < texturenumsurfaces;start = end)
9036                 {
9037                         startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]);
9038                         if(startplaneindex < 0)
9039                         {
9040                                 // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this.
9041                                 // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags);
9042                                 end = start + 1;
9043                                 continue;
9044                         }
9045                         for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++)
9046                                 ;
9047                         // now that we have a batch using the same planeindex, render it
9048                         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)))
9049                         {
9050                                 // render water or distortion background
9051                                 GL_DepthMask(true);
9052                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
9053                                 RSurf_DrawBatch();
9054                                 // blend surface on top
9055                                 GL_DepthMask(false);
9056                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false);
9057                                 RSurf_DrawBatch();
9058                         }
9059                         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
9060                         {
9061                                 // render surface with reflection texture as input
9062                                 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
9063                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
9064                                 RSurf_DrawBatch();
9065                         }
9066                 }
9067                 return;
9068         }
9069
9070         // render surface batch normally
9071         GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
9072         R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0);
9073         RSurf_DrawBatch();
9074 }
9075
9076 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
9077 {
9078         int vi;
9079         int j;
9080         r_vertexgeneric_t *batchvertex;
9081         float c[4];
9082         texture_t *t = rsurface.texture;
9083
9084 //      R_Mesh_ResetTextureState();
9085         R_SetupShader_Generic_NoTexture(false, false);
9086
9087         if(t && t->currentskinframe)
9088         {
9089                 memcpy(c, t->currentskinframe->avgcolor, sizeof(c));
9090                 c[3] *= t->currentalpha;
9091         }
9092         else
9093         {
9094                 c[0] = 1;
9095                 c[1] = 0;
9096                 c[2] = 1;
9097                 c[3] = 1;
9098         }
9099
9100         if (t->pantstexture || t->shirttexture)
9101         {
9102                 c[0] = 0.5 * (t->render_colormap_pants[0] * 0.3 + t->render_colormap_shirt[0] * 0.7);
9103                 c[1] = 0.5 * (t->render_colormap_pants[1] * 0.3 + t->render_colormap_shirt[1] * 0.7);
9104                 c[2] = 0.5 * (t->render_colormap_pants[2] * 0.3 + t->render_colormap_shirt[2] * 0.7);
9105         }
9106
9107         // brighten it up (as texture value 127 means "unlit")
9108         c[0] *= 2 * r_refdef.view.colorscale;
9109         c[1] *= 2 * r_refdef.view.colorscale;
9110         c[2] *= 2 * r_refdef.view.colorscale;
9111
9112         if(t->currentmaterialflags & MATERIALFLAG_WATERALPHA)
9113                 c[3] *= r_wateralpha.value;
9114
9115         if(t->currentmaterialflags & MATERIALFLAG_ALPHA && c[3] != 1)
9116         {
9117                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9118                 GL_DepthMask(false);
9119         }
9120         else if(t->currentmaterialflags & MATERIALFLAG_ADD)
9121         {
9122                 GL_BlendFunc(GL_ONE, GL_ONE);
9123                 GL_DepthMask(false);
9124         }
9125         else if(t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
9126         {
9127                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // can't do alpha test without texture, so let's blend instead
9128                 GL_DepthMask(false);
9129         }
9130         else if(t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
9131         {
9132                 GL_BlendFunc(t->customblendfunc[0], t->customblendfunc[1]);
9133                 GL_DepthMask(false);
9134         }
9135         else
9136         {
9137                 GL_BlendFunc(GL_ONE, GL_ZERO);
9138                 GL_DepthMask(writedepth);
9139         }
9140
9141         if (!r_refdef.view.showdebug)
9142         {
9143                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9144                 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchnumvertices);
9145                 for (j = 0, vi = 0;j < rsurface.batchnumvertices;j++, vi++)
9146                 {
9147                         VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
9148                         Vector4Set(batchvertex[vi].color4f, 0, 0, 0, 1);
9149                 }
9150                 R_Mesh_PrepareVertices_Generic_Unlock();
9151                 RSurf_DrawBatch();
9152         }
9153         else if (r_showsurfaces.integer == 4)
9154         {
9155                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9156                 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchnumvertices);
9157                 for (j = 0, vi = 0;j < rsurface.batchnumvertices;j++, vi++)
9158                 {
9159                         float d = (vi << 3) * (1.0f / 256.0f);
9160                         VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
9161                         Vector4Set(batchvertex[vi].color4f, d, d, d, 1);
9162                 }
9163                 R_Mesh_PrepareVertices_Generic_Unlock();
9164                 RSurf_DrawBatch();
9165         }
9166         else if (r_showsurfaces.integer == 2)
9167         {
9168                 const int *e;
9169                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9170                 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(3*rsurface.batchnumtriangles);
9171                 for (j = 0, e = rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle;j < rsurface.batchnumtriangles;j++, e += 3)
9172                 {
9173                         float d = ((j + rsurface.batchfirsttriangle) << 3) * (1.0f / 256.0f);
9174                         VectorCopy(rsurface.batchvertex3f + 3*e[0], batchvertex[j*3+0].vertex3f);
9175                         VectorCopy(rsurface.batchvertex3f + 3*e[1], batchvertex[j*3+1].vertex3f);
9176                         VectorCopy(rsurface.batchvertex3f + 3*e[2], batchvertex[j*3+2].vertex3f);
9177                         Vector4Set(batchvertex[j*3+0].color4f, d, d, d, 1);
9178                         Vector4Set(batchvertex[j*3+1].color4f, d, d, d, 1);
9179                         Vector4Set(batchvertex[j*3+2].color4f, d, d, d, 1);
9180                 }
9181                 R_Mesh_PrepareVertices_Generic_Unlock();
9182                 R_Mesh_Draw(0, rsurface.batchnumtriangles*3, 0, rsurface.batchnumtriangles, NULL, NULL, 0, NULL, NULL, 0);
9183         }
9184         else
9185         {
9186                 int texturesurfaceindex;
9187                 int k;
9188                 const msurface_t *surface;
9189                 float surfacecolor4f[4];
9190                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9191                 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchfirstvertex + rsurface.batchnumvertices);
9192                 vi = 0;
9193                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
9194                 {
9195                         surface = texturesurfacelist[texturesurfaceindex];
9196                         k = (int)(((size_t)surface) / sizeof(msurface_t));
9197                         Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
9198                         for (j = 0;j < surface->num_vertices;j++)
9199                         {
9200                                 VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
9201                                 Vector4Copy(surfacecolor4f, batchvertex[vi].color4f);
9202                                 vi++;
9203                         }
9204                 }
9205                 R_Mesh_PrepareVertices_Generic_Unlock();
9206                 RSurf_DrawBatch();
9207         }
9208 }
9209
9210 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
9211 {
9212         CHECKGLERROR
9213         RSurf_SetupDepthAndCulling();
9214         if (r_showsurfaces.integer)
9215         {
9216                 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
9217                 return;
9218         }
9219         switch (vid.renderpath)
9220         {
9221         case RENDERPATH_GL20:
9222         case RENDERPATH_GLES2:
9223                 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
9224                 break;
9225         }
9226         CHECKGLERROR
9227 }
9228
9229 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9230 {
9231         int i, j;
9232         int texturenumsurfaces, endsurface;
9233         texture_t *texture;
9234         const msurface_t *surface;
9235         const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
9236
9237         RSurf_ActiveModelEntity(ent, true, true, false);
9238
9239         if (r_transparentdepthmasking.integer)
9240         {
9241                 qboolean setup = false;
9242                 for (i = 0;i < numsurfaces;i = j)
9243                 {
9244                         j = i + 1;
9245                         surface = rsurface.modelsurfaces + surfacelist[i];
9246                         texture = surface->texture;
9247                         rsurface.texture = R_GetCurrentTexture(texture);
9248                         rsurface.lightmaptexture = NULL;
9249                         rsurface.deluxemaptexture = NULL;
9250                         rsurface.uselightmaptexture = false;
9251                         // scan ahead until we find a different texture
9252                         endsurface = min(i + 1024, numsurfaces);
9253                         texturenumsurfaces = 0;
9254                         texturesurfacelist[texturenumsurfaces++] = surface;
9255                         for (;j < endsurface;j++)
9256                         {
9257                                 surface = rsurface.modelsurfaces + surfacelist[j];
9258                                 if (texture != surface->texture)
9259                                         break;
9260                                 texturesurfacelist[texturenumsurfaces++] = surface;
9261                         }
9262                         if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
9263                                 continue;
9264                         // render the range of surfaces as depth
9265                         if (!setup)
9266                         {
9267                                 setup = true;
9268                                 GL_ColorMask(0,0,0,0);
9269                                 GL_Color(1,1,1,1);
9270                                 GL_DepthTest(true);
9271                                 GL_BlendFunc(GL_ONE, GL_ZERO);
9272                                 GL_DepthMask(true);
9273 //                              R_Mesh_ResetTextureState();
9274                         }
9275                         RSurf_SetupDepthAndCulling();
9276                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9277                         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
9278                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9279                         RSurf_DrawBatch();
9280                 }
9281                 if (setup)
9282                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
9283         }
9284
9285         for (i = 0;i < numsurfaces;i = j)
9286         {
9287                 j = i + 1;
9288                 surface = rsurface.modelsurfaces + surfacelist[i];
9289                 texture = surface->texture;
9290                 rsurface.texture = R_GetCurrentTexture(texture);
9291                 // scan ahead until we find a different texture
9292                 endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
9293                 texturenumsurfaces = 0;
9294                 texturesurfacelist[texturenumsurfaces++] = surface;
9295                 if(FAKELIGHT_ENABLED)
9296                 {
9297                         rsurface.lightmaptexture = NULL;
9298                         rsurface.deluxemaptexture = NULL;
9299                         rsurface.uselightmaptexture = false;
9300                         for (;j < endsurface;j++)
9301                         {
9302                                 surface = rsurface.modelsurfaces + surfacelist[j];
9303                                 if (texture != surface->texture)
9304                                         break;
9305                                 texturesurfacelist[texturenumsurfaces++] = surface;
9306                         }
9307                 }
9308                 else
9309                 {
9310                         rsurface.lightmaptexture = surface->lightmaptexture;
9311                         rsurface.deluxemaptexture = surface->deluxemaptexture;
9312                         rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
9313                         for (;j < endsurface;j++)
9314                         {
9315                                 surface = rsurface.modelsurfaces + surfacelist[j];
9316                                 if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture)
9317                                         break;
9318                                 texturesurfacelist[texturenumsurfaces++] = surface;
9319                         }
9320                 }
9321                 // render the range of surfaces
9322                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false);
9323         }
9324         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
9325 }
9326
9327 static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
9328 {
9329         // transparent surfaces get pushed off into the transparent queue
9330         int surfacelistindex;
9331         const msurface_t *surface;
9332         vec3_t tempcenter, center;
9333         for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
9334         {
9335                 surface = texturesurfacelist[surfacelistindex];
9336                 if (r_transparent_sortsurfacesbynearest.integer)
9337                 {
9338                         tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]);
9339                         tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]);
9340                         tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]);
9341                 }
9342                 else
9343                 {
9344                         tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
9345                         tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
9346                         tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
9347                 }
9348                 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
9349                 if (rsurface.entity->transparent_offset) // transparent offset
9350                 {
9351                         center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset;
9352                         center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset;
9353                         center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset;
9354                 }
9355                 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);
9356         }
9357 }
9358
9359 static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist)
9360 {
9361         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
9362                 return;
9363         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
9364                 return;
9365         RSurf_SetupDepthAndCulling();
9366         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9367         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9368         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
9369         RSurf_DrawBatch();
9370 }
9371
9372 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass)
9373 {
9374         CHECKGLERROR
9375         if (depthonly)
9376                 R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
9377         else if (prepass)
9378         {
9379                 if (!rsurface.texture->currentnumlayers)
9380                         return;
9381                 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
9382                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9383                 else
9384                         R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
9385         }
9386         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3))
9387                 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
9388         else if (!rsurface.texture->currentnumlayers)
9389                 return;
9390         else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
9391         {
9392                 // in the deferred case, transparent surfaces were queued during prepass
9393                 if (!r_shadow_usingdeferredprepass)
9394                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9395         }
9396         else
9397         {
9398                 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
9399                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass);
9400         }
9401         CHECKGLERROR
9402 }
9403
9404 static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass)
9405 {
9406         int i, j;
9407         texture_t *texture;
9408         R_FrameData_SetMark();
9409         // break the surface list down into batches by texture and use of lightmapping
9410         for (i = 0;i < numsurfaces;i = j)
9411         {
9412                 j = i + 1;
9413                 // texture is the base texture pointer, rsurface.texture is the
9414                 // current frame/skin the texture is directing us to use (for example
9415                 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
9416                 // use skin 1 instead)
9417                 texture = surfacelist[i]->texture;
9418                 rsurface.texture = R_GetCurrentTexture(texture);
9419                 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
9420                 {
9421                         // if this texture is not the kind we want, skip ahead to the next one
9422                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9423                                 ;
9424                         continue;
9425                 }
9426                 if(FAKELIGHT_ENABLED || depthonly || prepass)
9427                 {
9428                         rsurface.lightmaptexture = NULL;
9429                         rsurface.deluxemaptexture = NULL;
9430                         rsurface.uselightmaptexture = false;
9431                         // simply scan ahead until we find a different texture or lightmap state
9432                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9433                                 ;
9434                 }
9435                 else
9436                 {
9437                         rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
9438                         rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
9439                         rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
9440                         // simply scan ahead until we find a different texture or lightmap state
9441                         for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
9442                                 ;
9443                 }
9444                 // render the range of surfaces
9445                 R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass);
9446         }
9447         R_FrameData_ReturnToMark();
9448 }
9449
9450 float locboxvertex3f[6*4*3] =
9451 {
9452         1,0,1, 1,0,0, 1,1,0, 1,1,1,
9453         0,1,1, 0,1,0, 0,0,0, 0,0,1,
9454         1,1,1, 1,1,0, 0,1,0, 0,1,1,
9455         0,0,1, 0,0,0, 1,0,0, 1,0,1,
9456         0,0,1, 1,0,1, 1,1,1, 0,1,1,
9457         1,0,0, 0,0,0, 0,1,0, 1,1,0
9458 };
9459
9460 unsigned short locboxelements[6*2*3] =
9461 {
9462          0, 1, 2, 0, 2, 3,
9463          4, 5, 6, 4, 6, 7,
9464          8, 9,10, 8,10,11,
9465         12,13,14, 12,14,15,
9466         16,17,18, 16,18,19,
9467         20,21,22, 20,22,23
9468 };
9469
9470 static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9471 {
9472         int i, j;
9473         cl_locnode_t *loc = (cl_locnode_t *)ent;
9474         vec3_t mins, size;
9475         float vertex3f[6*4*3];
9476         CHECKGLERROR
9477         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9478         GL_DepthMask(false);
9479         GL_DepthRange(0, 1);
9480         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9481         GL_DepthTest(true);
9482         GL_CullFace(GL_NONE);
9483         R_EntityMatrix(&identitymatrix);
9484
9485 //      R_Mesh_ResetTextureState();
9486
9487         i = surfacelist[0];
9488         GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9489                          ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9490                          ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9491                         surfacelist[0] < 0 ? 0.5f : 0.125f);
9492
9493         if (VectorCompare(loc->mins, loc->maxs))
9494         {
9495                 VectorSet(size, 2, 2, 2);
9496                 VectorMA(loc->mins, -0.5f, size, mins);
9497         }
9498         else
9499         {
9500                 VectorCopy(loc->mins, mins);
9501                 VectorSubtract(loc->maxs, loc->mins, size);
9502         }
9503
9504         for (i = 0;i < 6*4*3;)
9505                 for (j = 0;j < 3;j++, i++)
9506                         vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
9507
9508         R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
9509         R_SetupShader_Generic_NoTexture(false, false);
9510         R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
9511 }
9512
9513 void R_DrawLocs(void)
9514 {
9515         int index;
9516         cl_locnode_t *loc, *nearestloc;
9517         vec3_t center;
9518         nearestloc = CL_Locs_FindNearest(cl.movement_origin);
9519         for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
9520         {
9521                 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
9522                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
9523         }
9524 }
9525
9526 void R_DecalSystem_Reset(decalsystem_t *decalsystem)
9527 {
9528         if (decalsystem->decals)
9529                 Mem_Free(decalsystem->decals);
9530         memset(decalsystem, 0, sizeof(*decalsystem));
9531 }
9532
9533 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)
9534 {
9535         tridecal_t *decal;
9536         tridecal_t *decals;
9537         int i;
9538
9539         // expand or initialize the system
9540         if (decalsystem->maxdecals <= decalsystem->numdecals)
9541         {
9542                 decalsystem_t old = *decalsystem;
9543                 qboolean useshortelements;
9544                 decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2);
9545                 useshortelements = decalsystem->maxdecals * 3 <= 65536;
9546                 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)));
9547                 decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals);
9548                 decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12);
9549                 decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6);
9550                 decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
9551                 decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
9552                 if (decalsystem->numdecals)
9553                         memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
9554                 if (old.decals)
9555                         Mem_Free(old.decals);
9556                 for (i = 0;i < decalsystem->maxdecals*3;i++)
9557                         decalsystem->element3i[i] = i;
9558                 if (useshortelements)
9559                         for (i = 0;i < decalsystem->maxdecals*3;i++)
9560                                 decalsystem->element3s[i] = i;
9561         }
9562
9563         // grab a decal and search for another free slot for the next one
9564         decals = decalsystem->decals;
9565         decal = decalsystem->decals + (i = decalsystem->freedecal++);
9566         for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4f[0][3];i++)
9567                 ;
9568         decalsystem->freedecal = i;
9569         if (decalsystem->numdecals <= i)
9570                 decalsystem->numdecals = i + 1;
9571
9572         // initialize the decal
9573         decal->lived = 0;
9574         decal->triangleindex = triangleindex;
9575         decal->surfaceindex = surfaceindex;
9576         decal->decalsequence = decalsequence;
9577         decal->color4f[0][0] = c0[0];
9578         decal->color4f[0][1] = c0[1];
9579         decal->color4f[0][2] = c0[2];
9580         decal->color4f[0][3] = 1;
9581         decal->color4f[1][0] = c1[0];
9582         decal->color4f[1][1] = c1[1];
9583         decal->color4f[1][2] = c1[2];
9584         decal->color4f[1][3] = 1;
9585         decal->color4f[2][0] = c2[0];
9586         decal->color4f[2][1] = c2[1];
9587         decal->color4f[2][2] = c2[2];
9588         decal->color4f[2][3] = 1;
9589         decal->vertex3f[0][0] = v0[0];
9590         decal->vertex3f[0][1] = v0[1];
9591         decal->vertex3f[0][2] = v0[2];
9592         decal->vertex3f[1][0] = v1[0];
9593         decal->vertex3f[1][1] = v1[1];
9594         decal->vertex3f[1][2] = v1[2];
9595         decal->vertex3f[2][0] = v2[0];
9596         decal->vertex3f[2][1] = v2[1];
9597         decal->vertex3f[2][2] = v2[2];
9598         decal->texcoord2f[0][0] = t0[0];
9599         decal->texcoord2f[0][1] = t0[1];
9600         decal->texcoord2f[1][0] = t1[0];
9601         decal->texcoord2f[1][1] = t1[1];
9602         decal->texcoord2f[2][0] = t2[0];
9603         decal->texcoord2f[2][1] = t2[1];
9604         TriangleNormal(v0, v1, v2, decal->plane);
9605         VectorNormalize(decal->plane);
9606         decal->plane[3] = DotProduct(v0, decal->plane);
9607 }
9608
9609 extern cvar_t cl_decals_bias;
9610 extern cvar_t cl_decals_models;
9611 extern cvar_t cl_decals_newsystem_intensitymultiplier;
9612 // baseparms, parms, temps
9613 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)
9614 {
9615         int cornerindex;
9616         int index;
9617         float v[9][3];
9618         const float *vertex3f;
9619         const float *normal3f;
9620         int numpoints;
9621         float points[2][9][3];
9622         float temp[3];
9623         float tc[9][2];
9624         float f;
9625         float c[9][4];
9626         const int *e;
9627
9628         e = rsurface.modelelement3i + 3*triangleindex;
9629
9630         vertex3f = rsurface.modelvertex3f;
9631         normal3f = rsurface.modelnormal3f;
9632
9633         if (normal3f)
9634         {
9635                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9636                 {
9637                         index = 3*e[cornerindex];
9638                         VectorMA(vertex3f + index, cl_decals_bias.value, normal3f + index, v[cornerindex]);
9639                 }
9640         }
9641         else
9642         {
9643                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9644                 {
9645                         index = 3*e[cornerindex];
9646                         VectorCopy(vertex3f + index, v[cornerindex]);
9647                 }
9648         }
9649
9650         // cull backfaces
9651         //TriangleNormal(v[0], v[1], v[2], normal);
9652         //if (DotProduct(normal, localnormal) < 0.0f)
9653         //      continue;
9654         // clip by each of the box planes formed from the projection matrix
9655         // if anything survives, we emit the decal
9656         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]);
9657         if (numpoints < 3)
9658                 return;
9659         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]);
9660         if (numpoints < 3)
9661                 return;
9662         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]);
9663         if (numpoints < 3)
9664                 return;
9665         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]);
9666         if (numpoints < 3)
9667                 return;
9668         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]);
9669         if (numpoints < 3)
9670                 return;
9671         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]);
9672         if (numpoints < 3)
9673                 return;
9674         // some part of the triangle survived, so we have to accept it...
9675         if (dynamic)
9676         {
9677                 // dynamic always uses the original triangle
9678                 numpoints = 3;
9679                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9680                 {
9681                         index = 3*e[cornerindex];
9682                         VectorCopy(vertex3f + index, v[cornerindex]);
9683                 }
9684         }
9685         for (cornerindex = 0;cornerindex < numpoints;cornerindex++)
9686         {
9687                 // convert vertex positions to texcoords
9688                 Matrix4x4_Transform(projection, v[cornerindex], temp);
9689                 tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
9690                 tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
9691                 // calculate distance fade from the projection origin
9692                 f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
9693                 f = bound(0.0f, f, 1.0f);
9694                 c[cornerindex][0] = r * f;
9695                 c[cornerindex][1] = g * f;
9696                 c[cornerindex][2] = b * f;
9697                 c[cornerindex][3] = 1.0f;
9698                 //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
9699         }
9700         if (dynamic)
9701                 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);
9702         else
9703                 for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
9704                         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);
9705 }
9706 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)
9707 {
9708         matrix4x4_t projection;
9709         decalsystem_t *decalsystem;
9710         qboolean dynamic;
9711         dp_model_t *model;
9712         const msurface_t *surface;
9713         const msurface_t *surfaces;
9714         const int *surfacelist;
9715         const texture_t *texture;
9716         int numtriangles;
9717         int numsurfacelist;
9718         int surfacelistindex;
9719         int surfaceindex;
9720         int triangleindex;
9721         float localorigin[3];
9722         float localnormal[3];
9723         float localmins[3];
9724         float localmaxs[3];
9725         float localsize;
9726         //float normal[3];
9727         float planes[6][4];
9728         float angles[3];
9729         bih_t *bih;
9730         int bih_triangles_count;
9731         int bih_triangles[256];
9732         int bih_surfaces[256];
9733
9734         decalsystem = &ent->decalsystem;
9735         model = ent->model;
9736         if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST)))
9737         {
9738                 R_DecalSystem_Reset(&ent->decalsystem);
9739                 return;
9740         }
9741
9742         if (!model->brush.data_leafs && !cl_decals_models.integer)
9743         {
9744                 if (decalsystem->model)
9745                         R_DecalSystem_Reset(decalsystem);
9746                 return;
9747         }
9748
9749         if (decalsystem->model != model)
9750                 R_DecalSystem_Reset(decalsystem);
9751         decalsystem->model = model;
9752
9753         RSurf_ActiveModelEntity(ent, true, false, false);
9754
9755         Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
9756         Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
9757         VectorNormalize(localnormal);
9758         localsize = worldsize*rsurface.inversematrixscale;
9759         localmins[0] = localorigin[0] - localsize;
9760         localmins[1] = localorigin[1] - localsize;
9761         localmins[2] = localorigin[2] - localsize;
9762         localmaxs[0] = localorigin[0] + localsize;
9763         localmaxs[1] = localorigin[1] + localsize;
9764         localmaxs[2] = localorigin[2] + localsize;
9765
9766         //VectorCopy(localnormal, planes[4]);
9767         //VectorVectors(planes[4], planes[2], planes[0]);
9768         AnglesFromVectors(angles, localnormal, NULL, false);
9769         AngleVectors(angles, planes[0], planes[2], planes[4]);
9770         VectorNegate(planes[0], planes[1]);
9771         VectorNegate(planes[2], planes[3]);
9772         VectorNegate(planes[4], planes[5]);
9773         planes[0][3] = DotProduct(planes[0], localorigin) - localsize;
9774         planes[1][3] = DotProduct(planes[1], localorigin) - localsize;
9775         planes[2][3] = DotProduct(planes[2], localorigin) - localsize;
9776         planes[3][3] = DotProduct(planes[3], localorigin) - localsize;
9777         planes[4][3] = DotProduct(planes[4], localorigin) - localsize;
9778         planes[5][3] = DotProduct(planes[5], localorigin) - localsize;
9779
9780 #if 1
9781 // works
9782 {
9783         matrix4x4_t forwardprojection;
9784         Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize);
9785         Matrix4x4_Invert_Simple(&projection, &forwardprojection);
9786 }
9787 #else
9788 // broken
9789 {
9790         float projectionvector[4][3];
9791         VectorScale(planes[0], ilocalsize, projectionvector[0]);
9792         VectorScale(planes[2], ilocalsize, projectionvector[1]);
9793         VectorScale(planes[4], ilocalsize, projectionvector[2]);
9794         projectionvector[0][0] = planes[0][0] * ilocalsize;
9795         projectionvector[0][1] = planes[1][0] * ilocalsize;
9796         projectionvector[0][2] = planes[2][0] * ilocalsize;
9797         projectionvector[1][0] = planes[0][1] * ilocalsize;
9798         projectionvector[1][1] = planes[1][1] * ilocalsize;
9799         projectionvector[1][2] = planes[2][1] * ilocalsize;
9800         projectionvector[2][0] = planes[0][2] * ilocalsize;
9801         projectionvector[2][1] = planes[1][2] * ilocalsize;
9802         projectionvector[2][2] = planes[2][2] * ilocalsize;
9803         projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]);
9804         projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]);
9805         projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]);
9806         Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]);
9807 }
9808 #endif
9809
9810         dynamic = model->surfmesh.isanimated;
9811         numsurfacelist = model->nummodelsurfaces;
9812         surfacelist = model->sortedmodelsurfaces;
9813         surfaces = model->data_surfaces;
9814
9815         bih = NULL;
9816         bih_triangles_count = -1;
9817         if(!dynamic)
9818         {
9819                 if(model->render_bih.numleafs)
9820                         bih = &model->render_bih;
9821                 else if(model->collision_bih.numleafs)
9822                         bih = &model->collision_bih;
9823         }
9824         if(bih)
9825                 bih_triangles_count = BIH_GetTriangleListForBox(bih, sizeof(bih_triangles) / sizeof(*bih_triangles), bih_triangles, bih_surfaces, localmins, localmaxs);
9826         if(bih_triangles_count == 0)
9827                 return;
9828         if(bih_triangles_count > (int) (sizeof(bih_triangles) / sizeof(*bih_triangles))) // hit too many, likely bad anyway
9829                 return;
9830         if(bih_triangles_count > 0)
9831         {
9832                 for (triangleindex = 0; triangleindex < bih_triangles_count; ++triangleindex)
9833                 {
9834                         surfaceindex = bih_surfaces[triangleindex];
9835                         surface = surfaces + surfaceindex;
9836                         texture = surface->texture;
9837                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9838                                 continue;
9839                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9840                                 continue;
9841                         R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, bih_triangles[triangleindex], surfaceindex);
9842                 }
9843         }
9844         else
9845         {
9846                 for (surfacelistindex = 0;surfacelistindex < numsurfacelist;surfacelistindex++)
9847                 {
9848                         surfaceindex = surfacelist[surfacelistindex];
9849                         surface = surfaces + surfaceindex;
9850                         // check cull box first because it rejects more than any other check
9851                         if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
9852                                 continue;
9853                         // skip transparent surfaces
9854                         texture = surface->texture;
9855                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9856                                 continue;
9857                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9858                                 continue;
9859                         numtriangles = surface->num_triangles;
9860                         for (triangleindex = 0; triangleindex < numtriangles; triangleindex++)
9861                                 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, triangleindex + surface->num_firsttriangle, surfaceindex);
9862                 }
9863         }
9864 }
9865
9866 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
9867 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)
9868 {
9869         int renderentityindex;
9870         float worldmins[3];
9871         float worldmaxs[3];
9872         entity_render_t *ent;
9873
9874         if (!cl_decals_newsystem.integer)
9875                 return;
9876
9877         worldmins[0] = worldorigin[0] - worldsize;
9878         worldmins[1] = worldorigin[1] - worldsize;
9879         worldmins[2] = worldorigin[2] - worldsize;
9880         worldmaxs[0] = worldorigin[0] + worldsize;
9881         worldmaxs[1] = worldorigin[1] + worldsize;
9882         worldmaxs[2] = worldorigin[2] + worldsize;
9883
9884         R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9885
9886         for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
9887         {
9888                 ent = r_refdef.scene.entities[renderentityindex];
9889                 if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
9890                         continue;
9891
9892                 R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9893         }
9894 }
9895
9896 typedef struct r_decalsystem_splatqueue_s
9897 {
9898         vec3_t worldorigin;
9899         vec3_t worldnormal;
9900         float color[4];
9901         float tcrange[4];
9902         float worldsize;
9903         unsigned int decalsequence;
9904 }
9905 r_decalsystem_splatqueue_t;
9906
9907 int r_decalsystem_numqueued = 0;
9908 r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
9909
9910 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)
9911 {
9912         r_decalsystem_splatqueue_t *queue;
9913
9914         if (!cl_decals_newsystem.integer || r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
9915                 return;
9916
9917         queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
9918         VectorCopy(worldorigin, queue->worldorigin);
9919         VectorCopy(worldnormal, queue->worldnormal);
9920         Vector4Set(queue->color, r, g, b, a);
9921         Vector4Set(queue->tcrange, s1, t1, s2, t2);
9922         queue->worldsize = worldsize;
9923         queue->decalsequence = cl.decalsequence++;
9924 }
9925
9926 static void R_DecalSystem_ApplySplatEntitiesQueue(void)
9927 {
9928         int i;
9929         r_decalsystem_splatqueue_t *queue;
9930
9931         for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
9932                 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);
9933         r_decalsystem_numqueued = 0;
9934 }
9935
9936 extern cvar_t cl_decals_max;
9937 static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
9938 {
9939         int i;
9940         decalsystem_t *decalsystem = &ent->decalsystem;
9941         int numdecals;
9942         unsigned int killsequence;
9943         tridecal_t *decal;
9944         float frametime;
9945         float lifetime;
9946
9947         if (!decalsystem->numdecals)
9948                 return;
9949
9950         if (r_showsurfaces.integer)
9951                 return;
9952
9953         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9954         {
9955                 R_DecalSystem_Reset(decalsystem);
9956                 return;
9957         }
9958
9959         killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
9960         lifetime = cl_decals_time.value + cl_decals_fadetime.value;
9961
9962         if (decalsystem->lastupdatetime)
9963                 frametime = (r_refdef.scene.time - decalsystem->lastupdatetime);
9964         else
9965                 frametime = 0;
9966         decalsystem->lastupdatetime = r_refdef.scene.time;
9967         numdecals = decalsystem->numdecals;
9968
9969         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9970         {
9971                 if (decal->color4f[0][3])
9972                 {
9973                         decal->lived += frametime;
9974                         if (killsequence > decal->decalsequence || decal->lived >= lifetime)
9975                         {
9976                                 memset(decal, 0, sizeof(*decal));
9977                                 if (decalsystem->freedecal > i)
9978                                         decalsystem->freedecal = i;
9979                         }
9980                 }
9981         }
9982         decal = decalsystem->decals;
9983         while (numdecals > 0 && !decal[numdecals-1].color4f[0][3])
9984                 numdecals--;
9985
9986         // collapse the array by shuffling the tail decals into the gaps
9987         for (;;)
9988         {
9989                 while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4f[0][3])
9990                         decalsystem->freedecal++;
9991                 if (decalsystem->freedecal == numdecals)
9992                         break;
9993                 decal[decalsystem->freedecal] = decal[--numdecals];
9994         }
9995
9996         decalsystem->numdecals = numdecals;
9997
9998         if (numdecals <= 0)
9999         {
10000                 // if there are no decals left, reset decalsystem
10001                 R_DecalSystem_Reset(decalsystem);
10002         }
10003 }
10004
10005 extern skinframe_t *decalskinframe;
10006 static void R_DrawModelDecals_Entity(entity_render_t *ent)
10007 {
10008         int i;
10009         decalsystem_t *decalsystem = &ent->decalsystem;
10010         int numdecals;
10011         tridecal_t *decal;
10012         float faderate;
10013         float alpha;
10014         float *v3f;
10015         float *c4f;
10016         float *t2f;
10017         const int *e;
10018         const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
10019         int numtris = 0;
10020
10021         numdecals = decalsystem->numdecals;
10022         if (!numdecals)
10023                 return;
10024
10025         if (r_showsurfaces.integer)
10026                 return;
10027
10028         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
10029         {
10030                 R_DecalSystem_Reset(decalsystem);
10031                 return;
10032         }
10033
10034         // if the model is static it doesn't matter what value we give for
10035         // wantnormals and wanttangents, so this logic uses only rules applicable
10036         // to a model, knowing that they are meaningless otherwise
10037         RSurf_ActiveModelEntity(ent, false, false, false);
10038
10039         decalsystem->lastupdatetime = r_refdef.scene.time;
10040
10041         faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
10042
10043         // update vertex positions for animated models
10044         v3f = decalsystem->vertex3f;
10045         c4f = decalsystem->color4f;
10046         t2f = decalsystem->texcoord2f;
10047         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
10048         {
10049                 if (!decal->color4f[0][3])
10050                         continue;
10051
10052                 if (surfacevisible && !surfacevisible[decal->surfaceindex])
10053                         continue;
10054
10055                 // skip backfaces
10056                 if (decal->triangleindex < 0 && DotProduct(r_refdef.view.origin, decal->plane) < decal->plane[3])
10057                         continue;
10058
10059                 // update color values for fading decals
10060                 if (decal->lived >= cl_decals_time.value)
10061                         alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
10062                 else
10063                         alpha = 1.0f;
10064
10065                 c4f[ 0] = decal->color4f[0][0] * alpha;
10066                 c4f[ 1] = decal->color4f[0][1] * alpha;
10067                 c4f[ 2] = decal->color4f[0][2] * alpha;
10068                 c4f[ 3] = 1;
10069                 c4f[ 4] = decal->color4f[1][0] * alpha;
10070                 c4f[ 5] = decal->color4f[1][1] * alpha;
10071                 c4f[ 6] = decal->color4f[1][2] * alpha;
10072                 c4f[ 7] = 1;
10073                 c4f[ 8] = decal->color4f[2][0] * alpha;
10074                 c4f[ 9] = decal->color4f[2][1] * alpha;
10075                 c4f[10] = decal->color4f[2][2] * alpha;
10076                 c4f[11] = 1;
10077
10078                 t2f[0] = decal->texcoord2f[0][0];
10079                 t2f[1] = decal->texcoord2f[0][1];
10080                 t2f[2] = decal->texcoord2f[1][0];
10081                 t2f[3] = decal->texcoord2f[1][1];
10082                 t2f[4] = decal->texcoord2f[2][0];
10083                 t2f[5] = decal->texcoord2f[2][1];
10084
10085                 // update vertex positions for animated models
10086                 if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
10087                 {
10088                         e = rsurface.modelelement3i + 3*decal->triangleindex;
10089                         VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f);
10090                         VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3);
10091                         VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6);
10092                 }
10093                 else
10094                 {
10095                         VectorCopy(decal->vertex3f[0], v3f);
10096                         VectorCopy(decal->vertex3f[1], v3f + 3);
10097                         VectorCopy(decal->vertex3f[2], v3f + 6);
10098                 }
10099
10100                 if (r_refdef.fogenabled)
10101                 {
10102                         alpha = RSurf_FogVertex(v3f);
10103                         VectorScale(c4f, alpha, c4f);
10104                         alpha = RSurf_FogVertex(v3f + 3);
10105                         VectorScale(c4f + 4, alpha, c4f + 4);
10106                         alpha = RSurf_FogVertex(v3f + 6);
10107                         VectorScale(c4f + 8, alpha, c4f + 8);
10108                 }
10109
10110                 v3f += 9;
10111                 c4f += 12;
10112                 t2f += 6;
10113                 numtris++;
10114         }
10115
10116         if (numtris > 0)
10117         {
10118                 r_refdef.stats[r_stat_drawndecals] += numtris;
10119
10120                 // now render the decals all at once
10121                 // (this assumes they all use one particle font texture!)
10122                 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);
10123 //              R_Mesh_ResetTextureState();
10124                 R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
10125                 GL_DepthMask(false);
10126                 GL_DepthRange(0, 1);
10127                 GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
10128                 GL_DepthTest(true);
10129                 GL_CullFace(GL_NONE);
10130                 GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
10131                 R_SetupShader_Generic(decalskinframe->base, NULL, GL_MODULATE, 1, false, false, false);
10132                 R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
10133         }
10134 }
10135
10136 static void R_DrawModelDecals(void)
10137 {
10138         int i, numdecals;
10139
10140         // fade faster when there are too many decals
10141         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
10142         for (i = 0;i < r_refdef.scene.numentities;i++)
10143                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
10144
10145         R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
10146         for (i = 0;i < r_refdef.scene.numentities;i++)
10147                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
10148                         R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
10149
10150         R_DecalSystem_ApplySplatEntitiesQueue();
10151
10152         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
10153         for (i = 0;i < r_refdef.scene.numentities;i++)
10154                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
10155
10156         r_refdef.stats[r_stat_totaldecals] += numdecals;
10157
10158         if (r_showsurfaces.integer)
10159                 return;
10160
10161         R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
10162
10163         for (i = 0;i < r_refdef.scene.numentities;i++)
10164         {
10165                 if (!r_refdef.viewcache.entityvisible[i])
10166                         continue;
10167                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
10168                         R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
10169         }
10170 }
10171
10172 extern cvar_t mod_collision_bih;
10173 static void R_DrawDebugModel(void)
10174 {
10175         entity_render_t *ent = rsurface.entity;
10176         int i, j, flagsmask;
10177         const msurface_t *surface;
10178         dp_model_t *model = ent->model;
10179
10180         if (!sv.active  && !cls.demoplayback && ent != r_refdef.scene.worldentity)
10181                 return;
10182
10183         if (r_showoverdraw.value > 0)
10184         {
10185                 float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
10186                 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
10187                 R_SetupShader_Generic_NoTexture(false, false);
10188                 GL_DepthTest(false);
10189                 GL_DepthMask(false);
10190                 GL_DepthRange(0, 1);
10191                 GL_BlendFunc(GL_ONE, GL_ONE);
10192                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
10193                 {
10194                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
10195                                 continue;
10196                         rsurface.texture = R_GetCurrentTexture(surface->texture);
10197                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
10198                         {
10199                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface);
10200                                 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
10201                                 if (!rsurface.texture->currentlayers->depthmask)
10202                                         GL_Color(c, 0, 0, 1.0f);
10203                                 else if (ent == r_refdef.scene.worldentity)
10204                                         GL_Color(c, c, c, 1.0f);
10205                                 else
10206                                         GL_Color(0, c, 0, 1.0f);
10207                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
10208                                 RSurf_DrawBatch();
10209                         }
10210                 }
10211                 rsurface.texture = NULL;
10212         }
10213
10214         flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
10215
10216 //      R_Mesh_ResetTextureState();
10217         R_SetupShader_Generic_NoTexture(false, false);
10218         GL_DepthRange(0, 1);
10219         GL_DepthTest(!r_showdisabledepthtest.integer);
10220         GL_DepthMask(false);
10221         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
10222
10223         if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs)
10224         {
10225                 int triangleindex;
10226                 int bihleafindex;
10227                 qboolean cullbox = false;
10228                 const q3mbrush_t *brush;
10229                 const bih_t *bih = &model->collision_bih;
10230                 const bih_leaf_t *bihleaf;
10231                 float vertex3f[3][3];
10232                 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
10233                 for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
10234                 {
10235                         if (cullbox && R_CullBox(bihleaf->mins, bihleaf->maxs))
10236                                 continue;
10237                         switch (bihleaf->type)
10238                         {
10239                         case BIH_BRUSH:
10240                                 brush = model->brush.data_brushes + bihleaf->itemindex;
10241                                 if (brush->colbrushf && brush->colbrushf->numtriangles)
10242                                 {
10243                                         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);
10244                                         R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL);
10245                                         R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0);
10246                                 }
10247                                 break;
10248                         case BIH_COLLISIONTRIANGLE:
10249                                 triangleindex = bihleaf->itemindex;
10250                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
10251                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
10252                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
10253                                 GL_Color((bihleafindex & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 5) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, ((bihleafindex >> 10) & 31) * (1.0f / 32.0f) * r_refdef.view.colorscale, r_showcollisionbrushes.value);
10254                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
10255                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
10256                                 break;
10257                         case BIH_RENDERTRIANGLE:
10258                                 triangleindex = bihleaf->itemindex;
10259                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
10260                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
10261                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[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                         }
10267                 }
10268         }
10269
10270         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
10271
10272 #ifndef USE_GLES2
10273         if (r_showtris.value > 0 && qglPolygonMode)
10274         {
10275                 if (r_showdisabledepthtest.integer)
10276                 {
10277                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
10278                         GL_DepthMask(false);
10279                 }
10280                 else
10281                 {
10282                         GL_BlendFunc(GL_ONE, GL_ZERO);
10283                         GL_DepthMask(true);
10284                 }
10285                 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR
10286                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
10287                 {
10288                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
10289                                 continue;
10290                         rsurface.texture = R_GetCurrentTexture(surface->texture);
10291                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
10292                         {
10293                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
10294                                 if (!rsurface.texture->currentlayers->depthmask)
10295                                         GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value);
10296                                 else if (ent == r_refdef.scene.worldentity)
10297                                         GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
10298                                 else
10299                                         GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
10300                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
10301                                 RSurf_DrawBatch();
10302                         }
10303                 }
10304                 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);CHECKGLERROR
10305                 rsurface.texture = NULL;
10306         }
10307
10308 # if 0
10309         // FIXME!  implement r_shownormals with just triangles
10310         if (r_shownormals.value != 0 && qglBegin)
10311         {
10312                 int l, k;
10313                 vec3_t v;
10314                 if (r_showdisabledepthtest.integer)
10315                 {
10316                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
10317                         GL_DepthMask(false);
10318                 }
10319                 else
10320                 {
10321                         GL_BlendFunc(GL_ONE, GL_ZERO);
10322                         GL_DepthMask(true);
10323                 }
10324                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
10325                 {
10326                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
10327                                 continue;
10328                         rsurface.texture = R_GetCurrentTexture(surface->texture);
10329                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
10330                         {
10331                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
10332                                 qglBegin(GL_LINES);
10333                                 if (r_shownormals.value < 0 && rsurface.batchnormal3f)
10334                                 {
10335                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10336                                         {
10337                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10338                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10339                                                 qglVertex3f(v[0], v[1], v[2]);
10340                                                 VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10341                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10342                                                 qglVertex3f(v[0], v[1], v[2]);
10343                                         }
10344                                 }
10345                                 if (r_shownormals.value > 0 && rsurface.batchsvector3f)
10346                                 {
10347                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10348                                         {
10349                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10350                                                 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
10351                                                 qglVertex3f(v[0], v[1], v[2]);
10352                                                 VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
10353                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10354                                                 qglVertex3f(v[0], v[1], v[2]);
10355                                         }
10356                                 }
10357                                 if (r_shownormals.value > 0 && rsurface.batchtvector3f)
10358                                 {
10359                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10360                                         {
10361                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10362                                                 GL_Color(0, r_refdef.view.colorscale, 0, 1);
10363                                                 qglVertex3f(v[0], v[1], v[2]);
10364                                                 VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
10365                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10366                                                 qglVertex3f(v[0], v[1], v[2]);
10367                                         }
10368                                 }
10369                                 if (r_shownormals.value > 0 && rsurface.batchnormal3f)
10370                                 {
10371                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10372                                         {
10373                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10374                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10375                                                 qglVertex3f(v[0], v[1], v[2]);
10376                                                 VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10377                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10378                                                 qglVertex3f(v[0], v[1], v[2]);
10379                                         }
10380                                 }
10381                                 qglEnd();
10382                                 CHECKGLERROR
10383                         }
10384                 }
10385                 rsurface.texture = NULL;
10386         }
10387 # endif
10388 #endif
10389 }
10390
10391 int r_maxsurfacelist = 0;
10392 const msurface_t **r_surfacelist = NULL;
10393 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass)
10394 {
10395         int i, j, endj, flagsmask;
10396         dp_model_t *model = ent->model;
10397         msurface_t *surfaces;
10398         unsigned char *update;
10399         int numsurfacelist = 0;
10400         if (model == NULL)
10401                 return;
10402
10403         if (r_maxsurfacelist < model->num_surfaces)
10404         {
10405                 r_maxsurfacelist = model->num_surfaces;
10406                 if (r_surfacelist)
10407                         Mem_Free((msurface_t **)r_surfacelist);
10408                 r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
10409         }
10410
10411         if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
10412                 RSurf_ActiveModelEntity(ent, false, false, false);
10413         else if (prepass)
10414                 RSurf_ActiveModelEntity(ent, true, true, true);
10415         else if (depthonly)
10416                 RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
10417         else
10418                 RSurf_ActiveModelEntity(ent, true, true, false);
10419
10420         surfaces = model->data_surfaces;
10421         update = model->brushq1.lightmapupdateflags;
10422
10423         // update light styles
10424         if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0)
10425         {
10426                 model_brush_lightstyleinfo_t *style;
10427                 for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++)
10428                 {
10429                         if (style->value != r_refdef.scene.lightstylevalue[style->style])
10430                         {
10431                                 int *list = style->surfacelist;
10432                                 style->value = r_refdef.scene.lightstylevalue[style->style];
10433                                 for (j = 0;j < style->numsurfaces;j++)
10434                                         update[list[j]] = true;
10435                         }
10436                 }
10437         }
10438
10439         flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
10440
10441         if (debug)
10442         {
10443                 R_DrawDebugModel();
10444                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10445                 return;
10446         }
10447
10448         rsurface.lightmaptexture = NULL;
10449         rsurface.deluxemaptexture = NULL;
10450         rsurface.uselightmaptexture = false;
10451         rsurface.texture = NULL;
10452         rsurface.rtlight = NULL;
10453         numsurfacelist = 0;
10454         // add visible surfaces to draw list
10455         if (ent == r_refdef.scene.worldentity)
10456         {
10457                 // for the world entity, check surfacevisible
10458                 for (i = 0;i < model->nummodelsurfaces;i++)
10459                 {
10460                         j = model->sortedmodelsurfaces[i];
10461                         if (r_refdef.viewcache.world_surfacevisible[j])
10462                                 r_surfacelist[numsurfacelist++] = surfaces + j;
10463                 }
10464         }
10465         else
10466         {
10467                 // add all surfaces
10468                 for (i = 0; i < model->nummodelsurfaces; i++)
10469                         r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i];
10470         }
10471         // don't do anything if there were no surfaces
10472         if (!numsurfacelist)
10473         {
10474                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10475                 return;
10476         }
10477         // update lightmaps if needed
10478         if (update)
10479         {
10480                 int updated = 0;
10481                 for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
10482                 {
10483                         if (update[j])
10484                         {
10485                                 updated++;
10486                                 R_BuildLightMap(ent, surfaces + j);
10487                         }
10488                 }
10489         }
10490
10491         R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass);
10492
10493         // add to stats if desired
10494         if (r_speeds.integer && !skysurfaces && !depthonly)
10495         {
10496                 r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist;
10497                 for (j = 0;j < numsurfacelist;j++)
10498                         r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
10499         }
10500
10501         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10502 }
10503
10504 void R_DebugLine(vec3_t start, vec3_t end)
10505 {
10506         dp_model_t *mod = CL_Mesh_UI();
10507         msurface_t *surf;
10508         int e0, e1, e2, e3;
10509         float offsetx, offsety, x1, y1, x2, y2, width = 1.0f;
10510         float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f, alpha1 = 0.25f;
10511         float r2 = 1.0f, g2 = 1.0f, b2 = 0.0f, alpha2 = 0.25f;
10512         vec4_t w[2], s[2];
10513
10514         // transform to screen coords first
10515         Vector4Set(w[0], start[0], start[1], start[2], 1);
10516         Vector4Set(w[1], end[0], end[1], end[2], 1);
10517         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
10518         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
10519         x1 = s[0][0] * vid_conwidth.value / vid.width;
10520         y1 = (vid.height - s[0][1]) * vid_conheight.value / vid.height;
10521         x2 = s[1][0] * vid_conwidth.value / vid.width;
10522         y2 = (vid.height - s[1][1]) * vid_conheight.value / vid.height;
10523         //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
10524
10525         // add the line to the UI mesh for drawing later
10526
10527         // width is measured in real pixels
10528         if (fabs(x2 - x1) > fabs(y2 - y1))
10529         {
10530                 offsetx = 0;
10531                 offsety = 0.5f * width * vid_conheight.value / vid.height;
10532         }
10533         else
10534         {
10535                 offsetx = 0.5f * width * vid_conwidth.value / vid.width;
10536                 offsety = 0;
10537         }
10538         surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, "white", 0, 0, MATERIALFLAG_VERTEXCOLOR), true);
10539         e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10540         e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10541         e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10542         e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10543         Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
10544         Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
10545
10546 }
10547
10548
10549 void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass)
10550 {
10551         int q;
10552         static texture_t texture;
10553         static msurface_t surface;
10554         const msurface_t *surfacelist = &surface;
10555
10556         // fake enough texture and surface state to render this geometry
10557
10558         texture.update_lastrenderframe = -1; // regenerate this texture
10559         texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
10560         texture.basealpha = 1.0f;
10561         texture.currentskinframe = skinframe;
10562         texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
10563         texture.offsetmapping = OFFSETMAPPING_OFF;
10564         texture.offsetscale = 1;
10565         texture.specularscalemod = 1;
10566         texture.specularpowermod = 1;
10567         texture.transparentsort = TRANSPARENTSORT_DISTANCE;
10568         // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
10569         // JUST GREP FOR "specularscalemod = 1".
10570
10571         for (q = 0; q < 3; q++)
10572         {
10573                 texture.render_glowmod[q] = r_refdef.view.colorscale * r_hdr_glowintensity.value;
10574                 texture.render_modellight_lightdir[q] = q == 2;
10575                 texture.render_modellight_ambient[q] = r_refdef.view.colorscale * r_refdef.scene.ambientintensity;
10576                 texture.render_modellight_diffuse[q] = r_refdef.view.colorscale;
10577                 texture.render_modellight_specular[q] = r_refdef.view.colorscale;
10578                 texture.render_lightmap_ambient[q] = r_refdef.view.colorscale * r_refdef.scene.ambientintensity;
10579                 texture.render_lightmap_diffuse[q] = r_refdef.view.colorscale * r_refdef.scene.lightmapintensity;
10580                 texture.render_lightmap_specular[q] = r_refdef.view.colorscale;
10581                 texture.render_rtlight_diffuse[q] = r_refdef.view.colorscale;
10582                 texture.render_rtlight_specular[q] = r_refdef.view.colorscale;
10583         }
10584         texture.currentalpha = 1.0f;
10585
10586         surface.texture = &texture;
10587         surface.num_triangles = numtriangles;
10588         surface.num_firsttriangle = firsttriangle;
10589         surface.num_vertices = numvertices;
10590         surface.num_firstvertex = firstvertex;
10591
10592         // now render it
10593         rsurface.texture = R_GetCurrentTexture(surface.texture);
10594         rsurface.lightmaptexture = NULL;
10595         rsurface.deluxemaptexture = NULL;
10596         rsurface.uselightmaptexture = false;
10597         R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass);
10598 }
10599
10600 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)
10601 {
10602         static msurface_t surface;
10603         const msurface_t *surfacelist = &surface;
10604
10605         // fake enough texture and surface state to render this geometry
10606         surface.texture = texture;
10607         surface.num_triangles = numtriangles;
10608         surface.num_firsttriangle = firsttriangle;
10609         surface.num_vertices = numvertices;
10610         surface.num_firstvertex = firstvertex;
10611
10612         // now render it
10613         rsurface.texture = R_GetCurrentTexture(surface.texture);
10614         rsurface.lightmaptexture = NULL;
10615         rsurface.deluxemaptexture = NULL;
10616         rsurface.uselightmaptexture = false;
10617         R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass);
10618 }