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