]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rmain.c
Refactored and improved Mod_ValidateElements so it also validates element3s and has...
[xonotic/darkplaces.git] / gl_rmain.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // r_main.c
21
22 #include "quakedef.h"
23 #include "r_shadow.h"
24 #include "polygon.h"
25 #include "image.h"
26 #include "ft2.h"
27 #include "csprogs.h"
28 #include "cl_video.h"
29 #include "cl_collision.h"
30
31 #ifdef WIN32
32 // Enable NVIDIA High Performance Graphics while using Integrated Graphics.
33 #ifdef __cplusplus
34 extern "C" {
35 #endif
36 __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
37 #ifdef __cplusplus
38 }
39 #endif
40 #endif
41
42 mempool_t *r_main_mempool;
43 rtexturepool_t *r_main_texturepool;
44
45 static int r_textureframe = 0; ///< used only by R_GetCurrentTexture
46
47 static qboolean r_loadnormalmap;
48 static qboolean r_loadgloss;
49 qboolean r_loadfog;
50 static qboolean r_loaddds;
51 static qboolean r_savedds;
52 static qboolean r_gpuskeletal;
53
54 //
55 // screen size info
56 //
57 r_refdef_t r_refdef;
58
59 cvar_t r_motionblur = {CVAR_SAVE, "r_motionblur", "0", "screen motionblur - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
60 cvar_t r_damageblur = {CVAR_SAVE, "r_damageblur", "0", "screen motionblur based on damage - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
61 cvar_t r_motionblur_averaging = {CVAR_SAVE, "r_motionblur_averaging", "0.1", "sliding average reaction time for velocity (higher = slower adaption to change)"};
62 cvar_t r_motionblur_randomize = {CVAR_SAVE, "r_motionblur_randomize", "0.1", "randomizing coefficient to workaround ghosting"};
63 cvar_t r_motionblur_minblur = {CVAR_SAVE, "r_motionblur_minblur", "0.5", "factor of blur to apply at all times (always have this amount of blur no matter what the other factors are)"};
64 cvar_t r_motionblur_maxblur = {CVAR_SAVE, "r_motionblur_maxblur", "0.9", "maxmimum amount of blur"};
65 cvar_t r_motionblur_velocityfactor = {CVAR_SAVE, "r_motionblur_velocityfactor", "1", "factoring in of player velocity to the blur equation - the faster the player moves around the map, the more blur they get"};
66 cvar_t r_motionblur_velocityfactor_minspeed = {CVAR_SAVE, "r_motionblur_velocityfactor_minspeed", "400", "lower value of velocity when it starts to factor into blur equation"};
67 cvar_t r_motionblur_velocityfactor_maxspeed = {CVAR_SAVE, "r_motionblur_velocityfactor_maxspeed", "800", "upper value of velocity when it reaches the peak factor into blur equation"};
68 cvar_t r_motionblur_mousefactor = {CVAR_SAVE, "r_motionblur_mousefactor", "2", "factoring in of mouse acceleration to the blur equation - the faster the player turns their mouse, the more blur they get"};
69 cvar_t r_motionblur_mousefactor_minspeed = {CVAR_SAVE, "r_motionblur_mousefactor_minspeed", "0", "lower value of mouse acceleration when it starts to factor into blur equation"};
70 cvar_t r_motionblur_mousefactor_maxspeed = {CVAR_SAVE, "r_motionblur_mousefactor_maxspeed", "50", "upper value of mouse acceleration when it reaches the peak factor into blur equation"};
71
72 // TODO do we want a r_equalize_entities cvar that works on all ents, or would that be a cheat?
73 cvar_t r_equalize_entities_fullbright = {CVAR_SAVE, "r_equalize_entities_fullbright", "0", "render fullbright entities by equalizing their lightness, not by not rendering light (DEPRECATED)"};
74 cvar_t r_equalize_entities_minambient = {CVAR_SAVE, "r_equalize_entities_minambient", "0.5", "light equalizing: ensure at least this ambient/diffuse ratio (DEPRECATED)"};
75 cvar_t r_equalize_entities_by = {CVAR_SAVE, "r_equalize_entities_by", "0.7", "light equalizing: exponent of dynamics compression (0 = no compression, 1 = full compression) (DEPRECATED)"};
76 cvar_t r_equalize_entities_to = {CVAR_SAVE, "r_equalize_entities_to", "0.8", "light equalizing: target light level (DEPRECATED)"};
77
78 cvar_t r_depthfirst = {CVAR_SAVE, "r_depthfirst", "0", "renders a depth-only version of the scene before normal rendering begins to eliminate overdraw, values: 0 = off, 1 = world depth, 2 = world and model depth"};
79 cvar_t r_useinfinitefarclip = {CVAR_SAVE, "r_useinfinitefarclip", "1", "enables use of a special kind of projection matrix that has an extremely large farclip"};
80 cvar_t r_farclip_base = {0, "r_farclip_base", "65536", "farclip (furthest visible distance) for rendering when r_useinfinitefarclip is 0"};
81 cvar_t r_farclip_world = {0, "r_farclip_world", "2", "adds map size to farclip multiplied by this value"};
82 cvar_t r_nearclip = {0, "r_nearclip", "1", "distance from camera of nearclip plane" };
83 cvar_t r_deformvertexes = {0, "r_deformvertexes", "1", "allows use of deformvertexes in shader files (can be turned off to check performance impact)"};
84 cvar_t r_transparent = {0, "r_transparent", "1", "allows use of transparent surfaces (can be turned off to check performance impact)"};
85 cvar_t r_transparent_alphatocoverage = {0, "r_transparent_alphatocoverage", "1", "enables GL_ALPHA_TO_COVERAGE antialiasing technique on alphablend and alphatest surfaces when using vid_samples 2 or higher"};
86 cvar_t r_transparent_sortsurfacesbynearest = {0, "r_transparent_sortsurfacesbynearest", "1", "sort entity and world surfaces by nearest point on bounding box instead of using the center of the bounding box, usually reduces sorting artifacts"};
87 cvar_t r_transparent_useplanardistance = {0, "r_transparent_useplanardistance", "0", "sort transparent meshes by distance from view plane rather than spherical distance to the chosen point"};
88 cvar_t r_showoverdraw = {0, "r_showoverdraw", "0", "shows overlapping geometry"};
89 cvar_t r_showbboxes = {0, "r_showbboxes", "0", "shows bounding boxes of server entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
90 cvar_t r_showbboxes_client = { 0, "r_showbboxes_client", "0", "shows bounding boxes of clientside qc entities, value controls opacity scaling (1 = 10%,  10 = 100%)" };
91 cvar_t r_showsurfaces = {0, "r_showsurfaces", "0", "1 shows surfaces as different colors, or a value of 2 shows triangle draw order (for analyzing whether meshes are optimized for vertex cache)"};
92 cvar_t r_showtris = {0, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"};
93 cvar_t r_shownormals = {0, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"};
94 cvar_t r_showlighting = {0, "r_showlighting", "0", "shows areas lit by lights, useful for finding out why some areas of a map render slowly (bright orange = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"};
95 cvar_t r_showshadowvolumes = {0, "r_showshadowvolumes", "0", "shows areas shadowed by lights, useful for finding out why some areas of a map render slowly (bright blue = lots of passes = slow), a value of 2 disables depth testing which can be interesting but not very useful"};
96 cvar_t r_showcollisionbrushes = {0, "r_showcollisionbrushes", "0", "draws collision brushes in quake3 maps (mode 1), mode 2 disables rendering of world (trippy!)"};
97 cvar_t r_showcollisionbrushes_polygonfactor = {0, "r_showcollisionbrushes_polygonfactor", "-1", "expands outward the brush polygons a little bit, used to make collision brushes appear infront of walls"};
98 cvar_t r_showcollisionbrushes_polygonoffset = {0, "r_showcollisionbrushes_polygonoffset", "0", "nudges brush polygon depth in hardware depth units, used to make collision brushes appear infront of walls"};
99 cvar_t r_showdisabledepthtest = {0, "r_showdisabledepthtest", "0", "disables depth testing on r_show* cvars, allowing you to see what hidden geometry the graphics card is processing"};
100 cvar_t r_showspriteedges = {0, "r_showspriteedges", "0", "renders a debug outline to show the polygon shape of each sprite frame rendered (may be 2 or more in case of interpolated animations), for debugging rendering bugs with specific view types"};
101 cvar_t r_showparticleedges = {0, "r_showparticleedges", "0", "renders a debug outline to show the polygon shape of each particle, for debugging rendering bugs with specific view types"};
102 cvar_t r_drawportals = {0, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"};
103 cvar_t r_drawentities = {0, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"};
104 cvar_t r_draw2d = {0, "r_draw2d","1", "draw 2D stuff (dangerous to turn off)"};
105 cvar_t r_drawworld = {0, "r_drawworld","1", "draw world (most static stuff)"};
106 cvar_t r_drawviewmodel = {0, "r_drawviewmodel","1", "draw your weapon model"};
107 cvar_t r_drawexteriormodel = {0, "r_drawexteriormodel","1", "draw your player model (e.g. in chase cam, reflections)"};
108 cvar_t r_cullentities_trace = {0, "r_cullentities_trace", "1", "probabistically cull invisible entities"};
109 cvar_t r_cullentities_trace_entityocclusion = { 0, "r_cullentities_trace_entityocclusion", "1", "check for occluding entities such as doors, not just world hull" };
110 cvar_t r_cullentities_trace_samples = {0, "r_cullentities_trace_samples", "2", "number of samples to test for entity culling (in addition to center sample)"};
111 cvar_t r_cullentities_trace_tempentitysamples = {0, "r_cullentities_trace_tempentitysamples", "-1", "number of samples to test for entity culling of temp entities (including all CSQC entities), -1 disables trace culling on these entities to prevent flicker (pvs still applies)"};
112 cvar_t r_cullentities_trace_enlarge = {0, "r_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
113 cvar_t r_cullentities_trace_expand = {0, "r_cullentities_trace_expand", "0", "box expanded by this many units for entity culling"};
114 cvar_t r_cullentities_trace_pad = {0, "r_cullentities_trace_pad", "8", "accept traces that hit within this many units of the box"};
115 cvar_t r_cullentities_trace_delay = {0, "r_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
116 cvar_t r_cullentities_trace_eyejitter = {0, "r_cullentities_trace_eyejitter", "16", "randomly offset rays from the eye by this much to reduce the odds of flickering"};
117 cvar_t r_sortentities = {0, "r_sortentities", "0", "sort entities before drawing (might be faster)"};
118 cvar_t r_speeds = {0, "r_speeds","0", "displays rendering statistics and per-subsystem timings"};
119 cvar_t r_fullbright = {0, "r_fullbright","0", "makes map very bright and renders faster"};
120
121 cvar_t r_fakelight = {0, "r_fakelight","0", "render 'fake' lighting instead of real lightmaps (DEPRECATED)"};
122 cvar_t r_fakelight_intensity = {0, "r_fakelight_intensity","0.75", "fakelight intensity modifier (DEPRECATED)"};
123 #define FAKELIGHT_ENABLED (r_fakelight.integer >= 2 || (r_fakelight.integer && r_refdef.scene.worldmodel && !r_refdef.scene.worldmodel->lit))
124
125 cvar_t r_fullbright_directed = {0, "r_fullbright_directed", "0", "render fullbright things (unlit worldmodel and EF_FULLBRIGHT entities, but not fullbright shaders) using a constant light direction instead to add more depth while keeping uniform brightness"};
126 cvar_t r_fullbright_directed_ambient = {0, "r_fullbright_directed_ambient", "0.5", "ambient light multiplier for directed fullbright"};
127 cvar_t r_fullbright_directed_diffuse = {0, "r_fullbright_directed_diffuse", "0.75", "diffuse light multiplier for directed fullbright"};
128 cvar_t r_fullbright_directed_pitch = {0, "r_fullbright_directed_pitch", "20", "constant pitch direction ('height') of the fake light source to use for fullbright"};
129 cvar_t r_fullbright_directed_pitch_relative = {0, "r_fullbright_directed_pitch_relative", "0", "whether r_fullbright_directed_pitch is interpreted as absolute (0) or relative (1) pitch"};
130
131 cvar_t r_wateralpha = {CVAR_SAVE, "r_wateralpha","1", "opacity of water polygons"};
132 cvar_t r_dynamic = {CVAR_SAVE, "r_dynamic","1", "enables dynamic lights (rocket glow and such)"};
133 cvar_t r_fullbrights = {CVAR_SAVE, "r_fullbrights", "1", "enables glowing pixels in quake textures (changes need r_restart to take effect)"};
134 cvar_t r_shadows = {CVAR_SAVE, "r_shadows", "0", "casts fake stencil shadows from models onto the world (rtlights are unaffected by this); when set to 2, always cast the shadows in the direction set by r_shadows_throwdirection, otherwise use the model lighting."};
135 cvar_t r_shadows_darken = {CVAR_SAVE, "r_shadows_darken", "0.5", "how much shadowed areas will be darkened"};
136 cvar_t r_shadows_throwdistance = {CVAR_SAVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"};
137 cvar_t r_shadows_throwdirection = {CVAR_SAVE, "r_shadows_throwdirection", "0 0 -1", "override throwing direction for r_shadows 2"};
138 cvar_t r_shadows_drawafterrtlighting = {CVAR_SAVE, "r_shadows_drawafterrtlighting", "0", "draw fake shadows AFTER realtime lightning is drawn. May be useful for simulating fast sunlight on large outdoor maps with only one noshadow rtlight. The price is less realistic appearance of dynamic light shadows."};
139 cvar_t r_shadows_castfrombmodels = {CVAR_SAVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"};
140 cvar_t r_shadows_focus = {CVAR_SAVE, "r_shadows_focus", "0 0 0", "offset the shadowed area focus"};
141 cvar_t r_shadows_shadowmapscale = {CVAR_SAVE, "r_shadows_shadowmapscale", "0.25", "higher values increase shadowmap quality at a cost of area covered (multiply global shadowmap precision) for fake shadows. Needs shadowmapping ON."};
142 cvar_t r_shadows_shadowmapbias = {CVAR_SAVE, "r_shadows_shadowmapbias", "-1", "sets shadowmap bias for fake shadows. -1 sets the value of r_shadow_shadowmapping_bias. Needs shadowmapping ON."};
143 cvar_t r_q1bsp_skymasking = {0, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
144 cvar_t r_polygonoffset_submodel_factor = {0, "r_polygonoffset_submodel_factor", "0", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
145 cvar_t r_polygonoffset_submodel_offset = {0, "r_polygonoffset_submodel_offset", "14", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
146 cvar_t r_polygonoffset_decals_factor = {0, "r_polygonoffset_decals_factor", "0", "biases depth values of decals to prevent z-fighting artifacts"};
147 cvar_t r_polygonoffset_decals_offset = {0, "r_polygonoffset_decals_offset", "-14", "biases depth values of decals to prevent z-fighting artifacts"};
148 cvar_t r_fog_exp2 = {0, "r_fog_exp2", "0", "uses GL_EXP2 fog (as in Nehahra) rather than realistic GL_EXP fog"};
149 cvar_t r_fog_clear = {0, "r_fog_clear", "1", "clears renderbuffer with fog color before render starts"};
150 cvar_t r_drawfog = {CVAR_SAVE, "r_drawfog", "1", "allows one to disable fog rendering"};
151 cvar_t r_transparentdepthmasking = {CVAR_SAVE, "r_transparentdepthmasking", "0", "enables depth writes on transparent meshes whose materially is normally opaque, this prevents seeing the inside of a transparent mesh"};
152 cvar_t r_transparent_sortmindist = {CVAR_SAVE, "r_transparent_sortmindist", "0", "lower distance limit for transparent sorting"};
153 cvar_t r_transparent_sortmaxdist = {CVAR_SAVE, "r_transparent_sortmaxdist", "32768", "upper distance limit for transparent sorting"};
154 cvar_t r_transparent_sortarraysize = {CVAR_SAVE, "r_transparent_sortarraysize", "4096", "number of distance-sorting layers"};
155 cvar_t r_celshading = {CVAR_SAVE, "r_celshading", "0", "cartoon-style light shading (OpenGL 2.x only)"}; // FIXME remove OpenGL 2.x only once implemented for DX9
156 cvar_t r_celoutlines = {CVAR_SAVE, "r_celoutlines", "0", "cartoon-style outlines (requires r_shadow_deferred; OpenGL 2.x only)"}; // FIXME remove OpenGL 2.x only once implemented for DX9
157
158 cvar_t gl_fogenable = {0, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"};
159 cvar_t gl_fogdensity = {0, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"};
160 cvar_t gl_fogred = {0, "gl_fogred","0.3", "nehahra fog color red value (for Nehahra compatibility only)"};
161 cvar_t gl_foggreen = {0, "gl_foggreen","0.3", "nehahra fog color green value (for Nehahra compatibility only)"};
162 cvar_t gl_fogblue = {0, "gl_fogblue","0.3", "nehahra fog color blue value (for Nehahra compatibility only)"};
163 cvar_t gl_fogstart = {0, "gl_fogstart", "0", "nehahra fog start distance (for Nehahra compatibility only)"};
164 cvar_t gl_fogend = {0, "gl_fogend","0", "nehahra fog end distance (for Nehahra compatibility only)"};
165 cvar_t gl_skyclip = {0, "gl_skyclip", "4608", "nehahra farclip distance - the real fog end (for Nehahra compatibility only)"};
166
167 cvar_t r_texture_dds_load = {CVAR_SAVE, "r_texture_dds_load", "0", "load compressed dds/filename.dds texture instead of filename.tga, if the file exists (requires driver support)"};
168 cvar_t r_texture_dds_save = {CVAR_SAVE, "r_texture_dds_save", "0", "save compressed dds/filename.dds texture when filename.tga is loaded, so that it can be loaded instead next time"};
169
170 cvar_t r_textureunits = {0, "r_textureunits", "32", "number of texture units to use in GL 1.1 and GL 1.3 rendering paths"};
171 static cvar_t gl_combine = {CVAR_READONLY, "gl_combine", "1", "indicates whether the OpenGL 1.3 rendering path is active"};
172 static cvar_t r_glsl = {CVAR_READONLY, "r_glsl", "1", "indicates whether the OpenGL 2.0 rendering path is active"};
173
174 cvar_t r_usedepthtextures = {CVAR_SAVE, "r_usedepthtextures", "1", "use depth texture instead of depth renderbuffer where possible, uses less video memory but may render slower (or faster) depending on hardware"};
175 cvar_t r_viewfbo = {CVAR_SAVE, "r_viewfbo", "0", "enables use of an 8bit (1) or 16bit (2) or 32bit (3) per component float framebuffer render, which may be at a different resolution than the video mode"};
176 cvar_t r_rendertarget_debug = {0, "r_rendertarget_debug", "-1", "replaces the view with the contents of the specified render target (by number - note that these can fluctuate depending on scene)"};
177 cvar_t r_viewscale = {CVAR_SAVE, "r_viewscale", "1", "scaling factor for resolution of the fbo rendering method, must be > 0, can be above 1 for a costly antialiasing behavior, typical values are 0.5 for 1/4th as many pixels rendered, or 1 for normal rendering"};
178 cvar_t r_viewscale_fpsscaling = {CVAR_SAVE, "r_viewscale_fpsscaling", "0", "change resolution based on framerate"};
179 cvar_t r_viewscale_fpsscaling_min = {CVAR_SAVE, "r_viewscale_fpsscaling_min", "0.0625", "worst acceptable quality"};
180 cvar_t r_viewscale_fpsscaling_multiply = {CVAR_SAVE, "r_viewscale_fpsscaling_multiply", "5", "adjust quality up or down by the frametime difference from 1.0/target, multiplied by this factor"};
181 cvar_t r_viewscale_fpsscaling_stepsize = {CVAR_SAVE, "r_viewscale_fpsscaling_stepsize", "0.01", "smallest adjustment to hit the target framerate (this value prevents minute oscillations)"};
182 cvar_t r_viewscale_fpsscaling_stepmax = {CVAR_SAVE, "r_viewscale_fpsscaling_stepmax", "1.00", "largest adjustment to hit the target framerate (this value prevents wild overshooting of the estimate)"};
183 cvar_t r_viewscale_fpsscaling_target = {CVAR_SAVE, "r_viewscale_fpsscaling_target", "70", "desired framerate"};
184
185 cvar_t r_glsl_skeletal = {CVAR_SAVE, "r_glsl_skeletal", "1", "render skeletal models faster using a gpu-skinning technique"};
186 cvar_t r_glsl_deluxemapping = {CVAR_SAVE, "r_glsl_deluxemapping", "1", "use per pixel lighting on deluxemap-compiled q3bsp maps (or a value of 2 forces deluxemap shading even without deluxemaps)"};
187 cvar_t r_glsl_offsetmapping = {CVAR_SAVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
188 cvar_t r_glsl_offsetmapping_steps = {CVAR_SAVE, "r_glsl_offsetmapping_steps", "2", "offset mapping steps (note: too high values may be not supported by your GPU)"};
189 cvar_t r_glsl_offsetmapping_reliefmapping = {CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
190 cvar_t r_glsl_offsetmapping_reliefmapping_steps = {CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping_steps", "10", "relief mapping steps (note: too high values may be not supported by your GPU)"};
191 cvar_t r_glsl_offsetmapping_reliefmapping_refinesteps = {CVAR_SAVE, "r_glsl_offsetmapping_reliefmapping_refinesteps", "5", "relief mapping refine steps (these are a binary search executed as the last step as given by r_glsl_offsetmapping_reliefmapping_steps)"};
192 cvar_t r_glsl_offsetmapping_scale = {CVAR_SAVE, "r_glsl_offsetmapping_scale", "0.04", "how deep the offset mapping effect is"};
193 cvar_t r_glsl_offsetmapping_lod = {CVAR_SAVE, "r_glsl_offsetmapping_lod", "0", "apply distance-based level-of-detail correction to number of offsetmappig steps, effectively making it render faster on large open-area maps"};
194 cvar_t r_glsl_offsetmapping_lod_distance = {CVAR_SAVE, "r_glsl_offsetmapping_lod_distance", "32", "first LOD level distance, second level (-50% steps) is 2x of this, third (33%) - 3x etc."};
195 cvar_t r_glsl_postprocess = {CVAR_SAVE, "r_glsl_postprocess", "0", "use a GLSL postprocessing shader"};
196 cvar_t r_glsl_postprocess_uservec1 = {CVAR_SAVE, "r_glsl_postprocess_uservec1", "0 0 0 0", "a 4-component vector to pass as uservec1 to the postprocessing shader (only useful if default.glsl has been customized)"};
197 cvar_t r_glsl_postprocess_uservec2 = {CVAR_SAVE, "r_glsl_postprocess_uservec2", "0 0 0 0", "a 4-component vector to pass as uservec2 to the postprocessing shader (only useful if default.glsl has been customized)"};
198 cvar_t r_glsl_postprocess_uservec3 = {CVAR_SAVE, "r_glsl_postprocess_uservec3", "0 0 0 0", "a 4-component vector to pass as uservec3 to the postprocessing shader (only useful if default.glsl has been customized)"};
199 cvar_t r_glsl_postprocess_uservec4 = {CVAR_SAVE, "r_glsl_postprocess_uservec4", "0 0 0 0", "a 4-component vector to pass as uservec4 to the postprocessing shader (only useful if default.glsl has been customized)"};
200 cvar_t r_glsl_postprocess_uservec1_enable = {CVAR_SAVE, "r_glsl_postprocess_uservec1_enable", "1", "enables postprocessing uservec1 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
201 cvar_t r_glsl_postprocess_uservec2_enable = {CVAR_SAVE, "r_glsl_postprocess_uservec2_enable", "1", "enables postprocessing uservec2 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
202 cvar_t r_glsl_postprocess_uservec3_enable = {CVAR_SAVE, "r_glsl_postprocess_uservec3_enable", "1", "enables postprocessing uservec3 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
203 cvar_t r_glsl_postprocess_uservec4_enable = {CVAR_SAVE, "r_glsl_postprocess_uservec4_enable", "1", "enables postprocessing uservec4 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
204
205 cvar_t r_water = {CVAR_SAVE, "r_water", "0", "whether to use reflections and refraction on water surfaces (note: r_wateralpha must be set below 1)"};
206 cvar_t r_water_cameraentitiesonly = {CVAR_SAVE, "r_water_cameraentitiesonly", "0", "whether to only show QC-defined reflections/refractions (typically used for camera- or portal-like effects)"};
207 cvar_t r_water_clippingplanebias = {CVAR_SAVE, "r_water_clippingplanebias", "1", "a rather technical setting which avoids black pixels around water edges"};
208 cvar_t r_water_resolutionmultiplier = {CVAR_SAVE, "r_water_resolutionmultiplier", "0.5", "multiplier for screen resolution when rendering refracted/reflected scenes, 1 is full quality, lower values are faster"};
209 cvar_t r_water_refractdistort = {CVAR_SAVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
210 cvar_t r_water_reflectdistort = {CVAR_SAVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"};
211 cvar_t r_water_scissormode = {0, "r_water_scissormode", "3", "scissor (1) or cull (2) or both (3) water renders"};
212 cvar_t r_water_lowquality = {0, "r_water_lowquality", "0", "special option to accelerate water rendering, 1 disables shadows and particles, 2 disables all dynamic lights"};
213 cvar_t r_water_hideplayer = {CVAR_SAVE, "r_water_hideplayer", "0", "if set to 1 then player will be hidden in refraction views, if set to 2 then player will also be hidden in reflection views, player is always visible in camera views"};
214
215 cvar_t r_lerpsprites = {CVAR_SAVE, "r_lerpsprites", "0", "enables animation smoothing on sprites"};
216 cvar_t r_lerpmodels = {CVAR_SAVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
217 cvar_t r_lerplightstyles = {CVAR_SAVE, "r_lerplightstyles", "0", "enable animation smoothing on flickering lights"};
218 cvar_t r_waterscroll = {CVAR_SAVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
219
220 cvar_t r_bloom = {CVAR_SAVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"};
221 cvar_t r_bloom_colorscale = {CVAR_SAVE, "r_bloom_colorscale", "1", "how bright the glow is"};
222
223 cvar_t r_bloom_brighten = {CVAR_SAVE, "r_bloom_brighten", "2", "how bright the glow is, after subtract/power"};
224 cvar_t r_bloom_blur = {CVAR_SAVE, "r_bloom_blur", "4", "how large the glow is"};
225 cvar_t r_bloom_resolution = {CVAR_SAVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"};
226 cvar_t r_bloom_colorexponent = {CVAR_SAVE, "r_bloom_colorexponent", "1", "how exaggerated the glow is"};
227 cvar_t r_bloom_colorsubtract = {CVAR_SAVE, "r_bloom_colorsubtract", "0.125", "reduces bloom colors by a certain amount"};
228 cvar_t r_bloom_scenebrightness = {CVAR_SAVE, "r_bloom_scenebrightness", "1", "global rendering brightness when bloom is enabled"};
229
230 cvar_t r_hdr_scenebrightness = {CVAR_SAVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
231 cvar_t r_hdr_glowintensity = {CVAR_SAVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
232 cvar_t r_hdr_irisadaptation = {CVAR_SAVE, "r_hdr_irisadaptation", "0", "adjust scene brightness according to light intensity at player location"};
233 cvar_t r_hdr_irisadaptation_multiplier = {CVAR_SAVE, "r_hdr_irisadaptation_multiplier", "2", "brightness at which value will be 1.0"};
234 cvar_t r_hdr_irisadaptation_minvalue = {CVAR_SAVE, "r_hdr_irisadaptation_minvalue", "0.5", "minimum value that can result from multiplier / brightness"};
235 cvar_t r_hdr_irisadaptation_maxvalue = {CVAR_SAVE, "r_hdr_irisadaptation_maxvalue", "4", "maximum value that can result from multiplier / brightness"};
236 cvar_t r_hdr_irisadaptation_value = {0, "r_hdr_irisadaptation_value", "1", "current value as scenebrightness multiplier, changes continuously when irisadaptation is active"};
237 cvar_t r_hdr_irisadaptation_fade_up = {CVAR_SAVE, "r_hdr_irisadaptation_fade_up", "0.1", "fade rate at which value adjusts to darkness"};
238 cvar_t r_hdr_irisadaptation_fade_down = {CVAR_SAVE, "r_hdr_irisadaptation_fade_down", "0.5", "fade rate at which value adjusts to brightness"};
239 cvar_t r_hdr_irisadaptation_radius = {CVAR_SAVE, "r_hdr_irisadaptation_radius", "15", "lighting within this many units of the eye is averaged"};
240
241 cvar_t r_smoothnormals_areaweighting = {0, "r_smoothnormals_areaweighting", "1", "uses significantly faster (and supposedly higher quality) area-weighted vertex normals and tangent vectors rather than summing normalized triangle normals and tangents"};
242
243 cvar_t developer_texturelogging = {0, "developer_texturelogging", "0", "produces a textures.log file containing names of skins and map textures the engine tried to load"};
244
245 cvar_t gl_lightmaps = {0, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers), a value of 2 keeps normalmap shading"};
246
247 cvar_t r_test = {0, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
248
249 cvar_t r_batch_multidraw = {CVAR_SAVE, "r_batch_multidraw", "1", "issue multiple glDrawElements calls when rendering a batch of surfaces with the same texture (otherwise the index data is copied to make it one draw)"};
250 cvar_t r_batch_multidraw_mintriangles = {CVAR_SAVE, "r_batch_multidraw_mintriangles", "0", "minimum number of triangles to activate multidraw path (copying small groups of triangles may be faster)"};
251 cvar_t r_batch_debugdynamicvertexpath = {CVAR_SAVE, "r_batch_debugdynamicvertexpath", "0", "force the dynamic batching code path for debugging purposes"};
252 cvar_t r_batch_dynamicbuffer = {CVAR_SAVE, "r_batch_dynamicbuffer", "0", "use vertex/index buffers for drawing dynamic and copytriangles batches"};
253
254 cvar_t r_glsl_saturation = {CVAR_SAVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"};
255 cvar_t r_glsl_saturation_redcompensate = {CVAR_SAVE, "r_glsl_saturation_redcompensate", "0", "a 'vampire sight' addition to desaturation effect, does compensation for red color, r_glsl_restart is required"};
256
257 cvar_t r_glsl_vertextextureblend_usebothalphas = {CVAR_SAVE, "r_glsl_vertextextureblend_usebothalphas", "0", "use both alpha layers on vertex blended surfaces, each alpha layer sets amount of 'blend leak' on another layer, requires mod_q3shader_force_terrain_alphaflag on."};
258
259 cvar_t r_framedatasize = {CVAR_SAVE, "r_framedatasize", "0.5", "size of renderer data cache used during one frame (for skeletal animation caching, light processing, etc)"};
260 cvar_t r_buffermegs[R_BUFFERDATA_COUNT] =
261 {
262         {CVAR_SAVE, "r_buffermegs_vertex", "4", "vertex buffer size for one frame"},
263         {CVAR_SAVE, "r_buffermegs_index16", "1", "index buffer size for one frame (16bit indices)"},
264         {CVAR_SAVE, "r_buffermegs_index32", "1", "index buffer size for one frame (32bit indices)"},
265         {CVAR_SAVE, "r_buffermegs_uniform", "0.25", "uniform buffer size for one frame"},
266 };
267
268 extern cvar_t v_glslgamma_2d;
269
270 extern qboolean v_flipped_state;
271
272 r_framebufferstate_t r_fb;
273
274 /// shadow volume bsp struct with automatically growing nodes buffer
275 svbsp_t r_svbsp;
276
277 int r_uniformbufferalignment = 32; // dynamically updated to match GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
278
279 rtexture_t *r_texture_blanknormalmap;
280 rtexture_t *r_texture_white;
281 rtexture_t *r_texture_grey128;
282 rtexture_t *r_texture_black;
283 rtexture_t *r_texture_notexture;
284 rtexture_t *r_texture_whitecube;
285 rtexture_t *r_texture_normalizationcube;
286 rtexture_t *r_texture_fogattenuation;
287 rtexture_t *r_texture_fogheighttexture;
288 rtexture_t *r_texture_gammaramps;
289 unsigned int r_texture_gammaramps_serial;
290 //rtexture_t *r_texture_fogintensity;
291 rtexture_t *r_texture_reflectcube;
292
293 // TODO: hash lookups?
294 typedef struct cubemapinfo_s
295 {
296         char basename[64];
297         rtexture_t *texture;
298 }
299 cubemapinfo_t;
300
301 int r_texture_numcubemaps;
302 cubemapinfo_t *r_texture_cubemaps[MAX_CUBEMAPS];
303
304 unsigned int r_queries[MAX_OCCLUSION_QUERIES];
305 unsigned int r_numqueries;
306 unsigned int r_maxqueries;
307
308 typedef struct r_qwskincache_s
309 {
310         char name[MAX_QPATH];
311         skinframe_t *skinframe;
312 }
313 r_qwskincache_t;
314
315 static r_qwskincache_t *r_qwskincache;
316 static int r_qwskincache_size;
317
318 /// vertex coordinates for a quad that covers the screen exactly
319 extern const float r_screenvertex3f[12];
320 const float r_screenvertex3f[12] =
321 {
322         0, 0, 0,
323         1, 0, 0,
324         1, 1, 0,
325         0, 1, 0
326 };
327
328 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
329 {
330         int i;
331         for (i = 0;i < verts;i++)
332         {
333                 out[0] = in[0] * r;
334                 out[1] = in[1] * g;
335                 out[2] = in[2] * b;
336                 out[3] = in[3];
337                 in += 4;
338                 out += 4;
339         }
340 }
341
342 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
343 {
344         int i;
345         for (i = 0;i < verts;i++)
346         {
347                 out[0] = r;
348                 out[1] = g;
349                 out[2] = b;
350                 out[3] = a;
351                 out += 4;
352         }
353 }
354
355 // FIXME: move this to client?
356 void FOG_clear(void)
357 {
358         if (gamemode == GAME_NEHAHRA)
359         {
360                 Cvar_Set("gl_fogenable", "0");
361                 Cvar_Set("gl_fogdensity", "0.2");
362                 Cvar_Set("gl_fogred", "0.3");
363                 Cvar_Set("gl_foggreen", "0.3");
364                 Cvar_Set("gl_fogblue", "0.3");
365         }
366         r_refdef.fog_density = 0;
367         r_refdef.fog_red = 0;
368         r_refdef.fog_green = 0;
369         r_refdef.fog_blue = 0;
370         r_refdef.fog_alpha = 1;
371         r_refdef.fog_start = 0;
372         r_refdef.fog_end = 16384;
373         r_refdef.fog_height = 1<<30;
374         r_refdef.fog_fadedepth = 128;
375         memset(r_refdef.fog_height_texturename, 0, sizeof(r_refdef.fog_height_texturename));
376 }
377
378 static void R_BuildBlankTextures(void)
379 {
380         unsigned char data[4];
381         data[2] = 128; // normal X
382         data[1] = 128; // normal Y
383         data[0] = 255; // normal Z
384         data[3] = 255; // height
385         r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
386         data[0] = 255;
387         data[1] = 255;
388         data[2] = 255;
389         data[3] = 255;
390         r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
391         data[0] = 128;
392         data[1] = 128;
393         data[2] = 128;
394         data[3] = 255;
395         r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
396         data[0] = 0;
397         data[1] = 0;
398         data[2] = 0;
399         data[3] = 255;
400         r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
401 }
402
403 static void R_BuildNoTexture(void)
404 {
405         int x, y;
406         unsigned char pix[16][16][4];
407         // this makes a light grey/dark grey checkerboard texture
408         for (y = 0;y < 16;y++)
409         {
410                 for (x = 0;x < 16;x++)
411                 {
412                         if ((y < 8) ^ (x < 8))
413                         {
414                                 pix[y][x][0] = 128;
415                                 pix[y][x][1] = 128;
416                                 pix[y][x][2] = 128;
417                                 pix[y][x][3] = 255;
418                         }
419                         else
420                         {
421                                 pix[y][x][0] = 64;
422                                 pix[y][x][1] = 64;
423                                 pix[y][x][2] = 64;
424                                 pix[y][x][3] = 255;
425                         }
426                 }
427         }
428         r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_PERSISTENT, -1, NULL);
429 }
430
431 static void R_BuildWhiteCube(void)
432 {
433         unsigned char data[6*1*1*4];
434         memset(data, 255, sizeof(data));
435         r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
436 }
437
438 static void R_BuildNormalizationCube(void)
439 {
440         int x, y, side;
441         vec3_t v;
442         vec_t s, t, intensity;
443 #define NORMSIZE 64
444         unsigned char *data;
445         data = (unsigned char *)Mem_Alloc(tempmempool, 6*NORMSIZE*NORMSIZE*4);
446         for (side = 0;side < 6;side++)
447         {
448                 for (y = 0;y < NORMSIZE;y++)
449                 {
450                         for (x = 0;x < NORMSIZE;x++)
451                         {
452                                 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
453                                 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
454                                 switch(side)
455                                 {
456                                 default:
457                                 case 0:
458                                         v[0] = 1;
459                                         v[1] = -t;
460                                         v[2] = -s;
461                                         break;
462                                 case 1:
463                                         v[0] = -1;
464                                         v[1] = -t;
465                                         v[2] = s;
466                                         break;
467                                 case 2:
468                                         v[0] = s;
469                                         v[1] = 1;
470                                         v[2] = t;
471                                         break;
472                                 case 3:
473                                         v[0] = s;
474                                         v[1] = -1;
475                                         v[2] = -t;
476                                         break;
477                                 case 4:
478                                         v[0] = s;
479                                         v[1] = -t;
480                                         v[2] = 1;
481                                         break;
482                                 case 5:
483                                         v[0] = -s;
484                                         v[1] = -t;
485                                         v[2] = -1;
486                                         break;
487                                 }
488                                 intensity = 127.0f / sqrt(DotProduct(v, v));
489                                 data[((side*64+y)*64+x)*4+2] = (unsigned char)(128.0f + intensity * v[0]);
490                                 data[((side*64+y)*64+x)*4+1] = (unsigned char)(128.0f + intensity * v[1]);
491                                 data[((side*64+y)*64+x)*4+0] = (unsigned char)(128.0f + intensity * v[2]);
492                                 data[((side*64+y)*64+x)*4+3] = 255;
493                         }
494                 }
495         }
496         r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
497         Mem_Free(data);
498 }
499
500 static void R_BuildFogTexture(void)
501 {
502         int x, b;
503 #define FOGWIDTH 256
504         unsigned char data1[FOGWIDTH][4];
505         //unsigned char data2[FOGWIDTH][4];
506         double d, r, alpha;
507
508         r_refdef.fogmasktable_start = r_refdef.fog_start;
509         r_refdef.fogmasktable_alpha = r_refdef.fog_alpha;
510         r_refdef.fogmasktable_range = r_refdef.fogrange;
511         r_refdef.fogmasktable_density = r_refdef.fog_density;
512
513         r = r_refdef.fogmasktable_range / FOGMASKTABLEWIDTH;
514         for (x = 0;x < FOGMASKTABLEWIDTH;x++)
515         {
516                 d = (x * r - r_refdef.fogmasktable_start);
517                 if(developer_extra.integer)
518                         Con_DPrintf("%f ", d);
519                 d = max(0, d);
520                 if (r_fog_exp2.integer)
521                         alpha = exp(-r_refdef.fogmasktable_density * r_refdef.fogmasktable_density * 0.0001 * d * d);
522                 else
523                         alpha = exp(-r_refdef.fogmasktable_density * 0.004 * d);
524                 if(developer_extra.integer)
525                         Con_DPrintf(" : %f ", alpha);
526                 alpha = 1 - (1 - alpha) * r_refdef.fogmasktable_alpha;
527                 if(developer_extra.integer)
528                         Con_DPrintf(" = %f\n", alpha);
529                 r_refdef.fogmasktable[x] = bound(0, alpha, 1);
530         }
531
532         for (x = 0;x < FOGWIDTH;x++)
533         {
534                 b = (int)(r_refdef.fogmasktable[x * (FOGMASKTABLEWIDTH - 1) / (FOGWIDTH - 1)] * 255);
535                 data1[x][0] = b;
536                 data1[x][1] = b;
537                 data1[x][2] = b;
538                 data1[x][3] = 255;
539                 //data2[x][0] = 255 - b;
540                 //data2[x][1] = 255 - b;
541                 //data2[x][2] = 255 - b;
542                 //data2[x][3] = 255;
543         }
544         if (r_texture_fogattenuation)
545         {
546                 R_UpdateTexture(r_texture_fogattenuation, &data1[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
547                 //R_UpdateTexture(r_texture_fogattenuation, &data2[0][0], 0, 0, 0, FOGWIDTH, 1, 1);
548         }
549         else
550         {
551                 r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
552                 //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
553         }
554 }
555
556 static void R_BuildFogHeightTexture(void)
557 {
558         unsigned char *inpixels;
559         int size;
560         int x;
561         int y;
562         int j;
563         float c[4];
564         float f;
565         inpixels = NULL;
566         strlcpy(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename, sizeof(r_refdef.fogheighttexturename));
567         if (r_refdef.fogheighttexturename[0])
568                 inpixels = loadimagepixelsbgra(r_refdef.fogheighttexturename, true, false, false, NULL);
569         if (!inpixels)
570         {
571                 r_refdef.fog_height_tablesize = 0;
572                 if (r_texture_fogheighttexture)
573                         R_FreeTexture(r_texture_fogheighttexture);
574                 r_texture_fogheighttexture = NULL;
575                 if (r_refdef.fog_height_table2d)
576                         Mem_Free(r_refdef.fog_height_table2d);
577                 r_refdef.fog_height_table2d = NULL;
578                 if (r_refdef.fog_height_table1d)
579                         Mem_Free(r_refdef.fog_height_table1d);
580                 r_refdef.fog_height_table1d = NULL;
581                 return;
582         }
583         size = image_width;
584         r_refdef.fog_height_tablesize = size;
585         r_refdef.fog_height_table1d = (unsigned char *)Mem_Alloc(r_main_mempool, size * 4);
586         r_refdef.fog_height_table2d = (unsigned char *)Mem_Alloc(r_main_mempool, size * size * 4);
587         memcpy(r_refdef.fog_height_table1d, inpixels, size * 4);
588         Mem_Free(inpixels);
589         // LordHavoc: now the magic - what is that table2d for?  it is a cooked
590         // average fog color table accounting for every fog layer between a point
591         // and the camera.  (Note: attenuation is handled separately!)
592         for (y = 0;y < size;y++)
593         {
594                 for (x = 0;x < size;x++)
595                 {
596                         Vector4Clear(c);
597                         f = 0;
598                         if (x < y)
599                         {
600                                 for (j = x;j <= y;j++)
601                                 {
602                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
603                                         f++;
604                                 }
605                         }
606                         else
607                         {
608                                 for (j = x;j >= y;j--)
609                                 {
610                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
611                                         f++;
612                                 }
613                         }
614                         f = 1.0f / f;
615                         r_refdef.fog_height_table2d[(y*size+x)*4+0] = (unsigned char)(c[0] * f);
616                         r_refdef.fog_height_table2d[(y*size+x)*4+1] = (unsigned char)(c[1] * f);
617                         r_refdef.fog_height_table2d[(y*size+x)*4+2] = (unsigned char)(c[2] * f);
618                         r_refdef.fog_height_table2d[(y*size+x)*4+3] = (unsigned char)(c[3] * f);
619                 }
620         }
621         r_texture_fogheighttexture = R_LoadTexture2D(r_main_texturepool, "fogheighttable", size, size, r_refdef.fog_height_table2d, TEXTYPE_BGRA, TEXF_ALPHA | TEXF_CLAMP, -1, NULL);
622 }
623
624 //=======================================================================================================================================================
625
626 static const char *builtinshaderstrings[] =
627 {
628 #include "shader_glsl.h"
629 0
630 };
631
632 //=======================================================================================================================================================
633
634 typedef struct shaderpermutationinfo_s
635 {
636         const char *pretext;
637         const char *name;
638 }
639 shaderpermutationinfo_t;
640
641 typedef struct shadermodeinfo_s
642 {
643         const char *sourcebasename;
644         const char *extension;
645         const char **builtinshaderstrings;
646         const char *pretext;
647         const char *name;
648         char *filename;
649         char *builtinstring;
650         int builtincrc;
651 }
652 shadermodeinfo_t;
653
654 // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
655 shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
656 {
657         {"#define USEDIFFUSE\n", " diffuse"},
658         {"#define USEVERTEXTEXTUREBLEND\n", " vertextextureblend"},
659         {"#define USEVIEWTINT\n", " viewtint"},
660         {"#define USECOLORMAPPING\n", " colormapping"},
661         {"#define USESATURATION\n", " saturation"},
662         {"#define USEFOGINSIDE\n", " foginside"},
663         {"#define USEFOGOUTSIDE\n", " fogoutside"},
664         {"#define USEFOGHEIGHTTEXTURE\n", " fogheighttexture"},
665         {"#define USEFOGALPHAHACK\n", " fogalphahack"},
666         {"#define USEGAMMARAMPS\n", " gammaramps"},
667         {"#define USECUBEFILTER\n", " cubefilter"},
668         {"#define USEGLOW\n", " glow"},
669         {"#define USEBLOOM\n", " bloom"},
670         {"#define USESPECULAR\n", " specular"},
671         {"#define USEPOSTPROCESSING\n", " postprocessing"},
672         {"#define USEREFLECTION\n", " reflection"},
673         {"#define USEOFFSETMAPPING\n", " offsetmapping"},
674         {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
675         {"#define USESHADOWMAP2D\n", " shadowmap2d"},
676         {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"}, // TODO make this a static parm
677         {"#define USESHADOWMAPORTHO\n", " shadowmaportho"},
678         {"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"},
679         {"#define USEALPHAKILL\n", " alphakill"},
680         {"#define USEREFLECTCUBE\n", " reflectcube"},
681         {"#define USENORMALMAPSCROLLBLEND\n", " normalmapscrollblend"},
682         {"#define USEBOUNCEGRID\n", " bouncegrid"},
683         {"#define USEBOUNCEGRIDDIRECTIONAL\n", " bouncegriddirectional"}, // TODO make this a static parm
684         {"#define USETRIPPY\n", " trippy"},
685         {"#define USEDEPTHRGB\n", " depthrgb"},
686         {"#define USEALPHAGENVERTEX\n", " alphagenvertex"},
687         {"#define USESKELETAL\n", " skeletal"},
688         {"#define USEOCCLUDE\n", " occlude"}
689 };
690
691 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
692 shadermodeinfo_t shadermodeinfo[SHADERLANGUAGE_COUNT][SHADERMODE_COUNT] =
693 {
694         // SHADERLANGUAGE_GLSL
695         {
696                 {"combined", "glsl", builtinshaderstrings, "#define MODE_GENERIC\n", " generic"},
697                 {"combined", "glsl", builtinshaderstrings, "#define MODE_POSTPROCESS\n", " postprocess"},
698                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
699                 {"combined", "glsl", builtinshaderstrings, "#define MODE_FLATCOLOR\n", " flatcolor"},
700                 {"combined", "glsl", builtinshaderstrings, "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
701                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTMAP\n", " lightmap"},
702                 {"combined", "glsl", builtinshaderstrings, "#define MODE_FAKELIGHT\n", " fakelight"},
703                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
704                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
705                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
706                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
707                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
708                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTSOURCE\n", " lightsource"},
709                 {"combined", "glsl", builtinshaderstrings, "#define MODE_REFRACTION\n", " refraction"},
710                 {"combined", "glsl", builtinshaderstrings, "#define MODE_WATER\n", " water"},
711                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
712                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
713         },
714 };
715
716 struct r_glsl_permutation_s;
717 typedef struct r_glsl_permutation_s
718 {
719         /// hash lookup data
720         struct r_glsl_permutation_s *hashnext;
721         unsigned int mode;
722         dpuint64 permutation;
723
724         /// indicates if we have tried compiling this permutation already
725         qboolean compiled;
726         /// 0 if compilation failed
727         int program;
728         // texture units assigned to each detected uniform
729         int tex_Texture_First;
730         int tex_Texture_Second;
731         int tex_Texture_GammaRamps;
732         int tex_Texture_Normal;
733         int tex_Texture_Color;
734         int tex_Texture_Gloss;
735         int tex_Texture_Glow;
736         int tex_Texture_SecondaryNormal;
737         int tex_Texture_SecondaryColor;
738         int tex_Texture_SecondaryGloss;
739         int tex_Texture_SecondaryGlow;
740         int tex_Texture_Pants;
741         int tex_Texture_Shirt;
742         int tex_Texture_FogHeightTexture;
743         int tex_Texture_FogMask;
744         int tex_Texture_Lightmap;
745         int tex_Texture_Deluxemap;
746         int tex_Texture_Attenuation;
747         int tex_Texture_Cube;
748         int tex_Texture_Refraction;
749         int tex_Texture_Reflection;
750         int tex_Texture_ShadowMap2D;
751         int tex_Texture_CubeProjection;
752         int tex_Texture_ScreenNormalMap;
753         int tex_Texture_ScreenDiffuse;
754         int tex_Texture_ScreenSpecular;
755         int tex_Texture_ReflectMask;
756         int tex_Texture_ReflectCube;
757         int tex_Texture_BounceGrid;
758         /// locations of detected uniforms in program object, or -1 if not found
759         int loc_Texture_First;
760         int loc_Texture_Second;
761         int loc_Texture_GammaRamps;
762         int loc_Texture_Normal;
763         int loc_Texture_Color;
764         int loc_Texture_Gloss;
765         int loc_Texture_Glow;
766         int loc_Texture_SecondaryNormal;
767         int loc_Texture_SecondaryColor;
768         int loc_Texture_SecondaryGloss;
769         int loc_Texture_SecondaryGlow;
770         int loc_Texture_Pants;
771         int loc_Texture_Shirt;
772         int loc_Texture_FogHeightTexture;
773         int loc_Texture_FogMask;
774         int loc_Texture_Lightmap;
775         int loc_Texture_Deluxemap;
776         int loc_Texture_Attenuation;
777         int loc_Texture_Cube;
778         int loc_Texture_Refraction;
779         int loc_Texture_Reflection;
780         int loc_Texture_ShadowMap2D;
781         int loc_Texture_CubeProjection;
782         int loc_Texture_ScreenNormalMap;
783         int loc_Texture_ScreenDiffuse;
784         int loc_Texture_ScreenSpecular;
785         int loc_Texture_ReflectMask;
786         int loc_Texture_ReflectCube;
787         int loc_Texture_BounceGrid;
788         int loc_Alpha;
789         int loc_BloomBlur_Parameters;
790         int loc_ClientTime;
791         int loc_Color_Ambient;
792         int loc_Color_Diffuse;
793         int loc_Color_Specular;
794         int loc_Color_Glow;
795         int loc_Color_Pants;
796         int loc_Color_Shirt;
797         int loc_DeferredColor_Ambient;
798         int loc_DeferredColor_Diffuse;
799         int loc_DeferredColor_Specular;
800         int loc_DeferredMod_Diffuse;
801         int loc_DeferredMod_Specular;
802         int loc_DistortScaleRefractReflect;
803         int loc_EyePosition;
804         int loc_FogColor;
805         int loc_FogHeightFade;
806         int loc_FogPlane;
807         int loc_FogPlaneViewDist;
808         int loc_FogRangeRecip;
809         int loc_LightColor;
810         int loc_LightDir;
811         int loc_LightPosition;
812         int loc_OffsetMapping_ScaleSteps;
813         int loc_OffsetMapping_LodDistance;
814         int loc_OffsetMapping_Bias;
815         int loc_PixelSize;
816         int loc_ReflectColor;
817         int loc_ReflectFactor;
818         int loc_ReflectOffset;
819         int loc_RefractColor;
820         int loc_Saturation;
821         int loc_ScreenCenterRefractReflect;
822         int loc_ScreenScaleRefractReflect;
823         int loc_ScreenToDepth;
824         int loc_ShadowMap_Parameters;
825         int loc_ShadowMap_TextureScale;
826         int loc_SpecularPower;
827         int loc_Skeletal_Transform12;
828         int loc_UserVec1;
829         int loc_UserVec2;
830         int loc_UserVec3;
831         int loc_UserVec4;
832         int loc_ViewTintColor;
833         int loc_ViewToLight;
834         int loc_ModelToLight;
835         int loc_TexMatrix;
836         int loc_BackgroundTexMatrix;
837         int loc_ModelViewProjectionMatrix;
838         int loc_ModelViewMatrix;
839         int loc_PixelToScreenTexCoord;
840         int loc_ModelToReflectCube;
841         int loc_ShadowMapMatrix;
842         int loc_BloomColorSubtract;
843         int loc_NormalmapScrollBlend;
844         int loc_BounceGridMatrix;
845         int loc_BounceGridIntensity;
846         /// uniform block bindings
847         int ubibind_Skeletal_Transform12_UniformBlock;
848         /// uniform block indices
849         int ubiloc_Skeletal_Transform12_UniformBlock;
850 }
851 r_glsl_permutation_t;
852
853 #define SHADERPERMUTATION_HASHSIZE 256
854
855
856 // non-degradable "lightweight" shader parameters to keep the permutations simpler
857 // these can NOT degrade! only use for simple stuff
858 enum
859 {
860         SHADERSTATICPARM_SATURATION_REDCOMPENSATE = 0, ///< red compensation filter for saturation
861         SHADERSTATICPARM_EXACTSPECULARMATH = 1, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
862         SHADERSTATICPARM_POSTPROCESS_USERVEC1 = 2, ///< postprocess uservec1 is enabled
863         SHADERSTATICPARM_POSTPROCESS_USERVEC2 = 3, ///< postprocess uservec2 is enabled
864         SHADERSTATICPARM_POSTPROCESS_USERVEC3 = 4, ///< postprocess uservec3 is enabled
865         SHADERSTATICPARM_POSTPROCESS_USERVEC4 = 5,  ///< postprocess uservec4 is enabled
866         SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS = 6, // use both alpha layers while blending materials, allows more advanced microblending
867         SHADERSTATICPARM_OFFSETMAPPING_USELOD = 7,  ///< LOD for offsetmapping
868         SHADERSTATICPARM_SHADOWMAPPCF_1 = 8, ///< PCF 1
869         SHADERSTATICPARM_SHADOWMAPPCF_2 = 9, ///< PCF 2
870         SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler
871         SHADERSTATICPARM_CELSHADING = 11, ///< celshading (alternative diffuse and specular math)
872         SHADERSTATICPARM_CELOUTLINES = 12, ///< celoutline (depth buffer analysis to produce outlines)
873         SHADERSTATICPARM_FXAA = 13 ///< fast approximate anti aliasing
874 };
875 #define SHADERSTATICPARMS_COUNT 14
876
877 static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT];
878 static int shaderstaticparms_count = 0;
879
880 static unsigned int r_compileshader_staticparms[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5] = {0};
881 #define R_COMPILESHADER_STATICPARM_ENABLE(p) r_compileshader_staticparms[(p) >> 5] |= (1 << ((p) & 0x1F))
882
883 extern qboolean r_shadow_shadowmapsampler;
884 extern int r_shadow_shadowmappcf;
885 qboolean R_CompileShader_CheckStaticParms(void)
886 {
887         static int r_compileshader_staticparms_save[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5];
888         memcpy(r_compileshader_staticparms_save, r_compileshader_staticparms, sizeof(r_compileshader_staticparms));
889         memset(r_compileshader_staticparms, 0, sizeof(r_compileshader_staticparms));
890
891         // detect all
892         if (r_glsl_saturation_redcompensate.integer)
893                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SATURATION_REDCOMPENSATE);
894         if (r_glsl_vertextextureblend_usebothalphas.integer)
895                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS);
896         if (r_shadow_glossexact.integer)
897                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_EXACTSPECULARMATH);
898         if (r_glsl_postprocess.integer)
899         {
900                 if (r_glsl_postprocess_uservec1_enable.integer)
901                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC1);
902                 if (r_glsl_postprocess_uservec2_enable.integer)
903                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC2);
904                 if (r_glsl_postprocess_uservec3_enable.integer)
905                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC3);
906                 if (r_glsl_postprocess_uservec4_enable.integer)
907                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC4);
908         }
909         if (r_fxaa.integer)
910                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_FXAA);
911         if (r_glsl_offsetmapping_lod.integer && r_glsl_offsetmapping_lod_distance.integer > 0)
912                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_OFFSETMAPPING_USELOD);
913
914         if (r_shadow_shadowmapsampler)
915                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWSAMPLER);
916         if (r_shadow_shadowmappcf > 1)
917                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_2);
918         else if (r_shadow_shadowmappcf)
919                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_1);
920         if (r_celshading.integer)
921                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELSHADING);
922         if (r_celoutlines.integer)
923                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELOUTLINES);
924
925         return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0;
926 }
927
928 #define R_COMPILESHADER_STATICPARM_EMIT(p, n) \
929         if(r_compileshader_staticparms[(p) >> 5] & (1 << ((p) & 0x1F))) \
930                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "#define " n "\n"; \
931         else \
932                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "\n"
933 static void R_CompileShader_AddStaticParms(unsigned int mode, dpuint64 permutation)
934 {
935         shaderstaticparms_count = 0;
936
937         // emit all
938         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SATURATION_REDCOMPENSATE, "SATURATION_REDCOMPENSATE");
939         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_EXACTSPECULARMATH, "USEEXACTSPECULARMATH");
940         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC1, "USERVEC1");
941         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC2, "USERVEC2");
942         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC3, "USERVEC3");
943         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC4, "USERVEC4");
944         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS, "USEBOTHALPHAS");
945         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_OFFSETMAPPING_USELOD, "USEOFFSETMAPPING_LOD");
946         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_1, "USESHADOWMAPPCF 1");
947         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_2, "USESHADOWMAPPCF 2");
948         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWSAMPLER, "USESHADOWSAMPLER");
949         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELSHADING, "USECELSHADING");
950         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELOUTLINES, "USECELOUTLINES");
951         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_FXAA, "USEFXAA");
952 }
953
954 /// information about each possible shader permutation
955 r_glsl_permutation_t *r_glsl_permutationhash[SHADERMODE_COUNT][SHADERPERMUTATION_HASHSIZE];
956 /// currently selected permutation
957 r_glsl_permutation_t *r_glsl_permutation;
958 /// storage for permutations linked in the hash table
959 memexpandablearray_t r_glsl_permutationarray;
960
961 static r_glsl_permutation_t *R_GLSL_FindPermutation(unsigned int mode, dpuint64 permutation)
962 {
963         //unsigned int hashdepth = 0;
964         unsigned int hashindex = (permutation * 0x1021) & (SHADERPERMUTATION_HASHSIZE - 1);
965         r_glsl_permutation_t *p;
966         for (p = r_glsl_permutationhash[mode][hashindex];p;p = p->hashnext)
967         {
968                 if (p->mode == mode && p->permutation == permutation)
969                 {
970                         //if (hashdepth > 10)
971                         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
972                         return p;
973                 }
974                 //hashdepth++;
975         }
976         p = (r_glsl_permutation_t*)Mem_ExpandableArray_AllocRecord(&r_glsl_permutationarray);
977         p->mode = mode;
978         p->permutation = permutation;
979         p->hashnext = r_glsl_permutationhash[mode][hashindex];
980         r_glsl_permutationhash[mode][hashindex] = p;
981         //if (hashdepth > 10)
982         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
983         return p;
984 }
985
986 static char *R_ShaderStrCat(const char **strings)
987 {
988         char *string, *s;
989         const char **p = strings;
990         const char *t;
991         size_t len = 0;
992         for (p = strings;(t = *p);p++)
993                 len += strlen(t);
994         len++;
995         s = string = (char *)Mem_Alloc(r_main_mempool, len);
996         len = 0;
997         for (p = strings;(t = *p);p++)
998         {
999                 len = strlen(t);
1000                 memcpy(s, t, len);
1001                 s += len;
1002         }
1003         *s = 0;
1004         return string;
1005 }
1006
1007 static char *R_ShaderStrCat(const char **strings);
1008 static void R_InitShaderModeInfo(void)
1009 {
1010         int i, language;
1011         shadermodeinfo_t *modeinfo;
1012         // we have a bunch of things to compute that weren't calculated at engine compile time - all filenames should have a crc of the builtin strings to prevent accidental overrides (any customization must be updated to match engine)
1013         for (language = 0; language < SHADERLANGUAGE_COUNT; language++)
1014         {
1015                 for (i = 0; i < SHADERMODE_COUNT; i++)
1016                 {
1017                         char filename[MAX_QPATH];
1018                         modeinfo = &shadermodeinfo[language][i];
1019                         modeinfo->builtinstring = R_ShaderStrCat(modeinfo->builtinshaderstrings);
1020                         modeinfo->builtincrc = CRC_Block((const unsigned char *)modeinfo->builtinstring, strlen(modeinfo->builtinstring));
1021                         dpsnprintf(filename, sizeof(filename), "%s/%s_crc%i.%s", modeinfo->extension, modeinfo->sourcebasename, modeinfo->builtincrc, modeinfo->extension);
1022                         modeinfo->filename = Mem_strdup(r_main_mempool, filename);
1023                 }
1024         }
1025 }
1026
1027 static char *ShaderModeInfo_GetShaderText(shadermodeinfo_t *modeinfo, qboolean printfromdisknotice, qboolean builtinonly)
1028 {
1029         char *shaderstring;
1030         // if the mode has no filename we have to return the builtin string
1031         if (builtinonly || !modeinfo->filename)
1032                 return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1033         // note that FS_LoadFile appends a 0 byte to make it a valid string
1034         shaderstring = (char *)FS_LoadFile(modeinfo->filename, r_main_mempool, false, NULL);
1035         if (shaderstring)
1036         {
1037                 if (printfromdisknotice)
1038                         Con_DPrintf("Loading shaders from file %s...\n", modeinfo->filename);
1039                 return shaderstring;
1040         }
1041         // fall back to builtinstring
1042         return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1043 }
1044
1045 static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, dpuint64 permutation)
1046 {
1047         int i;
1048         int ubibind;
1049         int sampler;
1050         shadermodeinfo_t *modeinfo = &shadermodeinfo[SHADERLANGUAGE_GLSL][mode];
1051         char *sourcestring;
1052         char permutationname[256];
1053         int vertstrings_count = 0;
1054         int geomstrings_count = 0;
1055         int fragstrings_count = 0;
1056         const char *vertstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1057         const char *geomstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1058         const char *fragstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1059
1060         if (p->compiled)
1061                 return;
1062         p->compiled = true;
1063         p->program = 0;
1064
1065         permutationname[0] = 0;
1066         sourcestring = ShaderModeInfo_GetShaderText(modeinfo, true, false);
1067
1068         strlcat(permutationname, modeinfo->filename, sizeof(permutationname));
1069
1070         // we need 140 for r_glsl_skeletal (GL_ARB_uniform_buffer_object)
1071         if(vid.support.glshaderversion >= 140)
1072         {
1073                 vertstrings_list[vertstrings_count++] = "#version 140\n";
1074                 geomstrings_list[geomstrings_count++] = "#version 140\n";
1075                 fragstrings_list[fragstrings_count++] = "#version 140\n";
1076                 vertstrings_list[vertstrings_count++] = "#define GLSL140\n";
1077                 geomstrings_list[geomstrings_count++] = "#define GLSL140\n";
1078                 fragstrings_list[fragstrings_count++] = "#define GLSL140\n";
1079         }
1080         // if we can do #version 130, we should (this improves quality of offset/reliefmapping thanks to textureGrad)
1081         else if(vid.support.glshaderversion >= 130)
1082         {
1083                 vertstrings_list[vertstrings_count++] = "#version 130\n";
1084                 geomstrings_list[geomstrings_count++] = "#version 130\n";
1085                 fragstrings_list[fragstrings_count++] = "#version 130\n";
1086                 vertstrings_list[vertstrings_count++] = "#define GLSL130\n";
1087                 geomstrings_list[geomstrings_count++] = "#define GLSL130\n";
1088                 fragstrings_list[fragstrings_count++] = "#define GLSL130\n";
1089         }
1090         // if we can do #version 120, we should (this adds the invariant keyword)
1091         else if(vid.support.glshaderversion >= 120)
1092         {
1093                 vertstrings_list[vertstrings_count++] = "#version 120\n";
1094                 geomstrings_list[geomstrings_count++] = "#version 120\n";
1095                 fragstrings_list[fragstrings_count++] = "#version 120\n";
1096                 vertstrings_list[vertstrings_count++] = "#define GLSL120\n";
1097                 geomstrings_list[geomstrings_count++] = "#define GLSL120\n";
1098                 fragstrings_list[fragstrings_count++] = "#define GLSL120\n";
1099         }
1100         // GLES also adds several things from GLSL120
1101         switch(vid.renderpath)
1102         {
1103         case RENDERPATH_GLES2:
1104                 vertstrings_list[vertstrings_count++] = "#define GLES\n";
1105                 geomstrings_list[geomstrings_count++] = "#define GLES\n";
1106                 fragstrings_list[fragstrings_count++] = "#define GLES\n";
1107                 break;
1108         default:
1109                 break;
1110         }
1111
1112         // the first pretext is which type of shader to compile as
1113         // (later these will all be bound together as a program object)
1114         vertstrings_list[vertstrings_count++] = "#define VERTEX_SHADER\n";
1115         geomstrings_list[geomstrings_count++] = "#define GEOMETRY_SHADER\n";
1116         fragstrings_list[fragstrings_count++] = "#define FRAGMENT_SHADER\n";
1117
1118         // the second pretext is the mode (for example a light source)
1119         vertstrings_list[vertstrings_count++] = modeinfo->pretext;
1120         geomstrings_list[geomstrings_count++] = modeinfo->pretext;
1121         fragstrings_list[fragstrings_count++] = modeinfo->pretext;
1122         strlcat(permutationname, modeinfo->name, sizeof(permutationname));
1123
1124         // now add all the permutation pretexts
1125         for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1126         {
1127                 if (permutation & (1ll<<i))
1128                 {
1129                         vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i].pretext;
1130                         geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i].pretext;
1131                         fragstrings_list[fragstrings_count++] = shaderpermutationinfo[i].pretext;
1132                         strlcat(permutationname, shaderpermutationinfo[i].name, sizeof(permutationname));
1133                 }
1134                 else
1135                 {
1136                         // keep line numbers correct
1137                         vertstrings_list[vertstrings_count++] = "\n";
1138                         geomstrings_list[geomstrings_count++] = "\n";
1139                         fragstrings_list[fragstrings_count++] = "\n";
1140                 }
1141         }
1142
1143         // add static parms
1144         R_CompileShader_AddStaticParms(mode, permutation);
1145         memcpy((char *)(vertstrings_list + vertstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1146         vertstrings_count += shaderstaticparms_count;
1147         memcpy((char *)(geomstrings_list + geomstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1148         geomstrings_count += shaderstaticparms_count;
1149         memcpy((char *)(fragstrings_list + fragstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1150         fragstrings_count += shaderstaticparms_count;
1151
1152         // now append the shader text itself
1153         vertstrings_list[vertstrings_count++] = sourcestring;
1154         geomstrings_list[geomstrings_count++] = sourcestring;
1155         fragstrings_list[fragstrings_count++] = sourcestring;
1156
1157         // compile the shader program
1158         if (vertstrings_count + geomstrings_count + fragstrings_count)
1159                 p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
1160         if (p->program)
1161         {
1162                 CHECKGLERROR
1163                 qglUseProgram(p->program);CHECKGLERROR
1164                 // look up all the uniform variable names we care about, so we don't
1165                 // have to look them up every time we set them
1166
1167 #if 0
1168                 // debugging aid
1169                 {
1170                         GLint activeuniformindex = 0;
1171                         GLint numactiveuniforms = 0;
1172                         char uniformname[128];
1173                         GLsizei uniformnamelength = 0;
1174                         GLint uniformsize = 0;
1175                         GLenum uniformtype = 0;
1176                         memset(uniformname, 0, sizeof(uniformname));
1177                         qglGetProgramiv(p->program, GL_ACTIVE_UNIFORMS, &numactiveuniforms);
1178                         Con_Printf("Shader has %i uniforms\n", numactiveuniforms);
1179                         for (activeuniformindex = 0;activeuniformindex < numactiveuniforms;activeuniformindex++)
1180                         {
1181                                 qglGetActiveUniform(p->program, activeuniformindex, sizeof(uniformname) - 1, &uniformnamelength, &uniformsize, &uniformtype, uniformname);
1182                                 Con_Printf("Uniform %i name \"%s\" size %i type %i\n", (int)activeuniformindex, uniformname, (int)uniformsize, (int)uniformtype);
1183                         }
1184                 }
1185 #endif
1186
1187                 p->loc_Texture_First              = qglGetUniformLocation(p->program, "Texture_First");
1188                 p->loc_Texture_Second             = qglGetUniformLocation(p->program, "Texture_Second");
1189                 p->loc_Texture_GammaRamps         = qglGetUniformLocation(p->program, "Texture_GammaRamps");
1190                 p->loc_Texture_Normal             = qglGetUniformLocation(p->program, "Texture_Normal");
1191                 p->loc_Texture_Color              = qglGetUniformLocation(p->program, "Texture_Color");
1192                 p->loc_Texture_Gloss              = qglGetUniformLocation(p->program, "Texture_Gloss");
1193                 p->loc_Texture_Glow               = qglGetUniformLocation(p->program, "Texture_Glow");
1194                 p->loc_Texture_SecondaryNormal    = qglGetUniformLocation(p->program, "Texture_SecondaryNormal");
1195                 p->loc_Texture_SecondaryColor     = qglGetUniformLocation(p->program, "Texture_SecondaryColor");
1196                 p->loc_Texture_SecondaryGloss     = qglGetUniformLocation(p->program, "Texture_SecondaryGloss");
1197                 p->loc_Texture_SecondaryGlow      = qglGetUniformLocation(p->program, "Texture_SecondaryGlow");
1198                 p->loc_Texture_Pants              = qglGetUniformLocation(p->program, "Texture_Pants");
1199                 p->loc_Texture_Shirt              = qglGetUniformLocation(p->program, "Texture_Shirt");
1200                 p->loc_Texture_FogHeightTexture   = qglGetUniformLocation(p->program, "Texture_FogHeightTexture");
1201                 p->loc_Texture_FogMask            = qglGetUniformLocation(p->program, "Texture_FogMask");
1202                 p->loc_Texture_Lightmap           = qglGetUniformLocation(p->program, "Texture_Lightmap");
1203                 p->loc_Texture_Deluxemap          = qglGetUniformLocation(p->program, "Texture_Deluxemap");
1204                 p->loc_Texture_Attenuation        = qglGetUniformLocation(p->program, "Texture_Attenuation");
1205                 p->loc_Texture_Cube               = qglGetUniformLocation(p->program, "Texture_Cube");
1206                 p->loc_Texture_Refraction         = qglGetUniformLocation(p->program, "Texture_Refraction");
1207                 p->loc_Texture_Reflection         = qglGetUniformLocation(p->program, "Texture_Reflection");
1208                 p->loc_Texture_ShadowMap2D        = qglGetUniformLocation(p->program, "Texture_ShadowMap2D");
1209                 p->loc_Texture_CubeProjection     = qglGetUniformLocation(p->program, "Texture_CubeProjection");
1210                 p->loc_Texture_ScreenNormalMap    = qglGetUniformLocation(p->program, "Texture_ScreenNormalMap");
1211                 p->loc_Texture_ScreenDiffuse      = qglGetUniformLocation(p->program, "Texture_ScreenDiffuse");
1212                 p->loc_Texture_ScreenSpecular     = qglGetUniformLocation(p->program, "Texture_ScreenSpecular");
1213                 p->loc_Texture_ReflectMask        = qglGetUniformLocation(p->program, "Texture_ReflectMask");
1214                 p->loc_Texture_ReflectCube        = qglGetUniformLocation(p->program, "Texture_ReflectCube");
1215                 p->loc_Texture_BounceGrid         = qglGetUniformLocation(p->program, "Texture_BounceGrid");
1216                 p->loc_Alpha                      = qglGetUniformLocation(p->program, "Alpha");
1217                 p->loc_BloomBlur_Parameters       = qglGetUniformLocation(p->program, "BloomBlur_Parameters");
1218                 p->loc_ClientTime                 = qglGetUniformLocation(p->program, "ClientTime");
1219                 p->loc_Color_Ambient              = qglGetUniformLocation(p->program, "Color_Ambient");
1220                 p->loc_Color_Diffuse              = qglGetUniformLocation(p->program, "Color_Diffuse");
1221                 p->loc_Color_Specular             = qglGetUniformLocation(p->program, "Color_Specular");
1222                 p->loc_Color_Glow                 = qglGetUniformLocation(p->program, "Color_Glow");
1223                 p->loc_Color_Pants                = qglGetUniformLocation(p->program, "Color_Pants");
1224                 p->loc_Color_Shirt                = qglGetUniformLocation(p->program, "Color_Shirt");
1225                 p->loc_DeferredColor_Ambient      = qglGetUniformLocation(p->program, "DeferredColor_Ambient");
1226                 p->loc_DeferredColor_Diffuse      = qglGetUniformLocation(p->program, "DeferredColor_Diffuse");
1227                 p->loc_DeferredColor_Specular     = qglGetUniformLocation(p->program, "DeferredColor_Specular");
1228                 p->loc_DeferredMod_Diffuse        = qglGetUniformLocation(p->program, "DeferredMod_Diffuse");
1229                 p->loc_DeferredMod_Specular       = qglGetUniformLocation(p->program, "DeferredMod_Specular");
1230                 p->loc_DistortScaleRefractReflect = qglGetUniformLocation(p->program, "DistortScaleRefractReflect");
1231                 p->loc_EyePosition                = qglGetUniformLocation(p->program, "EyePosition");
1232                 p->loc_FogColor                   = qglGetUniformLocation(p->program, "FogColor");
1233                 p->loc_FogHeightFade              = qglGetUniformLocation(p->program, "FogHeightFade");
1234                 p->loc_FogPlane                   = qglGetUniformLocation(p->program, "FogPlane");
1235                 p->loc_FogPlaneViewDist           = qglGetUniformLocation(p->program, "FogPlaneViewDist");
1236                 p->loc_FogRangeRecip              = qglGetUniformLocation(p->program, "FogRangeRecip");
1237                 p->loc_LightColor                 = qglGetUniformLocation(p->program, "LightColor");
1238                 p->loc_LightDir                   = qglGetUniformLocation(p->program, "LightDir");
1239                 p->loc_LightPosition              = qglGetUniformLocation(p->program, "LightPosition");
1240                 p->loc_OffsetMapping_ScaleSteps   = qglGetUniformLocation(p->program, "OffsetMapping_ScaleSteps");
1241                 p->loc_OffsetMapping_LodDistance  = qglGetUniformLocation(p->program, "OffsetMapping_LodDistance");
1242                 p->loc_OffsetMapping_Bias         = qglGetUniformLocation(p->program, "OffsetMapping_Bias");
1243                 p->loc_PixelSize                  = qglGetUniformLocation(p->program, "PixelSize");
1244                 p->loc_ReflectColor               = qglGetUniformLocation(p->program, "ReflectColor");
1245                 p->loc_ReflectFactor              = qglGetUniformLocation(p->program, "ReflectFactor");
1246                 p->loc_ReflectOffset              = qglGetUniformLocation(p->program, "ReflectOffset");
1247                 p->loc_RefractColor               = qglGetUniformLocation(p->program, "RefractColor");
1248                 p->loc_Saturation                 = qglGetUniformLocation(p->program, "Saturation");
1249                 p->loc_ScreenCenterRefractReflect = qglGetUniformLocation(p->program, "ScreenCenterRefractReflect");
1250                 p->loc_ScreenScaleRefractReflect  = qglGetUniformLocation(p->program, "ScreenScaleRefractReflect");
1251                 p->loc_ScreenToDepth              = qglGetUniformLocation(p->program, "ScreenToDepth");
1252                 p->loc_ShadowMap_Parameters       = qglGetUniformLocation(p->program, "ShadowMap_Parameters");
1253                 p->loc_ShadowMap_TextureScale     = qglGetUniformLocation(p->program, "ShadowMap_TextureScale");
1254                 p->loc_SpecularPower              = qglGetUniformLocation(p->program, "SpecularPower");
1255                 p->loc_UserVec1                   = qglGetUniformLocation(p->program, "UserVec1");
1256                 p->loc_UserVec2                   = qglGetUniformLocation(p->program, "UserVec2");
1257                 p->loc_UserVec3                   = qglGetUniformLocation(p->program, "UserVec3");
1258                 p->loc_UserVec4                   = qglGetUniformLocation(p->program, "UserVec4");
1259                 p->loc_ViewTintColor              = qglGetUniformLocation(p->program, "ViewTintColor");
1260                 p->loc_ViewToLight                = qglGetUniformLocation(p->program, "ViewToLight");
1261                 p->loc_ModelToLight               = qglGetUniformLocation(p->program, "ModelToLight");
1262                 p->loc_TexMatrix                  = qglGetUniformLocation(p->program, "TexMatrix");
1263                 p->loc_BackgroundTexMatrix        = qglGetUniformLocation(p->program, "BackgroundTexMatrix");
1264                 p->loc_ModelViewMatrix            = qglGetUniformLocation(p->program, "ModelViewMatrix");
1265                 p->loc_ModelViewProjectionMatrix  = qglGetUniformLocation(p->program, "ModelViewProjectionMatrix");
1266                 p->loc_PixelToScreenTexCoord      = qglGetUniformLocation(p->program, "PixelToScreenTexCoord");
1267                 p->loc_ModelToReflectCube         = qglGetUniformLocation(p->program, "ModelToReflectCube");
1268                 p->loc_ShadowMapMatrix            = qglGetUniformLocation(p->program, "ShadowMapMatrix");
1269                 p->loc_BloomColorSubtract         = qglGetUniformLocation(p->program, "BloomColorSubtract");
1270                 p->loc_NormalmapScrollBlend       = qglGetUniformLocation(p->program, "NormalmapScrollBlend");
1271                 p->loc_BounceGridMatrix           = qglGetUniformLocation(p->program, "BounceGridMatrix");
1272                 p->loc_BounceGridIntensity        = qglGetUniformLocation(p->program, "BounceGridIntensity");
1273                 // initialize the samplers to refer to the texture units we use
1274                 p->tex_Texture_First = -1;
1275                 p->tex_Texture_Second = -1;
1276                 p->tex_Texture_GammaRamps = -1;
1277                 p->tex_Texture_Normal = -1;
1278                 p->tex_Texture_Color = -1;
1279                 p->tex_Texture_Gloss = -1;
1280                 p->tex_Texture_Glow = -1;
1281                 p->tex_Texture_SecondaryNormal = -1;
1282                 p->tex_Texture_SecondaryColor = -1;
1283                 p->tex_Texture_SecondaryGloss = -1;
1284                 p->tex_Texture_SecondaryGlow = -1;
1285                 p->tex_Texture_Pants = -1;
1286                 p->tex_Texture_Shirt = -1;
1287                 p->tex_Texture_FogHeightTexture = -1;
1288                 p->tex_Texture_FogMask = -1;
1289                 p->tex_Texture_Lightmap = -1;
1290                 p->tex_Texture_Deluxemap = -1;
1291                 p->tex_Texture_Attenuation = -1;
1292                 p->tex_Texture_Cube = -1;
1293                 p->tex_Texture_Refraction = -1;
1294                 p->tex_Texture_Reflection = -1;
1295                 p->tex_Texture_ShadowMap2D = -1;
1296                 p->tex_Texture_CubeProjection = -1;
1297                 p->tex_Texture_ScreenNormalMap = -1;
1298                 p->tex_Texture_ScreenDiffuse = -1;
1299                 p->tex_Texture_ScreenSpecular = -1;
1300                 p->tex_Texture_ReflectMask = -1;
1301                 p->tex_Texture_ReflectCube = -1;
1302                 p->tex_Texture_BounceGrid = -1;
1303                 // bind the texture samplers in use
1304                 sampler = 0;
1305                 if (p->loc_Texture_First           >= 0) {p->tex_Texture_First            = sampler;qglUniform1i(p->loc_Texture_First           , sampler);sampler++;}
1306                 if (p->loc_Texture_Second          >= 0) {p->tex_Texture_Second           = sampler;qglUniform1i(p->loc_Texture_Second          , sampler);sampler++;}
1307                 if (p->loc_Texture_GammaRamps      >= 0) {p->tex_Texture_GammaRamps       = sampler;qglUniform1i(p->loc_Texture_GammaRamps      , sampler);sampler++;}
1308                 if (p->loc_Texture_Normal          >= 0) {p->tex_Texture_Normal           = sampler;qglUniform1i(p->loc_Texture_Normal          , sampler);sampler++;}
1309                 if (p->loc_Texture_Color           >= 0) {p->tex_Texture_Color            = sampler;qglUniform1i(p->loc_Texture_Color           , sampler);sampler++;}
1310                 if (p->loc_Texture_Gloss           >= 0) {p->tex_Texture_Gloss            = sampler;qglUniform1i(p->loc_Texture_Gloss           , sampler);sampler++;}
1311                 if (p->loc_Texture_Glow            >= 0) {p->tex_Texture_Glow             = sampler;qglUniform1i(p->loc_Texture_Glow            , sampler);sampler++;}
1312                 if (p->loc_Texture_SecondaryNormal >= 0) {p->tex_Texture_SecondaryNormal  = sampler;qglUniform1i(p->loc_Texture_SecondaryNormal , sampler);sampler++;}
1313                 if (p->loc_Texture_SecondaryColor  >= 0) {p->tex_Texture_SecondaryColor   = sampler;qglUniform1i(p->loc_Texture_SecondaryColor  , sampler);sampler++;}
1314                 if (p->loc_Texture_SecondaryGloss  >= 0) {p->tex_Texture_SecondaryGloss   = sampler;qglUniform1i(p->loc_Texture_SecondaryGloss  , sampler);sampler++;}
1315                 if (p->loc_Texture_SecondaryGlow   >= 0) {p->tex_Texture_SecondaryGlow    = sampler;qglUniform1i(p->loc_Texture_SecondaryGlow   , sampler);sampler++;}
1316                 if (p->loc_Texture_Pants           >= 0) {p->tex_Texture_Pants            = sampler;qglUniform1i(p->loc_Texture_Pants           , sampler);sampler++;}
1317                 if (p->loc_Texture_Shirt           >= 0) {p->tex_Texture_Shirt            = sampler;qglUniform1i(p->loc_Texture_Shirt           , sampler);sampler++;}
1318                 if (p->loc_Texture_FogHeightTexture>= 0) {p->tex_Texture_FogHeightTexture = sampler;qglUniform1i(p->loc_Texture_FogHeightTexture, sampler);sampler++;}
1319                 if (p->loc_Texture_FogMask         >= 0) {p->tex_Texture_FogMask          = sampler;qglUniform1i(p->loc_Texture_FogMask         , sampler);sampler++;}
1320                 if (p->loc_Texture_Lightmap        >= 0) {p->tex_Texture_Lightmap         = sampler;qglUniform1i(p->loc_Texture_Lightmap        , sampler);sampler++;}
1321                 if (p->loc_Texture_Deluxemap       >= 0) {p->tex_Texture_Deluxemap        = sampler;qglUniform1i(p->loc_Texture_Deluxemap       , sampler);sampler++;}
1322                 if (p->loc_Texture_Attenuation     >= 0) {p->tex_Texture_Attenuation      = sampler;qglUniform1i(p->loc_Texture_Attenuation     , sampler);sampler++;}
1323                 if (p->loc_Texture_Cube            >= 0) {p->tex_Texture_Cube             = sampler;qglUniform1i(p->loc_Texture_Cube            , sampler);sampler++;}
1324                 if (p->loc_Texture_Refraction      >= 0) {p->tex_Texture_Refraction       = sampler;qglUniform1i(p->loc_Texture_Refraction      , sampler);sampler++;}
1325                 if (p->loc_Texture_Reflection      >= 0) {p->tex_Texture_Reflection       = sampler;qglUniform1i(p->loc_Texture_Reflection      , sampler);sampler++;}
1326                 if (p->loc_Texture_ShadowMap2D     >= 0) {p->tex_Texture_ShadowMap2D      = sampler;qglUniform1i(p->loc_Texture_ShadowMap2D     , sampler);sampler++;}
1327                 if (p->loc_Texture_CubeProjection  >= 0) {p->tex_Texture_CubeProjection   = sampler;qglUniform1i(p->loc_Texture_CubeProjection  , sampler);sampler++;}
1328                 if (p->loc_Texture_ScreenNormalMap >= 0) {p->tex_Texture_ScreenNormalMap  = sampler;qglUniform1i(p->loc_Texture_ScreenNormalMap , sampler);sampler++;}
1329                 if (p->loc_Texture_ScreenDiffuse   >= 0) {p->tex_Texture_ScreenDiffuse    = sampler;qglUniform1i(p->loc_Texture_ScreenDiffuse   , sampler);sampler++;}
1330                 if (p->loc_Texture_ScreenSpecular  >= 0) {p->tex_Texture_ScreenSpecular   = sampler;qglUniform1i(p->loc_Texture_ScreenSpecular  , sampler);sampler++;}
1331                 if (p->loc_Texture_ReflectMask     >= 0) {p->tex_Texture_ReflectMask      = sampler;qglUniform1i(p->loc_Texture_ReflectMask     , sampler);sampler++;}
1332                 if (p->loc_Texture_ReflectCube     >= 0) {p->tex_Texture_ReflectCube      = sampler;qglUniform1i(p->loc_Texture_ReflectCube     , sampler);sampler++;}
1333                 if (p->loc_Texture_BounceGrid      >= 0) {p->tex_Texture_BounceGrid       = sampler;qglUniform1i(p->loc_Texture_BounceGrid      , sampler);sampler++;}
1334                 // get the uniform block indices so we can bind them
1335 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1336                 if (vid.support.arb_uniform_buffer_object)
1337                         p->ubiloc_Skeletal_Transform12_UniformBlock = qglGetUniformBlockIndex(p->program, "Skeletal_Transform12_UniformBlock");
1338                 else
1339 #endif
1340                         p->ubiloc_Skeletal_Transform12_UniformBlock = -1;
1341                 // clear the uniform block bindings
1342                 p->ubibind_Skeletal_Transform12_UniformBlock = -1;
1343                 // bind the uniform blocks in use
1344                 ubibind = 0;
1345 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1346                 if (p->ubiloc_Skeletal_Transform12_UniformBlock >= 0) {p->ubibind_Skeletal_Transform12_UniformBlock = ubibind;qglUniformBlockBinding(p->program, p->ubiloc_Skeletal_Transform12_UniformBlock, ubibind);ubibind++;}
1347 #endif
1348                 // we're done compiling and setting up the shader, at least until it is used
1349                 CHECKGLERROR
1350                 Con_DPrintf("^5GLSL shader %s compiled (%i textures).\n", permutationname, sampler);
1351         }
1352         else
1353                 Con_Printf("^1GLSL shader %s failed!  some features may not work properly.\n", permutationname);
1354
1355         // free the strings
1356         if (sourcestring)
1357                 Mem_Free(sourcestring);
1358 }
1359
1360 static void R_SetupShader_SetPermutationGLSL(unsigned int mode, dpuint64 permutation)
1361 {
1362         r_glsl_permutation_t *perm = R_GLSL_FindPermutation(mode, permutation);
1363         if (r_glsl_permutation != perm)
1364         {
1365                 r_glsl_permutation = perm;
1366                 if (!r_glsl_permutation->program)
1367                 {
1368                         if (!r_glsl_permutation->compiled)
1369                         {
1370                                 Con_DPrintf("Compiling shader mode %u permutation %u\n", mode, permutation);
1371                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1372                         }
1373                         if (!r_glsl_permutation->program)
1374                         {
1375                                 // remove features until we find a valid permutation
1376                                 int i;
1377                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1378                                 {
1379                                         // reduce i more quickly whenever it would not remove any bits
1380                                         dpuint64 j = 1ll<<(SHADERPERMUTATION_COUNT-1-i);
1381                                         if (!(permutation & j))
1382                                                 continue;
1383                                         permutation -= j;
1384                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1385                                         if (!r_glsl_permutation->compiled)
1386                                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1387                                         if (r_glsl_permutation->program)
1388                                                 break;
1389                                 }
1390                                 if (i >= SHADERPERMUTATION_COUNT)
1391                                 {
1392                                         //Con_Printf("Could not find a working OpenGL 2.0 shader for permutation %s %s\n", shadermodeinfo[mode].filename, shadermodeinfo[mode].pretext);
1393                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1394                                         qglUseProgram(0);CHECKGLERROR
1395                                         return; // no bit left to clear, entire mode is broken
1396                                 }
1397                         }
1398                 }
1399                 CHECKGLERROR
1400                 qglUseProgram(r_glsl_permutation->program);CHECKGLERROR
1401         }
1402         if (r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
1403         if (r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
1404         if (r_glsl_permutation->loc_ClientTime >= 0) qglUniform1f(r_glsl_permutation->loc_ClientTime, cl.time);
1405         CHECKGLERROR
1406 }
1407
1408 void R_GLSL_Restart_f(void)
1409 {
1410         unsigned int i, limit;
1411         switch(vid.renderpath)
1412         {
1413         case RENDERPATH_GL20:
1414         case RENDERPATH_GLES2:
1415                 {
1416                         r_glsl_permutation_t *p;
1417                         r_glsl_permutation = NULL;
1418                         limit = (unsigned int)Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
1419                         for (i = 0;i < limit;i++)
1420                         {
1421                                 if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i)))
1422                                 {
1423                                         GL_Backend_FreeProgram(p->program);
1424                                         Mem_ExpandableArray_FreeRecord(&r_glsl_permutationarray, (void*)p);
1425                                 }
1426                         }
1427                         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
1428                 }
1429                 break;
1430         }
1431 }
1432
1433 static void R_GLSL_DumpShader_f(void)
1434 {
1435         int i, language, mode, dupe;
1436         char *text;
1437         shadermodeinfo_t *modeinfo;
1438         qfile_t *file;
1439
1440         for (language = 0;language < SHADERLANGUAGE_COUNT;language++)
1441         {
1442                 modeinfo = shadermodeinfo[language];
1443                 for (mode = 0;mode < SHADERMODE_COUNT;mode++)
1444                 {
1445                         // don't dump the same file multiple times (most or all shaders come from the same file)
1446                         for (dupe = mode - 1;dupe >= 0;dupe--)
1447                                 if (!strcmp(modeinfo[mode].filename, modeinfo[dupe].filename))
1448                                         break;
1449                         if (dupe >= 0)
1450                                 continue;
1451                         text = modeinfo[mode].builtinstring;
1452                         if (!text)
1453                                 continue;
1454                         file = FS_OpenRealFile(modeinfo[mode].filename, "w", false);
1455                         if (file)
1456                         {
1457                                 FS_Print(file, "/* The engine may define the following macros:\n");
1458                                 FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
1459                                 for (i = 0;i < SHADERMODE_COUNT;i++)
1460                                         FS_Print(file, modeinfo[i].pretext);
1461                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1462                                         FS_Print(file, shaderpermutationinfo[i].pretext);
1463                                 FS_Print(file, "*/\n");
1464                                 FS_Print(file, text);
1465                                 FS_Close(file);
1466                                 Con_Printf("%s written\n", modeinfo[mode].filename);
1467                         }
1468                         else
1469                                 Con_Printf("failed to write to %s\n", modeinfo[mode].filename);
1470                 }
1471         }
1472 }
1473
1474 void R_SetupShader_Generic(rtexture_t *first, rtexture_t *second, int texturemode, int rgbscale, qboolean usegamma, qboolean notrippy, qboolean suppresstexalpha)
1475 {
1476         dpuint64 permutation = 0;
1477         if (r_trippy.integer && !notrippy)
1478                 permutation |= SHADERPERMUTATION_TRIPPY;
1479         permutation |= SHADERPERMUTATION_VIEWTINT;
1480         if (first)
1481                 permutation |= SHADERPERMUTATION_DIFFUSE;
1482         if (second)
1483                 permutation |= SHADERPERMUTATION_SPECULAR;
1484         if (texturemode == GL_MODULATE)
1485                 permutation |= SHADERPERMUTATION_COLORMAPPING;
1486         else if (texturemode == GL_ADD)
1487                 permutation |= SHADERPERMUTATION_GLOW;
1488         else if (texturemode == GL_DECAL)
1489                 permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1490         if (usegamma && v_glslgamma_2d.integer && !vid.sRGB2D && r_texture_gammaramps && !vid_gammatables_trivial)
1491                 permutation |= SHADERPERMUTATION_GAMMARAMPS;
1492         if (suppresstexalpha)
1493                 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1494         if (!second)
1495                 texturemode = GL_MODULATE;
1496         if (vid.allowalphatocoverage)
1497                 GL_AlphaToCoverage(false);
1498         switch (vid.renderpath)
1499         {
1500         case RENDERPATH_GL20:
1501         case RENDERPATH_GLES2:
1502                 R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, permutation);
1503                 if (r_glsl_permutation->tex_Texture_First >= 0)
1504                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First , first );
1505                 if (r_glsl_permutation->tex_Texture_Second >= 0)
1506                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second, second);
1507                 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0)
1508                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps);
1509                 break;
1510         }
1511 }
1512
1513 void R_SetupShader_Generic_NoTexture(qboolean usegamma, qboolean notrippy)
1514 {
1515         R_SetupShader_Generic(NULL, NULL, GL_MODULATE, 1, usegamma, notrippy, false);
1516 }
1517
1518 void R_SetupShader_DepthOrShadow(qboolean notrippy, qboolean depthrgb, qboolean skeletal)
1519 {
1520         dpuint64 permutation = 0;
1521         if (r_trippy.integer && !notrippy)
1522                 permutation |= SHADERPERMUTATION_TRIPPY;
1523         if (depthrgb)
1524                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1525         if (skeletal)
1526                 permutation |= SHADERPERMUTATION_SKELETAL;
1527
1528         if (vid.allowalphatocoverage)
1529                 GL_AlphaToCoverage(false);
1530         switch (vid.renderpath)
1531         {
1532         case RENDERPATH_GL20:
1533         case RENDERPATH_GLES2:
1534                 R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation);
1535 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1536                 if (r_glsl_permutation->ubiloc_Skeletal_Transform12_UniformBlock >= 0 && rsurface.batchskeletaltransform3x4buffer) qglBindBufferRange(GL_UNIFORM_BUFFER, r_glsl_permutation->ubibind_Skeletal_Transform12_UniformBlock, rsurface.batchskeletaltransform3x4buffer->bufferobject, rsurface.batchskeletaltransform3x4offset, rsurface.batchskeletaltransform3x4size);
1537 #endif
1538                 break;
1539         }
1540 }
1541
1542 #define BLENDFUNC_ALLOWS_COLORMOD      1
1543 #define BLENDFUNC_ALLOWS_FOG           2
1544 #define BLENDFUNC_ALLOWS_FOG_HACK0     4
1545 #define BLENDFUNC_ALLOWS_FOG_HACKALPHA 8
1546 #define BLENDFUNC_ALLOWS_ANYFOG        (BLENDFUNC_ALLOWS_FOG | BLENDFUNC_ALLOWS_FOG_HACK0 | BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1547 static int R_BlendFuncFlags(int src, int dst)
1548 {
1549         int r = 0;
1550
1551         // a blendfunc allows colormod if:
1552         // a) it can never keep the destination pixel invariant, or
1553         // b) it can keep the destination pixel invariant, and still can do so if colormodded
1554         // this is to prevent unintended side effects from colormod
1555
1556         // a blendfunc allows fog if:
1557         // blend(fog(src), fog(dst)) == fog(blend(src, dst))
1558         // this is to prevent unintended side effects from fog
1559
1560         // these checks are the output of fogeval.pl
1561
1562         r |= BLENDFUNC_ALLOWS_COLORMOD;
1563         if(src == GL_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1564         if(src == GL_DST_ALPHA && dst == GL_ONE_MINUS_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1565         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1566         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1567         if(src == GL_DST_COLOR && dst == GL_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1568         if(src == GL_DST_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1569         if(src == GL_DST_COLOR && dst == GL_ZERO) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1570         if(src == GL_ONE && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1571         if(src == GL_ONE && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG_HACKALPHA;
1572         if(src == GL_ONE && dst == GL_ZERO) r |= BLENDFUNC_ALLOWS_FOG;
1573         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1574         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1575         if(src == GL_ONE_MINUS_DST_COLOR && dst == GL_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1576         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1577         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1578         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1579         if(src == GL_ONE_MINUS_SRC_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1580         if(src == GL_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1581         if(src == GL_SRC_ALPHA && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1582         if(src == GL_ZERO && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG;
1583         if(src == GL_ZERO && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1584
1585         return r;
1586 }
1587
1588 void R_SetupShader_Surface(const float rtlightambient[3], const float rtlightdiffuse[3], const float rtlightspecular[3], rsurfacepass_t rsurfacepass, int texturenumsurfaces, const msurface_t **texturesurfacelist, void *surfacewaterplane, qboolean notrippy)
1589 {
1590         // select a permutation of the lighting shader appropriate to this
1591         // combination of texture, entity, light source, and fogging, only use the
1592         // minimum features necessary to avoid wasting rendering time in the
1593         // fragment shader on features that are not being used
1594         dpuint64 permutation = 0;
1595         unsigned int mode = 0;
1596         int blendfuncflags;
1597         texture_t *t = rsurface.texture;
1598         float m16f[16];
1599         matrix4x4_t tempmatrix;
1600         r_waterstate_waterplane_t *waterplane = (r_waterstate_waterplane_t *)surfacewaterplane;
1601         if (r_trippy.integer && !notrippy)
1602                 permutation |= SHADERPERMUTATION_TRIPPY;
1603         if (t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1604                 permutation |= SHADERPERMUTATION_ALPHAKILL;
1605         if (t->currentmaterialflags & MATERIALFLAG_OCCLUDE)
1606                 permutation |= SHADERPERMUTATION_OCCLUDE;
1607         if (t->r_water_waterscroll[0] && t->r_water_waterscroll[1])
1608                 permutation |= SHADERPERMUTATION_NORMALMAPSCROLLBLEND; // todo: make generic
1609         if (rsurfacepass == RSURFPASS_BACKGROUND)
1610         {
1611                 // distorted background
1612                 if (t->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1613                 {
1614                         mode = SHADERMODE_WATER;
1615                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1616                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1617                         if((r_wateralpha.value < 1) && (t->currentmaterialflags & MATERIALFLAG_WATERALPHA))
1618                         {
1619                                 // this is the right thing to do for wateralpha
1620                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1621                                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1622                         }
1623                         else
1624                         {
1625                                 // this is the right thing to do for entity alpha
1626                                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1627                                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1628                         }
1629                 }
1630                 else if (t->currentmaterialflags & MATERIALFLAG_REFRACTION)
1631                 {
1632                         mode = SHADERMODE_REFRACTION;
1633                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1634                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1635                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1636                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1637                 }
1638                 else
1639                 {
1640                         mode = SHADERMODE_GENERIC;
1641                         permutation |= SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_ALPHAKILL;
1642                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1643                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1644                 }
1645                 if (vid.allowalphatocoverage)
1646                         GL_AlphaToCoverage(false);
1647         }
1648         else if (rsurfacepass == RSURFPASS_DEFERREDGEOMETRY)
1649         {
1650                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1651                 {
1652                         switch(t->offsetmapping)
1653                         {
1654                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1655                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1656                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1657                         case OFFSETMAPPING_OFF: break;
1658                         }
1659                 }
1660                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1661                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1662                 // normalmap (deferred prepass), may use alpha test on diffuse
1663                 mode = SHADERMODE_DEFERREDGEOMETRY;
1664                 GL_BlendFunc(GL_ONE, GL_ZERO);
1665                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1666                 if (vid.allowalphatocoverage)
1667                         GL_AlphaToCoverage(false);
1668         }
1669         else if (rsurfacepass == RSURFPASS_RTLIGHT)
1670         {
1671                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1672                 {
1673                         switch(t->offsetmapping)
1674                         {
1675                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1676                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1677                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1678                         case OFFSETMAPPING_OFF: break;
1679                         }
1680                 }
1681                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1682                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1683                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1684                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1685                 // light source
1686                 mode = SHADERMODE_LIGHTSOURCE;
1687                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1688                         permutation |= SHADERPERMUTATION_CUBEFILTER;
1689                 if (VectorLength2(rtlightdiffuse) > 0)
1690                         permutation |= SHADERPERMUTATION_DIFFUSE;
1691                 if (VectorLength2(rtlightspecular) > 0)
1692                         permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1693                 if (r_refdef.fogenabled)
1694                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1695                 if (t->colormapping)
1696                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1697                 if (r_shadow_usingshadowmap2d)
1698                 {
1699                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1700                         if(r_shadow_shadowmapvsdct)
1701                                 permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
1702
1703                         if (r_shadow_shadowmap2ddepthbuffer)
1704                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1705                 }
1706                 if (t->reflectmasktexture)
1707                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1708                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1709                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE);
1710                 if (vid.allowalphatocoverage)
1711                         GL_AlphaToCoverage(false);
1712         }
1713         else if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
1714         {
1715                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1716                 {
1717                         switch(t->offsetmapping)
1718                         {
1719                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1720                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1721                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1722                         case OFFSETMAPPING_OFF: break;
1723                         }
1724                 }
1725                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1726                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1727                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1728                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1729                 // directional model lighting
1730                 mode = SHADERMODE_LIGHTDIRECTION;
1731                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1732                         permutation |= SHADERPERMUTATION_GLOW;
1733                 if (VectorLength2(t->render_modellight_diffuse))
1734                         permutation |= SHADERPERMUTATION_DIFFUSE;
1735                 if (VectorLength2(t->render_modellight_specular) > 0)
1736                         permutation |= SHADERPERMUTATION_SPECULAR;
1737                 if (r_refdef.fogenabled)
1738                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1739                 if (t->colormapping)
1740                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1741                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1742                 {
1743                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1744                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1745
1746                         if (r_shadow_shadowmap2ddepthbuffer)
1747                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1748                 }
1749                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1750                         permutation |= SHADERPERMUTATION_REFLECTION;
1751                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1752                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1753                 if (t->reflectmasktexture)
1754                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1755                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld)
1756                 {
1757                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1758                         if (r_shadow_bouncegrid_state.directional)
1759                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1760                 }
1761                 GL_BlendFunc(t->currentlayers[0].blendfunc1, t->currentlayers[0].blendfunc2);
1762                 blendfuncflags = R_BlendFuncFlags(t->currentlayers[0].blendfunc1, t->currentlayers[0].blendfunc2);
1763                 // when using alphatocoverage, we don't need alphakill
1764                 if (vid.allowalphatocoverage)
1765                 {
1766                         if (r_transparent_alphatocoverage.integer)
1767                         {
1768                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1769                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1770                         }
1771                         else
1772                                 GL_AlphaToCoverage(false);
1773                 }
1774         }
1775         else
1776         {
1777                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1778                 {
1779                         switch(t->offsetmapping)
1780                         {
1781                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1782                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1783                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1784                         case OFFSETMAPPING_OFF: break;
1785                         }
1786                 }
1787                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1788                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1789                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1790                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1791                 // lightmapped wall
1792                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1793                         permutation |= SHADERPERMUTATION_GLOW;
1794                 if (r_refdef.fogenabled)
1795                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1796                 if (t->colormapping)
1797                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1798                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1799                 {
1800                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1801                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1802
1803                         if (r_shadow_shadowmap2ddepthbuffer)
1804                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1805                 }
1806                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1807                         permutation |= SHADERPERMUTATION_REFLECTION;
1808                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1809                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1810                 if (t->reflectmasktexture)
1811                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1812                 if (FAKELIGHT_ENABLED)
1813                 {
1814                         // fake lightmapping (q1bsp, q3bsp, fullbright map)
1815                         mode = SHADERMODE_FAKELIGHT;
1816                         permutation |= SHADERPERMUTATION_DIFFUSE;
1817                         if (VectorLength2(t->render_lightmap_specular) > 0)
1818                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1819                 }
1820                 else if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping)
1821                 {
1822                         // deluxemapping (light direction texture)
1823                         if (rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping && r_refdef.scene.worldmodel->brushq3.deluxemapping_modelspace)
1824                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE;
1825                         else
1826                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1827                         permutation |= SHADERPERMUTATION_DIFFUSE;
1828                         if (VectorLength2(t->render_lightmap_specular) > 0)
1829                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1830                 }
1831                 else if (r_glsl_deluxemapping.integer >= 2)
1832                 {
1833                         // fake deluxemapping (uniform light direction in tangentspace)
1834                         if (rsurface.uselightmaptexture)
1835                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP;
1836                         else
1837                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR;
1838                         permutation |= SHADERPERMUTATION_DIFFUSE;
1839                         if (VectorLength2(t->render_lightmap_specular) > 0)
1840                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1841                 }
1842                 else if (rsurface.uselightmaptexture)
1843                 {
1844                         // ordinary lightmapping (q1bsp, q3bsp)
1845                         mode = SHADERMODE_LIGHTMAP;
1846                 }
1847                 else
1848                 {
1849                         // ordinary vertex coloring (q3bsp)
1850                         mode = SHADERMODE_VERTEXCOLOR;
1851                 }
1852                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld)
1853                 {
1854                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1855                         if (r_shadow_bouncegrid_state.directional)
1856                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1857                 }
1858                 GL_BlendFunc(t->currentlayers[0].blendfunc1, t->currentlayers[0].blendfunc2);
1859                 blendfuncflags = R_BlendFuncFlags(t->currentlayers[0].blendfunc1, t->currentlayers[0].blendfunc2);
1860                 // when using alphatocoverage, we don't need alphakill
1861                 if (vid.allowalphatocoverage)
1862                 {
1863                         if (r_transparent_alphatocoverage.integer)
1864                         {
1865                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1866                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1867                         }
1868                         else
1869                                 GL_AlphaToCoverage(false);
1870                 }
1871         }
1872         if(!(blendfuncflags & BLENDFUNC_ALLOWS_ANYFOG))
1873                 permutation &= ~(SHADERPERMUTATION_FOGHEIGHTTEXTURE | SHADERPERMUTATION_FOGOUTSIDE | SHADERPERMUTATION_FOGINSIDE);
1874         if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1875                 permutation |= SHADERPERMUTATION_FOGALPHAHACK;
1876         switch(vid.renderpath)
1877         {
1878         case RENDERPATH_GL20:
1879         case RENDERPATH_GLES2:
1880                 if (!vid.useinterleavedarrays)
1881                 {
1882                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | (rsurface.modellightmapcolor4f ? BATCHNEED_ARRAY_VERTEXCOLOR : 0) | BATCHNEED_ARRAY_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_ARRAY_LIGHTMAP : 0) | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
1883                         R_Mesh_VertexPointer(     3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
1884                         R_Mesh_ColorPointer(      4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset);
1885                         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
1886                         R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchsvector3f, rsurface.batchsvector3f_vertexbuffer, rsurface.batchsvector3f_bufferoffset);
1887                         R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset);
1888                         R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset);
1889                         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset);
1890                         R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
1891                         R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, rsurface.batchskeletalindex4ub_vertexbuffer, rsurface.batchskeletalindex4ub_bufferoffset);
1892                         R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, rsurface.batchskeletalweight4ub_vertexbuffer, rsurface.batchskeletalweight4ub_bufferoffset);
1893                 }
1894                 else
1895                 {
1896                         RSurf_PrepareVerticesForBatch(BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | (rsurface.modellightmapcolor4f ? BATCHNEED_VERTEXMESH_VERTEXCOLOR : 0) | BATCHNEED_VERTEXMESH_TEXCOORD | (rsurface.uselightmaptexture ? BATCHNEED_VERTEXMESH_LIGHTMAP : 0) | (rsurface.entityskeletaltransform3x4 ? BATCHNEED_VERTEXMESH_SKELETAL : 0) | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
1897                         R_Mesh_PrepareVertices_Mesh(rsurface.batchnumvertices, rsurface.batchvertexmesh, rsurface.batchvertexmesh_vertexbuffer, rsurface.batchvertexmesh_bufferoffset);
1898                 }
1899                 // this has to be after RSurf_PrepareVerticesForBatch
1900                 if (rsurface.batchskeletaltransform3x4buffer)
1901                         permutation |= SHADERPERMUTATION_SKELETAL;
1902                 R_SetupShader_SetPermutationGLSL(mode, permutation);
1903 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1904                 if (r_glsl_permutation->ubiloc_Skeletal_Transform12_UniformBlock >= 0 && rsurface.batchskeletaltransform3x4buffer) qglBindBufferRange(GL_UNIFORM_BUFFER, r_glsl_permutation->ubibind_Skeletal_Transform12_UniformBlock, rsurface.batchskeletaltransform3x4buffer->bufferobject, rsurface.batchskeletaltransform3x4offset, rsurface.batchskeletaltransform3x4size);
1905 #endif
1906                 if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);}
1907                 if (mode == SHADERMODE_LIGHTSOURCE)
1908                 {
1909                         if (r_glsl_permutation->loc_ModelToLight >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToLight, 1, false, m16f);}
1910                         if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
1911                         if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1912                         if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, rtlightambient[0], rtlightambient[1], rtlightambient[2]);
1913                         if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, rtlightdiffuse[0], rtlightdiffuse[1], rtlightdiffuse[2]);
1914                         if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, rtlightspecular[0], rtlightspecular[1], rtlightspecular[2]);
1915         
1916                         // additive passes are only darkened by fog, not tinted
1917                         if (r_glsl_permutation->loc_FogColor >= 0)
1918                                 qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1919                         if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1f(r_glsl_permutation->loc_SpecularPower, t->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
1920                 }
1921                 else
1922                 {
1923                         if (mode == SHADERMODE_FLATCOLOR)
1924                         {
1925                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_modellight_ambient[0], t->render_modellight_ambient[1], t->render_modellight_ambient[2]);
1926                         }
1927                         else if (mode == SHADERMODE_LIGHTDIRECTION)
1928                         {
1929                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_modellight_ambient[0], t->render_modellight_ambient[1], t->render_modellight_ambient[2]);
1930                                 if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, t->render_modellight_diffuse[0], t->render_modellight_diffuse[1], t->render_modellight_diffuse[2]);
1931                                 if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, t->render_modellight_specular[0], t->render_modellight_specular[1], t->render_modellight_specular[2]);
1932                                 if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Diffuse, t->render_rtlight_diffuse[0], t->render_rtlight_diffuse[1], t->render_rtlight_diffuse[2]);
1933                                 if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, t->render_rtlight_specular[0], t->render_rtlight_specular[1], t->render_rtlight_specular[2]);
1934                                 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1935                                 if (r_glsl_permutation->loc_LightDir >= 0) qglUniform3f(r_glsl_permutation->loc_LightDir, t->render_modellight_lightdir[0], t->render_modellight_lightdir[1], t->render_modellight_lightdir[2]);
1936                         }
1937                         else
1938                         {
1939                                 if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, t->render_lightmap_ambient[0], t->render_lightmap_ambient[1], t->render_lightmap_ambient[2]);
1940                                 if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, t->render_lightmap_diffuse[0], t->render_lightmap_diffuse[1], t->render_lightmap_diffuse[2]);
1941                                 if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, t->render_lightmap_specular[0], t->render_lightmap_specular[1], t->render_lightmap_specular[2]);
1942                                 if (r_glsl_permutation->loc_DeferredMod_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Diffuse, t->render_rtlight_diffuse[0], t->render_rtlight_diffuse[1], t->render_rtlight_diffuse[2]);
1943                                 if (r_glsl_permutation->loc_DeferredMod_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_DeferredMod_Specular, t->render_rtlight_specular[0], t->render_rtlight_specular[1], t->render_rtlight_specular[2]);
1944                         }
1945                         // additive passes are only darkened by fog, not tinted
1946                         if (r_glsl_permutation->loc_FogColor >= 0)
1947                         {
1948                                 if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0)
1949                                         qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1950                                 else
1951                                         qglUniform3f(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1952                         }
1953                         if (r_glsl_permutation->loc_DistortScaleRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_DistortScaleRefractReflect, r_water_refractdistort.value * t->refractfactor, r_water_refractdistort.value * t->refractfactor, r_water_reflectdistort.value * t->reflectfactor, r_water_reflectdistort.value * t->reflectfactor);
1954                         if (r_glsl_permutation->loc_ScreenScaleRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_ScreenScaleRefractReflect, r_fb.water.screenscale[0], r_fb.water.screenscale[1], r_fb.water.screenscale[0], r_fb.water.screenscale[1]);
1955                         if (r_glsl_permutation->loc_ScreenCenterRefractReflect >= 0) qglUniform4f(r_glsl_permutation->loc_ScreenCenterRefractReflect, r_fb.water.screencenter[0], r_fb.water.screencenter[1], r_fb.water.screencenter[0], r_fb.water.screencenter[1]);
1956                         if (r_glsl_permutation->loc_RefractColor >= 0) qglUniform4f(r_glsl_permutation->loc_RefractColor, t->refractcolor4f[0], t->refractcolor4f[1], t->refractcolor4f[2], t->refractcolor4f[3] * t->currentalpha);
1957                         if (r_glsl_permutation->loc_ReflectColor >= 0) qglUniform4f(r_glsl_permutation->loc_ReflectColor, t->reflectcolor4f[0], t->reflectcolor4f[1], t->reflectcolor4f[2], t->reflectcolor4f[3] * t->currentalpha);
1958                         if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectFactor, t->reflectmax - t->reflectmin);
1959                         if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectOffset, t->reflectmin);
1960                         if (r_glsl_permutation->loc_SpecularPower >= 0) qglUniform1f(r_glsl_permutation->loc_SpecularPower, t->specularpower * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
1961                         if (r_glsl_permutation->loc_NormalmapScrollBlend >= 0) qglUniform2f(r_glsl_permutation->loc_NormalmapScrollBlend, t->r_water_waterscroll[0], t->r_water_waterscroll[1]);
1962                 }
1963                 if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currenttexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
1964                 if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
1965                 if (r_glsl_permutation->loc_ShadowMapMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ShadowMapMatrix, 1, false, m16f);}
1966                 if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
1967                 {
1968                         if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_modelshadowmap_texturescale[0], r_shadow_modelshadowmap_texturescale[1], r_shadow_modelshadowmap_texturescale[2], r_shadow_modelshadowmap_texturescale[3]);
1969                         if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_modelshadowmap_parameters[0], r_shadow_modelshadowmap_parameters[1], r_shadow_modelshadowmap_parameters[2], r_shadow_modelshadowmap_parameters[3]);
1970                 }
1971                 else
1972                 {
1973                         if (r_glsl_permutation->loc_ShadowMap_TextureScale >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_TextureScale, r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
1974                         if (r_glsl_permutation->loc_ShadowMap_Parameters >= 0) qglUniform4f(r_glsl_permutation->loc_ShadowMap_Parameters, r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
1975                 }
1976
1977                 if (r_glsl_permutation->loc_Color_Glow >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Glow, t->render_glowmod[0], t->render_glowmod[1], t->render_glowmod[2]);
1978                 if (r_glsl_permutation->loc_Alpha >= 0) qglUniform1f(r_glsl_permutation->loc_Alpha, t->currentalpha * ((t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay) ? t->r_water_wateralpha : 1));
1979                 if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3f(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
1980                 if (r_glsl_permutation->loc_Color_Pants >= 0)
1981                 {
1982                         if (t->pantstexture)
1983                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, t->render_colormap_pants[0], t->render_colormap_pants[1], t->render_colormap_pants[2]);
1984                         else
1985                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
1986                 }
1987                 if (r_glsl_permutation->loc_Color_Shirt >= 0)
1988                 {
1989                         if (t->shirttexture)
1990                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, t->render_colormap_shirt[0], t->render_colormap_shirt[1], t->render_colormap_shirt[2]);
1991                         else
1992                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
1993                 }
1994                 if (r_glsl_permutation->loc_FogPlane >= 0) qglUniform4f(r_glsl_permutation->loc_FogPlane, rsurface.fogplane[0], rsurface.fogplane[1], rsurface.fogplane[2], rsurface.fogplane[3]);
1995                 if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1f(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist);
1996                 if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1f(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
1997                 if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1f(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
1998                 if (r_glsl_permutation->loc_OffsetMapping_ScaleSteps >= 0) qglUniform4f(r_glsl_permutation->loc_OffsetMapping_ScaleSteps,
1999                                 r_glsl_offsetmapping_scale.value*t->offsetscale,
2000                                 max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2001                                 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2002                                 max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer)
2003                         );
2004                 if (r_glsl_permutation->loc_OffsetMapping_LodDistance >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_LodDistance, r_glsl_offsetmapping_lod_distance.integer * r_refdef.view.quality);
2005                 if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, t->offsetbias);
2006                 if (r_glsl_permutation->loc_ScreenToDepth >= 0) qglUniform2f(r_glsl_permutation->loc_ScreenToDepth, r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
2007                 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
2008                 if (r_glsl_permutation->loc_BounceGridMatrix >= 0) {Matrix4x4_Concat(&tempmatrix, &r_shadow_bouncegrid_state.matrix, &rsurface.matrix);Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BounceGridMatrix, 1, false, m16f);}
2009                 if (r_glsl_permutation->loc_BounceGridIntensity >= 0) qglUniform1f(r_glsl_permutation->loc_BounceGridIntensity, r_shadow_bouncegrid_state.intensity*r_refdef.view.colorscale);
2010
2011                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First            , r_texture_white                                     );
2012                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second           , r_texture_white                                     );
2013                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps       , r_texture_gammaramps                                );
2014                 if (r_glsl_permutation->tex_Texture_Normal          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Normal           , t->nmaptexture                       );
2015                 if (r_glsl_permutation->tex_Texture_Color           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Color            , t->basetexture                       );
2016                 if (r_glsl_permutation->tex_Texture_Gloss           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Gloss            , t->glosstexture                      );
2017                 if (r_glsl_permutation->tex_Texture_Glow            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Glow             , t->glowtexture                       );
2018                 if (r_glsl_permutation->tex_Texture_SecondaryNormal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryNormal  , t->backgroundnmaptexture             );
2019                 if (r_glsl_permutation->tex_Texture_SecondaryColor  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryColor   , t->backgroundbasetexture             );
2020                 if (r_glsl_permutation->tex_Texture_SecondaryGloss  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGloss   , t->backgroundglosstexture            );
2021                 if (r_glsl_permutation->tex_Texture_SecondaryGlow   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGlow    , t->backgroundglowtexture             );
2022                 if (r_glsl_permutation->tex_Texture_Pants           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Pants            , t->pantstexture                      );
2023                 if (r_glsl_permutation->tex_Texture_Shirt           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Shirt            , t->shirttexture                      );
2024                 if (r_glsl_permutation->tex_Texture_ReflectMask     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectMask      , t->reflectmasktexture                );
2025                 if (r_glsl_permutation->tex_Texture_ReflectCube     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectCube      , t->reflectcubetexture ? t->reflectcubetexture : r_texture_whitecube);
2026                 if (r_glsl_permutation->tex_Texture_FogHeightTexture>= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogHeightTexture , r_texture_fogheighttexture                          );
2027                 if (r_glsl_permutation->tex_Texture_FogMask         >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogMask          , r_texture_fogattenuation                            );
2028                 if (r_glsl_permutation->tex_Texture_Lightmap        >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Lightmap         , rsurface.lightmaptexture ? rsurface.lightmaptexture : r_texture_white);
2029                 if (r_glsl_permutation->tex_Texture_Deluxemap       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Deluxemap        , rsurface.deluxemaptexture ? rsurface.deluxemaptexture : r_texture_blanknormalmap);
2030                 if (r_glsl_permutation->tex_Texture_Attenuation     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation      , r_shadow_attenuationgradienttexture                 );
2031                 if (rsurfacepass == RSURFPASS_BACKGROUND)
2032                 {
2033                         if (r_glsl_permutation->tex_Texture_Refraction  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Refraction        , waterplane->rt_refraction ? waterplane->rt_refraction->colortexture[0] : r_texture_black);
2034                         if (r_glsl_permutation->tex_Texture_First       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First             , waterplane->rt_camera ? waterplane->rt_camera->colortexture[0] : r_texture_black);
2035                         if (r_glsl_permutation->tex_Texture_Reflection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Reflection        , waterplane->rt_reflection ? waterplane->rt_reflection->colortexture[0] : r_texture_black);
2036                 }
2037                 else
2038                 {
2039                         if (r_glsl_permutation->tex_Texture_Reflection >= 0 && waterplane) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Reflection        , waterplane->rt_reflection ? waterplane->rt_reflection->colortexture[0] : r_texture_black);
2040                 }
2041                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap   , r_shadow_prepassgeometrynormalmaptexture            );
2042                 if (r_glsl_permutation->tex_Texture_ScreenDiffuse   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDiffuse     , r_shadow_prepasslightingdiffusetexture              );
2043                 if (r_glsl_permutation->tex_Texture_ScreenSpecular  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenSpecular    , r_shadow_prepasslightingspeculartexture             );
2044                 if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)))
2045                 {
2046                         if (r_glsl_permutation->tex_Texture_ShadowMap2D     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D, r_shadow_shadowmap2ddepthtexture                           );
2047                         if (rsurface.rtlight)
2048                         {
2049                                 if (r_glsl_permutation->tex_Texture_Cube            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube              , rsurface.rtlight->currentcubemap                    );
2050                                 if (r_glsl_permutation->tex_Texture_CubeProjection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection    , r_shadow_shadowmapvsdcttexture                      );
2051                         }
2052                 }
2053                 if (r_glsl_permutation->tex_Texture_BounceGrid  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_BounceGrid, r_shadow_bouncegrid_state.texture);
2054                 CHECKGLERROR
2055                 break;
2056         }
2057 }
2058
2059 void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
2060 {
2061         // select a permutation of the lighting shader appropriate to this
2062         // combination of texture, entity, light source, and fogging, only use the
2063         // minimum features necessary to avoid wasting rendering time in the
2064         // fragment shader on features that are not being used
2065         dpuint64 permutation = 0;
2066         unsigned int mode = 0;
2067         const float *lightcolorbase = rtlight->currentcolor;
2068         float ambientscale = rtlight->ambientscale;
2069         float diffusescale = rtlight->diffusescale;
2070         float specularscale = rtlight->specularscale;
2071         // this is the location of the light in view space
2072         vec3_t viewlightorigin;
2073         // this transforms from view space (camera) to light space (cubemap)
2074         matrix4x4_t viewtolight;
2075         matrix4x4_t lighttoview;
2076         float viewtolight16f[16];
2077         // light source
2078         mode = SHADERMODE_DEFERREDLIGHTSOURCE;
2079         if (rtlight->currentcubemap != r_texture_whitecube)
2080                 permutation |= SHADERPERMUTATION_CUBEFILTER;
2081         if (diffusescale > 0)
2082                 permutation |= SHADERPERMUTATION_DIFFUSE;
2083         if (specularscale > 0 && r_shadow_gloss.integer > 0)
2084                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
2085         if (r_shadow_usingshadowmap2d)
2086         {
2087                 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
2088                 if (r_shadow_shadowmapvsdct)
2089                         permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
2090
2091                 if (r_shadow_shadowmap2ddepthbuffer)
2092                         permutation |= SHADERPERMUTATION_DEPTHRGB;
2093         }
2094         if (vid.allowalphatocoverage)
2095                 GL_AlphaToCoverage(false);
2096         Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rtlight->shadoworigin, viewlightorigin);
2097         Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rtlight->matrix_lighttoworld);
2098         Matrix4x4_Invert_Full(&viewtolight, &lighttoview);
2099         Matrix4x4_ToArrayFloatGL(&viewtolight, viewtolight16f);
2100         switch(vid.renderpath)
2101         {
2102         case RENDERPATH_GL20:
2103         case RENDERPATH_GLES2:
2104                 R_SetupShader_SetPermutationGLSL(mode, permutation);
2105                 if (r_glsl_permutation->loc_LightPosition             >= 0) qglUniform3f(       r_glsl_permutation->loc_LightPosition            , viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]);
2106                 if (r_glsl_permutation->loc_ViewToLight               >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ViewToLight              , 1, false, viewtolight16f);
2107                 if (r_glsl_permutation->loc_DeferredColor_Ambient     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Ambient    , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
2108                 if (r_glsl_permutation->loc_DeferredColor_Diffuse     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Diffuse    , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
2109                 if (r_glsl_permutation->loc_DeferredColor_Specular    >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Specular   , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
2110                 if (r_glsl_permutation->loc_ShadowMap_TextureScale    >= 0) qglUniform4f(       r_glsl_permutation->loc_ShadowMap_TextureScale   , r_shadow_lightshadowmap_texturescale[0], r_shadow_lightshadowmap_texturescale[1], r_shadow_lightshadowmap_texturescale[2], r_shadow_lightshadowmap_texturescale[3]);
2111                 if (r_glsl_permutation->loc_ShadowMap_Parameters      >= 0) qglUniform4f(       r_glsl_permutation->loc_ShadowMap_Parameters     , r_shadow_lightshadowmap_parameters[0], r_shadow_lightshadowmap_parameters[1], r_shadow_lightshadowmap_parameters[2], r_shadow_lightshadowmap_parameters[3]);
2112                 if (r_glsl_permutation->loc_SpecularPower             >= 0) qglUniform1f(       r_glsl_permutation->loc_SpecularPower            , (r_shadow_gloss.integer == 2 ? r_shadow_gloss2exponent.value : r_shadow_glossexponent.value) * (r_shadow_glossexact.integer ? 0.25f : 1.0f) - 1.0f);
2113                 if (r_glsl_permutation->loc_ScreenToDepth             >= 0) qglUniform2f(       r_glsl_permutation->loc_ScreenToDepth            , r_refdef.view.viewport.screentodepth[0], r_refdef.view.viewport.screentodepth[1]);
2114                 if (r_glsl_permutation->loc_PixelToScreenTexCoord     >= 0) qglUniform2f(       r_glsl_permutation->loc_PixelToScreenTexCoord    , 1.0f/vid.width, 1.0f/vid.height);
2115
2116                 if (r_glsl_permutation->tex_Texture_Attenuation       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation        , r_shadow_attenuationgradienttexture                 );
2117                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap    , r_shadow_prepassgeometrynormalmaptexture            );
2118                 if (r_glsl_permutation->tex_Texture_Cube              >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube               , rsurface.rtlight->currentcubemap                    );
2119                 if (r_glsl_permutation->tex_Texture_ShadowMap2D       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D        , r_shadow_shadowmap2ddepthtexture                    );
2120                 if (r_glsl_permutation->tex_Texture_CubeProjection    >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection     , r_shadow_shadowmapvsdcttexture                      );
2121                 break;
2122         }
2123 }
2124
2125 #define SKINFRAME_HASH 1024
2126
2127 typedef struct
2128 {
2129         unsigned int loadsequence; // incremented each level change
2130         memexpandablearray_t array;
2131         skinframe_t *hash[SKINFRAME_HASH];
2132 }
2133 r_skinframe_t;
2134 r_skinframe_t r_skinframe;
2135
2136 void R_SkinFrame_PrepareForPurge(void)
2137 {
2138         r_skinframe.loadsequence++;
2139         // wrap it without hitting zero
2140         if (r_skinframe.loadsequence >= 200)
2141                 r_skinframe.loadsequence = 1;
2142 }
2143
2144 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
2145 {
2146         if (!skinframe)
2147                 return;
2148         // mark the skinframe as used for the purging code
2149         skinframe->loadsequence = r_skinframe.loadsequence;
2150 }
2151
2152 void R_SkinFrame_PurgeSkinFrame(skinframe_t *s)
2153 {
2154         if (s == NULL)
2155                 return;
2156         if (s->merged == s->base)
2157                 s->merged = NULL;
2158         R_PurgeTexture(s->stain); s->stain = NULL;
2159         R_PurgeTexture(s->merged); s->merged = NULL;
2160         R_PurgeTexture(s->base); s->base = NULL;
2161         R_PurgeTexture(s->pants); s->pants = NULL;
2162         R_PurgeTexture(s->shirt); s->shirt = NULL;
2163         R_PurgeTexture(s->nmap); s->nmap = NULL;
2164         R_PurgeTexture(s->gloss); s->gloss = NULL;
2165         R_PurgeTexture(s->glow); s->glow = NULL;
2166         R_PurgeTexture(s->fog); s->fog = NULL;
2167         R_PurgeTexture(s->reflect); s->reflect = NULL;
2168         s->loadsequence = 0;
2169 }
2170
2171 void R_SkinFrame_Purge(void)
2172 {
2173         int i;
2174         skinframe_t *s;
2175         for (i = 0;i < SKINFRAME_HASH;i++)
2176         {
2177                 for (s = r_skinframe.hash[i];s;s = s->next)
2178                 {
2179                         if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
2180                                 R_SkinFrame_PurgeSkinFrame(s);
2181                 }
2182         }
2183 }
2184
2185 skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name ) {
2186         skinframe_t *item;
2187         char basename[MAX_QPATH];
2188
2189         Image_StripImageExtension(name, basename, sizeof(basename));
2190
2191         if( last == NULL ) {
2192                 int hashindex;
2193                 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2194                 item = r_skinframe.hash[hashindex];
2195         } else {
2196                 item = last->next;
2197         }
2198
2199         // linearly search through the hash bucket
2200         for( ; item ; item = item->next ) {
2201                 if( !strcmp( item->basename, basename ) ) {
2202                         return item;
2203                 }
2204         }
2205         return NULL;
2206 }
2207
2208 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qboolean add)
2209 {
2210         skinframe_t *item;
2211         int hashindex;
2212         char basename[MAX_QPATH];
2213
2214         Image_StripImageExtension(name, basename, sizeof(basename));
2215
2216         hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2217         for (item = r_skinframe.hash[hashindex];item;item = item->next)
2218                 if (!strcmp(item->basename, basename) && (comparecrc < 0 || (item->textureflags == textureflags && item->comparewidth == comparewidth && item->compareheight == compareheight && item->comparecrc == comparecrc)))
2219                         break;
2220
2221         if (!item)
2222         {
2223                 if (!add)
2224                         return NULL;
2225                 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
2226                 memset(item, 0, sizeof(*item));
2227                 strlcpy(item->basename, basename, sizeof(item->basename));
2228                 item->textureflags = textureflags & ~TEXF_FORCE_RELOAD;
2229                 item->comparewidth = comparewidth;
2230                 item->compareheight = compareheight;
2231                 item->comparecrc = comparecrc;
2232                 item->next = r_skinframe.hash[hashindex];
2233                 r_skinframe.hash[hashindex] = item;
2234         }
2235         else if (textureflags & TEXF_FORCE_RELOAD)
2236         {
2237                 if (!add)
2238                         return NULL;
2239                 R_SkinFrame_PurgeSkinFrame(item);
2240         }
2241
2242         R_SkinFrame_MarkUsed(item);
2243         return item;
2244 }
2245
2246 #define R_SKINFRAME_LOAD_AVERAGE_COLORS(cnt, getpixel) \
2247         { \
2248                 unsigned long long avgcolor[5], wsum; \
2249                 int pix, comp, w; \
2250                 avgcolor[0] = 0; \
2251                 avgcolor[1] = 0; \
2252                 avgcolor[2] = 0; \
2253                 avgcolor[3] = 0; \
2254                 avgcolor[4] = 0; \
2255                 wsum = 0; \
2256                 for(pix = 0; pix < cnt; ++pix) \
2257                 { \
2258                         w = 0; \
2259                         for(comp = 0; comp < 3; ++comp) \
2260                                 w += getpixel; \
2261                         if(w) /* ignore perfectly black pixels because that is better for model skins */ \
2262                         { \
2263                                 ++wsum; \
2264                                 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2265                                 w = getpixel; \
2266                                 for(comp = 0; comp < 3; ++comp) \
2267                                         avgcolor[comp] += getpixel * w; \
2268                                 avgcolor[3] += w; \
2269                         } \
2270                         /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2271                         avgcolor[4] += getpixel; \
2272                 } \
2273                 if(avgcolor[3] == 0) /* no pixels seen? even worse */ \
2274                         avgcolor[3] = 1; \
2275                 skinframe->avgcolor[0] = avgcolor[2] / (255.0 * avgcolor[3]); \
2276                 skinframe->avgcolor[1] = avgcolor[1] / (255.0 * avgcolor[3]); \
2277                 skinframe->avgcolor[2] = avgcolor[0] / (255.0 * avgcolor[3]); \
2278                 skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \
2279         }
2280
2281 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2282 {
2283         skinframe_t *skinframe;
2284
2285         if (cls.state == ca_dedicated)
2286                 return NULL;
2287
2288         // return an existing skinframe if already loaded
2289         // if loading of the first image fails, don't make a new skinframe as it
2290         // would cause all future lookups of this to be missing
2291         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, -1, false);
2292         if (skinframe && skinframe->base)
2293                 return skinframe;
2294
2295         return R_SkinFrame_LoadExternal_SkinFrame(skinframe, name, textureflags, complain, fallbacknotexture);
2296 }
2297
2298 extern cvar_t gl_picmip;
2299 skinframe_t *R_SkinFrame_LoadExternal_SkinFrame(skinframe_t *skinframe, const char *name, int textureflags, qboolean complain, qboolean fallbacknotexture)
2300 {
2301         int j;
2302         unsigned char *pixels;
2303         unsigned char *bumppixels;
2304         unsigned char *basepixels = NULL;
2305         int basepixels_width = 0;
2306         int basepixels_height = 0;
2307         rtexture_t *ddsbase = NULL;
2308         qboolean ddshasalpha = false;
2309         float ddsavgcolor[4];
2310         char basename[MAX_QPATH];
2311         int miplevel = R_PicmipForFlags(textureflags);
2312         int savemiplevel = miplevel;
2313         int mymiplevel;
2314         char vabuf[1024];
2315
2316         if (cls.state == ca_dedicated)
2317                 return NULL;
2318
2319         Image_StripImageExtension(name, basename, sizeof(basename));
2320
2321         // check for DDS texture file first
2322         if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false)))
2323         {
2324                 basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel);
2325                 if (basepixels == NULL && fallbacknotexture)
2326                         basepixels = Image_GenerateNoTexture();
2327                 if (basepixels == NULL)
2328                         return NULL;
2329         }
2330
2331         // FIXME handle miplevel
2332
2333         if (developer_loading.integer)
2334                 Con_Printf("loading skin \"%s\"\n", name);
2335
2336         // we've got some pixels to store, so really allocate this new texture now
2337         if (!skinframe)
2338                 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
2339         textureflags &= ~TEXF_FORCE_RELOAD;
2340         skinframe->stain = NULL;
2341         skinframe->merged = NULL;
2342         skinframe->base = NULL;
2343         skinframe->pants = NULL;
2344         skinframe->shirt = NULL;
2345         skinframe->nmap = NULL;
2346         skinframe->gloss = NULL;
2347         skinframe->glow = NULL;
2348         skinframe->fog = NULL;
2349         skinframe->reflect = NULL;
2350         skinframe->hasalpha = false;
2351         // we could store the q2animname here too
2352
2353         if (ddsbase)
2354         {
2355                 skinframe->base = ddsbase;
2356                 skinframe->hasalpha = ddshasalpha;
2357                 VectorCopy(ddsavgcolor, skinframe->avgcolor);
2358                 if (r_loadfog && skinframe->hasalpha)
2359                         skinframe->fog = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), false, textureflags | TEXF_ALPHA, NULL, NULL, miplevel, true);
2360                 //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2361         }
2362         else
2363         {
2364                 basepixels_width = image_width;
2365                 basepixels_height = image_height;
2366                 skinframe->base = R_LoadTexture2D (r_main_texturepool, skinframe->basename, basepixels_width, basepixels_height, basepixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), miplevel, NULL);
2367                 if (textureflags & TEXF_ALPHA)
2368                 {
2369                         for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
2370                         {
2371                                 if (basepixels[j] < 255)
2372                                 {
2373                                         skinframe->hasalpha = true;
2374                                         break;
2375                                 }
2376                         }
2377                         if (r_loadfog && skinframe->hasalpha)
2378                         {
2379                                 // has transparent pixels
2380                                 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2381                                 for (j = 0;j < image_width * image_height * 4;j += 4)
2382                                 {
2383                                         pixels[j+0] = 255;
2384                                         pixels[j+1] = 255;
2385                                         pixels[j+2] = 255;
2386                                         pixels[j+3] = basepixels[j+3];
2387                                 }
2388                                 skinframe->fog = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_mask", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), miplevel, NULL);
2389                                 Mem_Free(pixels);
2390                         }
2391                 }
2392                 R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
2393 #ifndef USE_GLES2
2394                 //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2395                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->base)
2396                         R_SaveTextureDDSFile(skinframe->base, va(vabuf, sizeof(vabuf), "dds/%s.dds", skinframe->basename), r_texture_dds_save.integer < 2, skinframe->hasalpha);
2397                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->fog)
2398                         R_SaveTextureDDSFile(skinframe->fog, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2399 #endif
2400         }
2401
2402         if (r_loaddds)
2403         {
2404                 mymiplevel = savemiplevel;
2405                 if (r_loadnormalmap)
2406                         skinframe->nmap = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), false, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), NULL, NULL, mymiplevel, true);
2407                 skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2408                 if (r_loadgloss)
2409                         skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2410                 skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2411                 skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2412                 skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2413         }
2414
2415         // _norm is the name used by tenebrae and has been adopted as standard
2416         if (r_loadnormalmap && skinframe->nmap == NULL)
2417         {
2418                 mymiplevel = savemiplevel;
2419                 if ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2420                 {
2421                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2422                         Mem_Free(pixels);
2423                         pixels = NULL;
2424                 }
2425                 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_bump", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2426                 {
2427                         pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2428                         Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
2429                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), image_width, image_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2430                         Mem_Free(pixels);
2431                         Mem_Free(bumppixels);
2432                 }
2433                 else if (r_shadow_bumpscale_basetexture.value > 0)
2434                 {
2435                         pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
2436                         Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
2437                         skinframe->nmap = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), basepixels_width, basepixels_height, pixels, TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP) & (gl_texturecompression_normal.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2438                         Mem_Free(pixels);
2439                 }
2440 #ifndef USE_GLES2
2441                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->nmap)
2442                         R_SaveTextureDDSFile(skinframe->nmap, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2443 #endif
2444         }
2445
2446         // _luma is supported only for tenebrae compatibility
2447         // _glow is the preferred name
2448         mymiplevel = savemiplevel;
2449         if (skinframe->glow == NULL && ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_glow",  skinframe->basename), false, false, false, &mymiplevel)) || (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_luma", skinframe->basename), false, false, false, &mymiplevel))))
2450         {
2451                 skinframe->glow = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_glow.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2452 #ifndef USE_GLES2
2453                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->glow)
2454                         R_SaveTextureDDSFile(skinframe->glow, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2455 #endif
2456                 Mem_Free(pixels);pixels = NULL;
2457         }
2458
2459         mymiplevel = savemiplevel;
2460         if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), false, false, false, &mymiplevel)))
2461         {
2462                 skinframe->gloss = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, (TEXF_ALPHA | textureflags) & (gl_texturecompression_gloss.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2463 #ifndef USE_GLES2
2464                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->gloss)
2465                         R_SaveTextureDDSFile(skinframe->gloss, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2466 #endif
2467                 Mem_Free(pixels);
2468                 pixels = NULL;
2469         }
2470
2471         mymiplevel = savemiplevel;
2472         if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), false, false, false, &mymiplevel)))
2473         {
2474                 skinframe->pants = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2475 #ifndef USE_GLES2
2476                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->pants)
2477                         R_SaveTextureDDSFile(skinframe->pants, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2478 #endif
2479                 Mem_Free(pixels);
2480                 pixels = NULL;
2481         }
2482
2483         mymiplevel = savemiplevel;
2484         if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), false, false, false, &mymiplevel)))
2485         {
2486                 skinframe->shirt = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_color.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2487 #ifndef USE_GLES2
2488                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->shirt)
2489                         R_SaveTextureDDSFile(skinframe->shirt, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2490 #endif
2491                 Mem_Free(pixels);
2492                 pixels = NULL;
2493         }
2494
2495         mymiplevel = savemiplevel;
2496         if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), false, false, false, &mymiplevel)))
2497         {
2498                 skinframe->reflect = R_LoadTexture2D (r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), image_width, image_height, pixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags & (gl_texturecompression_reflectmask.integer && gl_texturecompression.integer ? ~0 : ~TEXF_COMPRESS), mymiplevel, NULL);
2499 #ifndef USE_GLES2
2500                 if (r_savedds && qglGetCompressedTexImageARB && skinframe->reflect)
2501                         R_SaveTextureDDSFile(skinframe->reflect, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2502 #endif
2503                 Mem_Free(pixels);
2504                 pixels = NULL;
2505         }
2506
2507         if (basepixels)
2508                 Mem_Free(basepixels);
2509
2510         return skinframe;
2511 }
2512
2513 // this is only used by .spr32 sprites, HL .spr files, HL .bsp files
2514 skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height, qboolean sRGB)
2515 {
2516         int i;
2517         skinframe_t *skinframe;
2518         char vabuf[1024];
2519
2520         if (cls.state == ca_dedicated)
2521                 return NULL;
2522
2523         // if already loaded just return it, otherwise make a new skinframe
2524         skinframe = R_SkinFrame_Find(name, textureflags, width, height, (!(textureflags & TEXF_FORCE_RELOAD) && skindata) ? CRC_Block(skindata, width*height*4) : -1, true);
2525         if (skinframe->base)
2526                 return skinframe;
2527         textureflags &= ~TEXF_FORCE_RELOAD;
2528
2529         skinframe->stain = NULL;
2530         skinframe->merged = NULL;
2531         skinframe->base = NULL;
2532         skinframe->pants = NULL;
2533         skinframe->shirt = NULL;
2534         skinframe->nmap = NULL;
2535         skinframe->gloss = NULL;
2536         skinframe->glow = NULL;
2537         skinframe->fog = NULL;
2538         skinframe->reflect = NULL;
2539         skinframe->hasalpha = false;
2540
2541         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2542         if (!skindata)
2543                 return NULL;
2544
2545         if (developer_loading.integer)
2546                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2547
2548         if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0)
2549         {
2550                 unsigned char *a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2551                 unsigned char *b = a + width * height * 4;
2552                 Image_HeightmapToNormalmap_BGRA(skindata, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2553                 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), width, height, b, TEXTYPE_BGRA, (textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL);
2554                 Mem_Free(a);
2555         }
2556         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL);
2557         if (textureflags & TEXF_ALPHA)
2558         {
2559                 for (i = 3;i < width * height * 4;i += 4)
2560                 {
2561                         if (skindata[i] < 255)
2562                         {
2563                                 skinframe->hasalpha = true;
2564                                 break;
2565                         }
2566                 }
2567                 if (r_loadfog && skinframe->hasalpha)
2568                 {
2569                         unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
2570                         memcpy(fogpixels, skindata, width * height * 4);
2571                         for (i = 0;i < width * height * 4;i += 4)
2572                                 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
2573                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, textureflags, -1, NULL);
2574                         Mem_Free(fogpixels);
2575                 }
2576         }
2577
2578         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]);
2579         //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2580
2581         return skinframe;
2582 }
2583
2584 skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height)
2585 {
2586         int i;
2587         int featuresmask;
2588         skinframe_t *skinframe;
2589
2590         if (cls.state == ca_dedicated)
2591                 return NULL;
2592
2593         // if already loaded just return it, otherwise make a new skinframe
2594         skinframe = R_SkinFrame_Find(name, textureflags, width, height, (!(textureflags & TEXF_FORCE_RELOAD) && skindata) ? CRC_Block(skindata, width*height) : -1, true);
2595         if (skinframe->base)
2596                 return skinframe;
2597         //textureflags &= ~TEXF_FORCE_RELOAD;
2598
2599         skinframe->stain = NULL;
2600         skinframe->merged = NULL;
2601         skinframe->base = NULL;
2602         skinframe->pants = NULL;
2603         skinframe->shirt = NULL;
2604         skinframe->nmap = NULL;
2605         skinframe->gloss = NULL;
2606         skinframe->glow = NULL;
2607         skinframe->fog = NULL;
2608         skinframe->reflect = NULL;
2609         skinframe->hasalpha = false;
2610
2611         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2612         if (!skindata)
2613                 return NULL;
2614
2615         if (developer_loading.integer)
2616                 Con_Printf("loading quake skin \"%s\"\n", name);
2617
2618         // we actually don't upload anything until the first use, because mdl skins frequently go unused, and are almost never used in both modes (colormapped and non-colormapped)
2619         skinframe->qpixels = (unsigned char *)Mem_Alloc(r_main_mempool, width*height); // FIXME LEAK
2620         memcpy(skinframe->qpixels, skindata, width*height);
2621         skinframe->qwidth = width;
2622         skinframe->qheight = height;
2623
2624         featuresmask = 0;
2625         for (i = 0;i < width * height;i++)
2626                 featuresmask |= palette_featureflags[skindata[i]];
2627
2628         skinframe->hasalpha = false;
2629         // fence textures
2630         if (name[0] == '{')
2631                 skinframe->hasalpha = true;
2632         skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT));
2633         skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0;
2634         skinframe->qgeneratemerged = true;
2635         skinframe->qgeneratebase = skinframe->qhascolormapping;
2636         skinframe->qgenerateglow = loadglowtexture && (featuresmask & PALETTEFEATURE_GLOW);
2637
2638         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette_bgra_complete)[skindata[pix]*4 + comp]);
2639         //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2640
2641         return skinframe;
2642 }
2643
2644 static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qboolean colormapped)
2645 {
2646         int width;
2647         int height;
2648         unsigned char *skindata;
2649         char vabuf[1024];
2650
2651         if (!skinframe->qpixels)
2652                 return;
2653
2654         if (!skinframe->qhascolormapping)
2655                 colormapped = false;
2656
2657         if (colormapped)
2658         {
2659                 if (!skinframe->qgeneratebase)
2660                         return;
2661         }
2662         else
2663         {
2664                 if (!skinframe->qgeneratemerged)
2665                         return;
2666         }
2667
2668         width = skinframe->qwidth;
2669         height = skinframe->qheight;
2670         skindata = skinframe->qpixels;
2671
2672         if (skinframe->qgeneratenmap)
2673         {
2674                 unsigned char *a, *b;
2675                 skinframe->qgeneratenmap = false;
2676                 a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2677                 b = a + width * height * 4;
2678                 // use either a custom palette or the quake palette
2679                 Image_Copy8bitBGRA(skindata, a, width * height, palette_bgra_complete);
2680                 Image_HeightmapToNormalmap_BGRA(a, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2681                 skinframe->nmap = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nmap", skinframe->basename), width, height, b, TEXTYPE_BGRA, (skinframe->textureflags | TEXF_ALPHA) & (r_mipnormalmaps.integer ? ~0 : ~TEXF_MIPMAP), -1, NULL);
2682                 Mem_Free(a);
2683         }
2684
2685         if (skinframe->qgenerateglow)
2686         {
2687                 skinframe->qgenerateglow = false;
2688                 if (skinframe->hasalpha) // fence textures
2689                         skinframe->glow = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags | TEXF_ALPHA, -1, palette_bgra_onlyfullbrights_transparent); // glow
2690                 else
2691                         skinframe->glow = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_glow", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_onlyfullbrights); // glow
2692         }
2693
2694         if (colormapped)
2695         {
2696                 skinframe->qgeneratebase = false;
2697                 skinframe->base  = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_nospecial", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, skinframe->glow ? palette_bgra_nocolormapnofullbrights : palette_bgra_nocolormap);
2698                 skinframe->pants = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_pantsaswhite);
2699                 skinframe->shirt = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, palette_bgra_shirtaswhite);
2700         }
2701         else
2702         {
2703                 skinframe->qgeneratemerged = false;
2704                 if (skinframe->hasalpha) // fence textures
2705                         skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags | TEXF_ALPHA, -1, skinframe->glow ? palette_bgra_nofullbrights_transparent : palette_bgra_transparent);
2706                 else
2707                         skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, vid.sRGB3D ? TEXTYPE_SRGB_PALETTE : TEXTYPE_PALETTE, skinframe->textureflags, -1, skinframe->glow ? palette_bgra_nofullbrights : palette_bgra_complete);
2708         }
2709
2710         if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase)
2711         {
2712                 Mem_Free(skinframe->qpixels);
2713                 skinframe->qpixels = NULL;
2714         }
2715 }
2716
2717 skinframe_t *R_SkinFrame_LoadInternal8bit(const char *name, int textureflags, const unsigned char *skindata, int width, int height, const unsigned int *palette, const unsigned int *alphapalette)
2718 {
2719         int i;
2720         skinframe_t *skinframe;
2721         char vabuf[1024];
2722
2723         if (cls.state == ca_dedicated)
2724                 return NULL;
2725
2726         // if already loaded just return it, otherwise make a new skinframe
2727         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2728         if (skinframe->base)
2729                 return skinframe;
2730         textureflags &= ~TEXF_FORCE_RELOAD;
2731
2732         skinframe->stain = NULL;
2733         skinframe->merged = NULL;
2734         skinframe->base = NULL;
2735         skinframe->pants = NULL;
2736         skinframe->shirt = NULL;
2737         skinframe->nmap = NULL;
2738         skinframe->gloss = NULL;
2739         skinframe->glow = NULL;
2740         skinframe->fog = NULL;
2741         skinframe->reflect = NULL;
2742         skinframe->hasalpha = false;
2743
2744         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2745         if (!skindata)
2746                 return NULL;
2747
2748         if (developer_loading.integer)
2749                 Con_Printf("loading embedded 8bit image \"%s\"\n", name);
2750
2751         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, palette);
2752         if ((textureflags & TEXF_ALPHA) && alphapalette)
2753         {
2754                 for (i = 0;i < width * height;i++)
2755                 {
2756                         if (((unsigned char *)palette)[skindata[i]*4+3] < 255)
2757                         {
2758                                 skinframe->hasalpha = true;
2759                                 break;
2760                         }
2761                 }
2762                 if (r_loadfog && skinframe->hasalpha)
2763                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, alphapalette);
2764         }
2765
2766         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
2767         //Con_Printf("Texture %s has average colors %f %f %f alpha %f\n", name, skinframe->avgcolor[0], skinframe->avgcolor[1], skinframe->avgcolor[2], skinframe->avgcolor[3]);
2768
2769         return skinframe;
2770 }
2771
2772 skinframe_t *R_SkinFrame_LoadMissing(void)
2773 {
2774         skinframe_t *skinframe;
2775
2776         if (cls.state == ca_dedicated)
2777                 return NULL;
2778
2779         skinframe = R_SkinFrame_Find("missing", TEXF_FORCENEAREST, 0, 0, 0, true);
2780         skinframe->stain = NULL;
2781         skinframe->merged = NULL;
2782         skinframe->base = NULL;
2783         skinframe->pants = NULL;
2784         skinframe->shirt = NULL;
2785         skinframe->nmap = NULL;
2786         skinframe->gloss = NULL;
2787         skinframe->glow = NULL;
2788         skinframe->fog = NULL;
2789         skinframe->reflect = NULL;
2790         skinframe->hasalpha = false;
2791
2792         skinframe->avgcolor[0] = rand() / RAND_MAX;
2793         skinframe->avgcolor[1] = rand() / RAND_MAX;
2794         skinframe->avgcolor[2] = rand() / RAND_MAX;
2795         skinframe->avgcolor[3] = 1;
2796
2797         return skinframe;
2798 }
2799
2800 skinframe_t *R_SkinFrame_LoadNoTexture(void)
2801 {
2802         int x, y;
2803         static unsigned char pix[16][16][4];
2804
2805         if (cls.state == ca_dedicated)
2806                 return NULL;
2807
2808         // this makes a light grey/dark grey checkerboard texture
2809         if (!pix[0][0][3])
2810         {
2811                 for (y = 0; y < 16; y++)
2812                 {
2813                         for (x = 0; x < 16; x++)
2814                         {
2815                                 if ((y < 8) ^ (x < 8))
2816                                 {
2817                                         pix[y][x][0] = 128;
2818                                         pix[y][x][1] = 128;
2819                                         pix[y][x][2] = 128;
2820                                         pix[y][x][3] = 255;
2821                                 }
2822                                 else
2823                                 {
2824                                         pix[y][x][0] = 64;
2825                                         pix[y][x][1] = 64;
2826                                         pix[y][x][2] = 64;
2827                                         pix[y][x][3] = 255;
2828                                 }
2829                         }
2830                 }
2831         }
2832
2833         return R_SkinFrame_LoadInternalBGRA("notexture", TEXF_FORCENEAREST, pix[0][0], 16, 16, false);
2834 }
2835
2836 skinframe_t *R_SkinFrame_LoadInternalUsingTexture(const char *name, int textureflags, rtexture_t *tex, int width, int height, qboolean sRGB)
2837 {
2838         skinframe_t *skinframe;
2839         if (cls.state == ca_dedicated)
2840                 return NULL;
2841         // if already loaded just return it, otherwise make a new skinframe
2842         skinframe = R_SkinFrame_Find(name, textureflags, width, height, (textureflags & TEXF_FORCE_RELOAD) ? -1 : 0, true);
2843         if (skinframe->base)
2844                 return skinframe;
2845         textureflags &= ~TEXF_FORCE_RELOAD;
2846         skinframe->stain = NULL;
2847         skinframe->merged = NULL;
2848         skinframe->base = NULL;
2849         skinframe->pants = NULL;
2850         skinframe->shirt = NULL;
2851         skinframe->nmap = NULL;
2852         skinframe->gloss = NULL;
2853         skinframe->glow = NULL;
2854         skinframe->fog = NULL;
2855         skinframe->reflect = NULL;
2856         skinframe->hasalpha = (textureflags & TEXF_ALPHA) != 0;
2857         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2858         if (!tex)
2859                 return NULL;
2860         if (developer_loading.integer)
2861                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2862         skinframe->base = skinframe->merged = tex;
2863         Vector4Set(skinframe->avgcolor, 1, 1, 1, 1); // bogus placeholder
2864         return skinframe;
2865 }
2866
2867 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2868 typedef struct suffixinfo_s
2869 {
2870         const char *suffix;
2871         qboolean flipx, flipy, flipdiagonal;
2872 }
2873 suffixinfo_t;
2874 static suffixinfo_t suffix[3][6] =
2875 {
2876         {
2877                 {"px",   false, false, false},
2878                 {"nx",   false, false, false},
2879                 {"py",   false, false, false},
2880                 {"ny",   false, false, false},
2881                 {"pz",   false, false, false},
2882                 {"nz",   false, false, false}
2883         },
2884         {
2885                 {"posx", false, false, false},
2886                 {"negx", false, false, false},
2887                 {"posy", false, false, false},
2888                 {"negy", false, false, false},
2889                 {"posz", false, false, false},
2890                 {"negz", false, false, false}
2891         },
2892         {
2893                 {"rt",    true, false,  true},
2894                 {"lf",   false,  true,  true},
2895                 {"ft",    true,  true, false},
2896                 {"bk",   false, false, false},
2897                 {"up",    true, false,  true},
2898                 {"dn",    true, false,  true}
2899         }
2900 };
2901
2902 static int componentorder[4] = {0, 1, 2, 3};
2903
2904 static rtexture_t *R_LoadCubemap(const char *basename)
2905 {
2906         int i, j, cubemapsize;
2907         unsigned char *cubemappixels, *image_buffer;
2908         rtexture_t *cubemaptexture;
2909         char name[256];
2910         // must start 0 so the first loadimagepixels has no requested width/height
2911         cubemapsize = 0;
2912         cubemappixels = NULL;
2913         cubemaptexture = NULL;
2914         // keep trying different suffix groups (posx, px, rt) until one loads
2915         for (j = 0;j < 3 && !cubemappixels;j++)
2916         {
2917                 // load the 6 images in the suffix group
2918                 for (i = 0;i < 6;i++)
2919                 {
2920                         // generate an image name based on the base and and suffix
2921                         dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2922                         // load it
2923                         if ((image_buffer = loadimagepixelsbgra(name, false, false, false, NULL)))
2924                         {
2925                                 // an image loaded, make sure width and height are equal
2926                                 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
2927                                 {
2928                                         // if this is the first image to load successfully, allocate the cubemap memory
2929                                         if (!cubemappixels && image_width >= 1)
2930                                         {
2931                                                 cubemapsize = image_width;
2932                                                 // note this clears to black, so unavailable sides are black
2933                                                 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2934                                         }
2935                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2936                                         if (cubemappixels)
2937                                                 Image_CopyMux(cubemappixels+i*cubemapsize*cubemapsize*4, image_buffer, cubemapsize, cubemapsize, suffix[j][i].flipx, suffix[j][i].flipy, suffix[j][i].flipdiagonal, 4, 4, componentorder);
2938                                 }
2939                                 else
2940                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2941                                 // free the image
2942                                 Mem_Free(image_buffer);
2943                         }
2944                 }
2945         }
2946         // if a cubemap loaded, upload it
2947         if (cubemappixels)
2948         {
2949                 if (developer_loading.integer)
2950                         Con_Printf("loading cubemap \"%s\"\n", basename);
2951
2952                 cubemaptexture = R_LoadTextureCubeMap(r_main_texturepool, basename, cubemapsize, cubemappixels, vid.sRGB3D ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, (gl_texturecompression_lightcubemaps.integer && gl_texturecompression.integer ? TEXF_COMPRESS : 0) | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
2953                 Mem_Free(cubemappixels);
2954         }
2955         else
2956         {
2957                 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
2958                 if (developer_loading.integer)
2959                 {
2960                         Con_Printf("(tried tried images ");
2961                         for (j = 0;j < 3;j++)
2962                                 for (i = 0;i < 6;i++)
2963                                         Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2964                         Con_Print(" and was unable to find any of them).\n");
2965                 }
2966         }
2967         return cubemaptexture;
2968 }
2969
2970 rtexture_t *R_GetCubemap(const char *basename)
2971 {
2972         int i;
2973         for (i = 0;i < r_texture_numcubemaps;i++)
2974                 if (r_texture_cubemaps[i] != NULL)
2975                         if (!strcasecmp(r_texture_cubemaps[i]->basename, basename))
2976                                 return r_texture_cubemaps[i]->texture ? r_texture_cubemaps[i]->texture : r_texture_whitecube;
2977         if (i >= MAX_CUBEMAPS || !r_main_mempool)
2978                 return r_texture_whitecube;
2979         r_texture_numcubemaps++;
2980         r_texture_cubemaps[i] = (cubemapinfo_t *)Mem_Alloc(r_main_mempool, sizeof(cubemapinfo_t));
2981         strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename));
2982         r_texture_cubemaps[i]->texture = R_LoadCubemap(r_texture_cubemaps[i]->basename);
2983         return r_texture_cubemaps[i]->texture;
2984 }
2985
2986 static void R_Main_FreeViewCache(void)
2987 {
2988         if (r_refdef.viewcache.entityvisible)
2989                 Mem_Free(r_refdef.viewcache.entityvisible);
2990         if (r_refdef.viewcache.world_pvsbits)
2991                 Mem_Free(r_refdef.viewcache.world_pvsbits);
2992         if (r_refdef.viewcache.world_leafvisible)
2993                 Mem_Free(r_refdef.viewcache.world_leafvisible);
2994         if (r_refdef.viewcache.world_surfacevisible)
2995                 Mem_Free(r_refdef.viewcache.world_surfacevisible);
2996         memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache));
2997 }
2998
2999 static void R_Main_ResizeViewCache(void)
3000 {
3001         int numentities = r_refdef.scene.numentities;
3002         int numclusters = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusters : 1;
3003         int numclusterbytes = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusterbytes : 1;
3004         int numleafs = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_leafs : 1;
3005         int numsurfaces = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->num_surfaces : 1;
3006         if (r_refdef.viewcache.maxentities < numentities)
3007         {
3008                 r_refdef.viewcache.maxentities = numentities;
3009                 if (r_refdef.viewcache.entityvisible)
3010                         Mem_Free(r_refdef.viewcache.entityvisible);
3011                 r_refdef.viewcache.entityvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.maxentities);
3012         }
3013         if (r_refdef.viewcache.world_numclusters != numclusters)
3014         {
3015                 r_refdef.viewcache.world_numclusters = numclusters;
3016                 r_refdef.viewcache.world_numclusterbytes = numclusterbytes;
3017                 if (r_refdef.viewcache.world_pvsbits)
3018                         Mem_Free(r_refdef.viewcache.world_pvsbits);
3019                 r_refdef.viewcache.world_pvsbits = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numclusterbytes);
3020         }
3021         if (r_refdef.viewcache.world_numleafs != numleafs)
3022         {
3023                 r_refdef.viewcache.world_numleafs = numleafs;
3024                 if (r_refdef.viewcache.world_leafvisible)
3025                         Mem_Free(r_refdef.viewcache.world_leafvisible);
3026                 r_refdef.viewcache.world_leafvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numleafs);
3027         }
3028         if (r_refdef.viewcache.world_numsurfaces != numsurfaces)
3029         {
3030                 r_refdef.viewcache.world_numsurfaces = numsurfaces;
3031                 if (r_refdef.viewcache.world_surfacevisible)
3032                         Mem_Free(r_refdef.viewcache.world_surfacevisible);
3033                 r_refdef.viewcache.world_surfacevisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numsurfaces);
3034         }
3035 }
3036
3037 extern rtexture_t *loadingscreentexture;
3038 static void gl_main_start(void)
3039 {
3040         loadingscreentexture = NULL;
3041         r_texture_blanknormalmap = NULL;
3042         r_texture_white = NULL;
3043         r_texture_grey128 = NULL;
3044         r_texture_black = NULL;
3045         r_texture_whitecube = NULL;
3046         r_texture_normalizationcube = NULL;
3047         r_texture_fogattenuation = NULL;
3048         r_texture_fogheighttexture = NULL;
3049         r_texture_gammaramps = NULL;
3050         r_texture_numcubemaps = 0;
3051         r_uniformbufferalignment = 32;
3052
3053         r_loaddds = r_texture_dds_load.integer != 0;
3054         r_savedds = vid.support.arb_texture_compression && vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer;
3055
3056         switch(vid.renderpath)
3057         {
3058         case RENDERPATH_GL20:
3059         case RENDERPATH_GLES2:
3060                 Cvar_SetValueQuick(&r_textureunits, vid.texunits);
3061                 Cvar_SetValueQuick(&gl_combine, 1);
3062                 Cvar_SetValueQuick(&r_glsl, 1);
3063                 r_loadnormalmap = true;
3064                 r_loadgloss = true;
3065                 r_loadfog = false;
3066 #ifdef GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
3067                 if (vid.support.arb_uniform_buffer_object)
3068                         qglGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &r_uniformbufferalignment);
3069 #endif
3070                         break;
3071         }
3072
3073         R_AnimCache_Free();
3074         R_FrameData_Reset();
3075         R_BufferData_Reset();
3076
3077         r_numqueries = 0;
3078         r_maxqueries = 0;
3079         memset(r_queries, 0, sizeof(r_queries));
3080
3081         r_qwskincache = NULL;
3082         r_qwskincache_size = 0;
3083
3084         // due to caching of texture_t references, the collision cache must be reset
3085         Collision_Cache_Reset(true);
3086
3087         // set up r_skinframe loading system for textures
3088         memset(&r_skinframe, 0, sizeof(r_skinframe));
3089         r_skinframe.loadsequence = 1;
3090         Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
3091
3092         r_main_texturepool = R_AllocTexturePool();
3093         R_BuildBlankTextures();
3094         R_BuildNoTexture();
3095         if (vid.support.arb_texture_cube_map)
3096         {
3097                 R_BuildWhiteCube();
3098                 R_BuildNormalizationCube();
3099         }
3100         r_texture_fogattenuation = NULL;
3101         r_texture_fogheighttexture = NULL;
3102         r_texture_gammaramps = NULL;
3103         //r_texture_fogintensity = NULL;
3104         memset(&r_fb, 0, sizeof(r_fb));
3105         Mem_ExpandableArray_NewArray(&r_fb.rendertargets, r_main_mempool, sizeof(r_rendertarget_t), 128);
3106         r_glsl_permutation = NULL;
3107         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3108         Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256);
3109         memset(&r_svbsp, 0, sizeof (r_svbsp));
3110
3111         memset(r_texture_cubemaps, 0, sizeof(r_texture_cubemaps));
3112         r_texture_numcubemaps = 0;
3113
3114         r_refdef.fogmasktable_density = 0;
3115
3116 #ifdef __ANDROID__
3117         // For Steelstorm Android
3118         // FIXME CACHE the program and reload
3119         // FIXME see possible combinations for SS:BR android
3120         Con_DPrintf("Compiling most used shaders for SS:BR android... START\n");
3121         R_SetupShader_SetPermutationGLSL(0, 12);
3122         R_SetupShader_SetPermutationGLSL(0, 13);
3123         R_SetupShader_SetPermutationGLSL(0, 8388621);
3124         R_SetupShader_SetPermutationGLSL(3, 0);
3125         R_SetupShader_SetPermutationGLSL(3, 2048);
3126         R_SetupShader_SetPermutationGLSL(5, 0);
3127         R_SetupShader_SetPermutationGLSL(5, 2);
3128         R_SetupShader_SetPermutationGLSL(5, 2048);
3129         R_SetupShader_SetPermutationGLSL(5, 8388608);
3130         R_SetupShader_SetPermutationGLSL(11, 1);
3131         R_SetupShader_SetPermutationGLSL(11, 2049);
3132         R_SetupShader_SetPermutationGLSL(11, 8193);
3133         R_SetupShader_SetPermutationGLSL(11, 10241);
3134         Con_DPrintf("Compiling most used shaders for SS:BR android... END\n");
3135 #endif
3136 }
3137
3138 static void gl_main_shutdown(void)
3139 {
3140         R_RenderTarget_FreeUnused(true);
3141         Mem_ExpandableArray_FreeArray(&r_fb.rendertargets);
3142         R_AnimCache_Free();
3143         R_FrameData_Reset();
3144         R_BufferData_Reset();
3145
3146         R_Main_FreeViewCache();
3147
3148         switch(vid.renderpath)
3149         {
3150         case RENDERPATH_GL20:
3151         case RENDERPATH_GLES2:
3152 #if defined(GL_SAMPLES_PASSED_ARB) && !defined(USE_GLES2)
3153                 if (r_maxqueries)
3154                         qglDeleteQueriesARB(r_maxqueries, r_queries);
3155 #endif
3156                 break;
3157         }
3158
3159         r_numqueries = 0;
3160         r_maxqueries = 0;
3161         memset(r_queries, 0, sizeof(r_queries));
3162
3163         r_qwskincache = NULL;
3164         r_qwskincache_size = 0;
3165
3166         // clear out the r_skinframe state
3167         Mem_ExpandableArray_FreeArray(&r_skinframe.array);
3168         memset(&r_skinframe, 0, sizeof(r_skinframe));
3169
3170         if (r_svbsp.nodes)
3171                 Mem_Free(r_svbsp.nodes);
3172         memset(&r_svbsp, 0, sizeof (r_svbsp));
3173         R_FreeTexturePool(&r_main_texturepool);
3174         loadingscreentexture = NULL;
3175         r_texture_blanknormalmap = NULL;
3176         r_texture_white = NULL;
3177         r_texture_grey128 = NULL;
3178         r_texture_black = NULL;
3179         r_texture_whitecube = NULL;
3180         r_texture_normalizationcube = NULL;
3181         r_texture_fogattenuation = NULL;
3182         r_texture_fogheighttexture = NULL;
3183         r_texture_gammaramps = NULL;
3184         r_texture_numcubemaps = 0;
3185         //r_texture_fogintensity = NULL;
3186         memset(&r_fb, 0, sizeof(r_fb));
3187         R_GLSL_Restart_f();
3188
3189         r_glsl_permutation = NULL;
3190         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3191         Mem_ExpandableArray_FreeArray(&r_glsl_permutationarray);
3192 }
3193
3194 static void gl_main_newmap(void)
3195 {
3196         // FIXME: move this code to client
3197         char *entities, entname[MAX_QPATH];
3198         if (r_qwskincache)
3199                 Mem_Free(r_qwskincache);
3200         r_qwskincache = NULL;
3201         r_qwskincache_size = 0;
3202         if (cl.worldmodel)
3203         {
3204                 dpsnprintf(entname, sizeof(entname), "%s.ent", cl.worldnamenoextension);
3205                 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
3206                 {
3207                         CL_ParseEntityLump(entities);
3208                         Mem_Free(entities);
3209                         return;
3210                 }
3211                 if (cl.worldmodel->brush.entities)
3212                         CL_ParseEntityLump(cl.worldmodel->brush.entities);
3213         }
3214         R_Main_FreeViewCache();
3215
3216         R_FrameData_Reset();
3217         R_BufferData_Reset();
3218 }
3219
3220 void GL_Main_Init(void)
3221 {
3222         int i;
3223         r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
3224         R_InitShaderModeInfo();
3225
3226         Cmd_AddCommand("r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
3227         Cmd_AddCommand("r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
3228         // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
3229         if (gamemode == GAME_NEHAHRA)
3230         {
3231                 Cvar_RegisterVariable (&gl_fogenable);
3232                 Cvar_RegisterVariable (&gl_fogdensity);
3233                 Cvar_RegisterVariable (&gl_fogred);
3234                 Cvar_RegisterVariable (&gl_foggreen);
3235                 Cvar_RegisterVariable (&gl_fogblue);
3236                 Cvar_RegisterVariable (&gl_fogstart);
3237                 Cvar_RegisterVariable (&gl_fogend);
3238                 Cvar_RegisterVariable (&gl_skyclip);
3239         }
3240         Cvar_RegisterVariable(&r_motionblur);
3241         Cvar_RegisterVariable(&r_damageblur);
3242         Cvar_RegisterVariable(&r_motionblur_averaging);
3243         Cvar_RegisterVariable(&r_motionblur_randomize);
3244         Cvar_RegisterVariable(&r_motionblur_minblur);
3245         Cvar_RegisterVariable(&r_motionblur_maxblur);
3246         Cvar_RegisterVariable(&r_motionblur_velocityfactor);
3247         Cvar_RegisterVariable(&r_motionblur_velocityfactor_minspeed);
3248         Cvar_RegisterVariable(&r_motionblur_velocityfactor_maxspeed);
3249         Cvar_RegisterVariable(&r_motionblur_mousefactor);
3250         Cvar_RegisterVariable(&r_motionblur_mousefactor_minspeed);
3251         Cvar_RegisterVariable(&r_motionblur_mousefactor_maxspeed);
3252         Cvar_RegisterVariable(&r_equalize_entities_fullbright);
3253         Cvar_RegisterVariable(&r_equalize_entities_minambient);
3254         Cvar_RegisterVariable(&r_equalize_entities_by);
3255         Cvar_RegisterVariable(&r_equalize_entities_to);
3256         Cvar_RegisterVariable(&r_depthfirst);
3257         Cvar_RegisterVariable(&r_useinfinitefarclip);
3258         Cvar_RegisterVariable(&r_farclip_base);
3259         Cvar_RegisterVariable(&r_farclip_world);
3260         Cvar_RegisterVariable(&r_nearclip);
3261         Cvar_RegisterVariable(&r_deformvertexes);
3262         Cvar_RegisterVariable(&r_transparent);
3263         Cvar_RegisterVariable(&r_transparent_alphatocoverage);
3264         Cvar_RegisterVariable(&r_transparent_sortsurfacesbynearest);
3265         Cvar_RegisterVariable(&r_transparent_useplanardistance);
3266         Cvar_RegisterVariable(&r_showoverdraw);
3267         Cvar_RegisterVariable(&r_showbboxes);
3268         Cvar_RegisterVariable(&r_showbboxes_client);
3269         Cvar_RegisterVariable(&r_showsurfaces);
3270         Cvar_RegisterVariable(&r_showtris);
3271         Cvar_RegisterVariable(&r_shownormals);
3272         Cvar_RegisterVariable(&r_showlighting);
3273         Cvar_RegisterVariable(&r_showshadowvolumes);
3274         Cvar_RegisterVariable(&r_showcollisionbrushes);
3275         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
3276         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
3277         Cvar_RegisterVariable(&r_showdisabledepthtest);
3278         Cvar_RegisterVariable(&r_showspriteedges);
3279         Cvar_RegisterVariable(&r_showparticleedges);
3280         Cvar_RegisterVariable(&r_drawportals);
3281         Cvar_RegisterVariable(&r_drawentities);
3282         Cvar_RegisterVariable(&r_draw2d);
3283         Cvar_RegisterVariable(&r_drawworld);
3284         Cvar_RegisterVariable(&r_cullentities_trace);
3285         Cvar_RegisterVariable(&r_cullentities_trace_entityocclusion);
3286         Cvar_RegisterVariable(&r_cullentities_trace_samples);
3287         Cvar_RegisterVariable(&r_cullentities_trace_tempentitysamples);
3288         Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
3289         Cvar_RegisterVariable(&r_cullentities_trace_expand);
3290         Cvar_RegisterVariable(&r_cullentities_trace_pad);
3291         Cvar_RegisterVariable(&r_cullentities_trace_delay);
3292         Cvar_RegisterVariable(&r_cullentities_trace_eyejitter);
3293         Cvar_RegisterVariable(&r_sortentities);
3294         Cvar_RegisterVariable(&r_drawviewmodel);
3295         Cvar_RegisterVariable(&r_drawexteriormodel);
3296         Cvar_RegisterVariable(&r_speeds);
3297         Cvar_RegisterVariable(&r_fullbrights);
3298         Cvar_RegisterVariable(&r_wateralpha);
3299         Cvar_RegisterVariable(&r_dynamic);
3300         Cvar_RegisterVariable(&r_fakelight);
3301         Cvar_RegisterVariable(&r_fakelight_intensity);
3302         Cvar_RegisterVariable(&r_fullbright_directed);
3303         Cvar_RegisterVariable(&r_fullbright_directed_ambient);
3304         Cvar_RegisterVariable(&r_fullbright_directed_diffuse);
3305         Cvar_RegisterVariable(&r_fullbright_directed_pitch);
3306         Cvar_RegisterVariable(&r_fullbright_directed_pitch_relative);
3307         Cvar_RegisterVariable(&r_fullbright);
3308         Cvar_RegisterVariable(&r_shadows);
3309         Cvar_RegisterVariable(&r_shadows_darken);
3310         Cvar_RegisterVariable(&r_shadows_drawafterrtlighting);
3311         Cvar_RegisterVariable(&r_shadows_castfrombmodels);
3312         Cvar_RegisterVariable(&r_shadows_throwdistance);
3313         Cvar_RegisterVariable(&r_shadows_throwdirection);
3314         Cvar_RegisterVariable(&r_shadows_focus);
3315         Cvar_RegisterVariable(&r_shadows_shadowmapscale);
3316         Cvar_RegisterVariable(&r_shadows_shadowmapbias);
3317         Cvar_RegisterVariable(&r_q1bsp_skymasking);
3318         Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
3319         Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
3320         Cvar_RegisterVariable(&r_polygonoffset_decals_factor);
3321         Cvar_RegisterVariable(&r_polygonoffset_decals_offset);
3322         Cvar_RegisterVariable(&r_fog_exp2);
3323         Cvar_RegisterVariable(&r_fog_clear);
3324         Cvar_RegisterVariable(&r_drawfog);
3325         Cvar_RegisterVariable(&r_transparentdepthmasking);
3326         Cvar_RegisterVariable(&r_transparent_sortmindist);
3327         Cvar_RegisterVariable(&r_transparent_sortmaxdist);
3328         Cvar_RegisterVariable(&r_transparent_sortarraysize);
3329         Cvar_RegisterVariable(&r_texture_dds_load);
3330         Cvar_RegisterVariable(&r_texture_dds_save);
3331         Cvar_RegisterVariable(&r_textureunits);
3332         Cvar_RegisterVariable(&gl_combine);
3333         Cvar_RegisterVariable(&r_usedepthtextures);
3334         Cvar_RegisterVariable(&r_viewfbo);
3335         Cvar_RegisterVariable(&r_rendertarget_debug);
3336         Cvar_RegisterVariable(&r_viewscale);
3337         Cvar_RegisterVariable(&r_viewscale_fpsscaling);
3338         Cvar_RegisterVariable(&r_viewscale_fpsscaling_min);
3339         Cvar_RegisterVariable(&r_viewscale_fpsscaling_multiply);
3340         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepsize);
3341         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepmax);
3342         Cvar_RegisterVariable(&r_viewscale_fpsscaling_target);
3343         Cvar_RegisterVariable(&r_glsl);
3344         Cvar_RegisterVariable(&r_glsl_deluxemapping);
3345         Cvar_RegisterVariable(&r_glsl_offsetmapping);
3346         Cvar_RegisterVariable(&r_glsl_offsetmapping_steps);
3347         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
3348         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_steps);
3349         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_refinesteps);
3350         Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
3351         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod);
3352         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod_distance);
3353         Cvar_RegisterVariable(&r_glsl_postprocess);
3354         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1);
3355         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2);
3356         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3);
3357         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4);
3358         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1_enable);
3359         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2_enable);
3360         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3_enable);
3361         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable);
3362         Cvar_RegisterVariable(&r_celshading);
3363         Cvar_RegisterVariable(&r_celoutlines);
3364
3365         Cvar_RegisterVariable(&r_water);
3366         Cvar_RegisterVariable(&r_water_cameraentitiesonly);
3367         Cvar_RegisterVariable(&r_water_resolutionmultiplier);
3368         Cvar_RegisterVariable(&r_water_clippingplanebias);
3369         Cvar_RegisterVariable(&r_water_refractdistort);
3370         Cvar_RegisterVariable(&r_water_reflectdistort);
3371         Cvar_RegisterVariable(&r_water_scissormode);
3372         Cvar_RegisterVariable(&r_water_lowquality);
3373         Cvar_RegisterVariable(&r_water_hideplayer);
3374
3375         Cvar_RegisterVariable(&r_lerpsprites);
3376         Cvar_RegisterVariable(&r_lerpmodels);
3377         Cvar_RegisterVariable(&r_lerplightstyles);
3378         Cvar_RegisterVariable(&r_waterscroll);
3379         Cvar_RegisterVariable(&r_bloom);
3380         Cvar_RegisterVariable(&r_bloom_colorscale);
3381         Cvar_RegisterVariable(&r_bloom_brighten);
3382         Cvar_RegisterVariable(&r_bloom_blur);
3383         Cvar_RegisterVariable(&r_bloom_resolution);
3384         Cvar_RegisterVariable(&r_bloom_colorexponent);
3385         Cvar_RegisterVariable(&r_bloom_colorsubtract);
3386         Cvar_RegisterVariable(&r_bloom_scenebrightness);
3387         Cvar_RegisterVariable(&r_hdr_scenebrightness);
3388         Cvar_RegisterVariable(&r_hdr_glowintensity);
3389         Cvar_RegisterVariable(&r_hdr_irisadaptation);
3390         Cvar_RegisterVariable(&r_hdr_irisadaptation_multiplier);
3391         Cvar_RegisterVariable(&r_hdr_irisadaptation_minvalue);
3392         Cvar_RegisterVariable(&r_hdr_irisadaptation_maxvalue);
3393         Cvar_RegisterVariable(&r_hdr_irisadaptation_value);
3394         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_up);
3395         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_down);
3396         Cvar_RegisterVariable(&r_hdr_irisadaptation_radius);
3397         Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
3398         Cvar_RegisterVariable(&developer_texturelogging);
3399         Cvar_RegisterVariable(&gl_lightmaps);
3400         Cvar_RegisterVariable(&r_test);
3401         Cvar_RegisterVariable(&r_batch_multidraw);
3402         Cvar_RegisterVariable(&r_batch_multidraw_mintriangles);
3403         Cvar_RegisterVariable(&r_batch_debugdynamicvertexpath);
3404         Cvar_RegisterVariable(&r_glsl_skeletal);
3405         Cvar_RegisterVariable(&r_glsl_saturation);
3406         Cvar_RegisterVariable(&r_glsl_saturation_redcompensate);
3407         Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas);
3408         Cvar_RegisterVariable(&r_framedatasize);
3409         for (i = 0;i < R_BUFFERDATA_COUNT;i++)
3410                 Cvar_RegisterVariable(&r_buffermegs[i]);
3411         Cvar_RegisterVariable(&r_batch_dynamicbuffer);
3412         if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
3413                 Cvar_SetValue("r_fullbrights", 0);
3414 #ifdef DP_MOBILETOUCH
3415         // GLES devices have terrible depth precision in general, so...
3416         Cvar_SetValueQuick(&r_nearclip, 4);
3417         Cvar_SetValueQuick(&r_farclip_base, 4096);
3418         Cvar_SetValueQuick(&r_farclip_world, 0);
3419         Cvar_SetValueQuick(&r_useinfinitefarclip, 0);
3420 #endif
3421         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
3422 }
3423
3424 void Render_Init(void)
3425 {
3426         gl_backend_init();
3427         R_Textures_Init();
3428         GL_Main_Init();
3429         Font_Init();
3430         GL_Draw_Init();
3431         R_Shadow_Init();
3432         R_Sky_Init();
3433         GL_Surf_Init();
3434         Sbar_Init();
3435         R_Particles_Init();
3436         R_Explosion_Init();
3437         R_LightningBeams_Init();
3438         Mod_RenderInit();
3439 }
3440
3441 /*
3442 ===============
3443 GL_Init
3444 ===============
3445 */
3446 #ifndef USE_GLES2
3447 extern char *ENGINE_EXTENSIONS;
3448 void GL_Init (void)
3449 {
3450         gl_renderer = (const char *)qglGetString(GL_RENDERER);
3451         gl_vendor = (const char *)qglGetString(GL_VENDOR);
3452         gl_version = (const char *)qglGetString(GL_VERSION);
3453         gl_extensions = (const char *)qglGetString(GL_EXTENSIONS);
3454
3455         if (!gl_extensions)
3456                 gl_extensions = "";
3457         if (!gl_platformextensions)
3458                 gl_platformextensions = "";
3459
3460         Con_Printf("GL_VENDOR: %s\n", gl_vendor);
3461         Con_Printf("GL_RENDERER: %s\n", gl_renderer);
3462         Con_Printf("GL_VERSION: %s\n", gl_version);
3463         Con_DPrintf("GL_EXTENSIONS: %s\n", gl_extensions);
3464         Con_DPrintf("%s_EXTENSIONS: %s\n", gl_platform, gl_platformextensions);
3465
3466         VID_CheckExtensions();
3467
3468         // LordHavoc: report supported extensions
3469 #ifdef CONFIG_MENU
3470         Con_DPrintf("\nQuakeC extensions for server and client: %s\nQuakeC extensions for menu: %s\n", vm_sv_extensions, vm_m_extensions );
3471 #else
3472         Con_DPrintf("\nQuakeC extensions for server and client: %s\n", vm_sv_extensions );
3473 #endif
3474
3475         // clear to black (loading plaque will be seen over this)
3476         GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 128);
3477 }
3478 #endif
3479
3480 int R_CullBox(const vec3_t mins, const vec3_t maxs)
3481 {
3482         int i;
3483         mplane_t *p;
3484         if (r_trippy.integer)
3485                 return false;
3486         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
3487         {
3488                 p = r_refdef.view.frustum + i;
3489                 switch(p->signbits)
3490                 {
3491                 default:
3492                 case 0:
3493                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3494                                 return true;
3495                         break;
3496                 case 1:
3497                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3498                                 return true;
3499                         break;
3500                 case 2:
3501                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3502                                 return true;
3503                         break;
3504                 case 3:
3505                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3506                                 return true;
3507                         break;
3508                 case 4:
3509                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3510                                 return true;
3511                         break;
3512                 case 5:
3513                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3514                                 return true;
3515                         break;
3516                 case 6:
3517                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3518                                 return true;
3519                         break;
3520                 case 7:
3521                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3522                                 return true;
3523                         break;
3524                 }
3525         }
3526         return false;
3527 }
3528
3529 int R_CullBoxCustomPlanes(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
3530 {
3531         int i;
3532         const mplane_t *p;
3533         if (r_trippy.integer)
3534                 return false;
3535         for (i = 0;i < numplanes;i++)
3536         {
3537                 p = planes + i;
3538                 switch(p->signbits)
3539                 {
3540                 default:
3541                 case 0:
3542                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3543                                 return true;
3544                         break;
3545                 case 1:
3546                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*maxs[2] < p->dist)
3547                                 return true;
3548                         break;
3549                 case 2:
3550                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3551                                 return true;
3552                         break;
3553                 case 3:
3554                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*maxs[2] < p->dist)
3555                                 return true;
3556                         break;
3557                 case 4:
3558                         if (p->normal[0]*maxs[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3559                                 return true;
3560                         break;
3561                 case 5:
3562                         if (p->normal[0]*mins[0] + p->normal[1]*maxs[1] + p->normal[2]*mins[2] < p->dist)
3563                                 return true;
3564                         break;
3565                 case 6:
3566                         if (p->normal[0]*maxs[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3567                                 return true;
3568                         break;
3569                 case 7:
3570                         if (p->normal[0]*mins[0] + p->normal[1]*mins[1] + p->normal[2]*mins[2] < p->dist)
3571                                 return true;
3572                         break;
3573                 }
3574         }
3575         return false;
3576 }
3577
3578 //==================================================================================
3579
3580 // LordHavoc: this stores temporary data used within the same frame
3581
3582 typedef struct r_framedata_mem_s
3583 {
3584         struct r_framedata_mem_s *purge; // older mem block to free on next frame
3585         size_t size; // how much usable space
3586         size_t current; // how much space in use
3587         size_t mark; // last "mark" location, temporary memory can be freed by returning to this
3588         size_t wantedsize; // how much space was allocated
3589         unsigned char *data; // start of real data (16byte aligned)
3590 }
3591 r_framedata_mem_t;
3592
3593 static r_framedata_mem_t *r_framedata_mem;
3594
3595 void R_FrameData_Reset(void)
3596 {
3597         while (r_framedata_mem)
3598         {
3599                 r_framedata_mem_t *next = r_framedata_mem->purge;
3600                 Mem_Free(r_framedata_mem);
3601                 r_framedata_mem = next;
3602         }
3603 }
3604
3605 static void R_FrameData_Resize(qboolean mustgrow)
3606 {
3607         size_t wantedsize;
3608         wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
3609         wantedsize = bound(65536, wantedsize, 1000*1024*1024);
3610         if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize || mustgrow)
3611         {
3612                 r_framedata_mem_t *newmem = (r_framedata_mem_t *)Mem_Alloc(r_main_mempool, wantedsize);
3613                 newmem->wantedsize = wantedsize;
3614                 newmem->data = (unsigned char *)(((size_t)(newmem+1) + 15) & ~15);
3615                 newmem->size = (unsigned char *)newmem + wantedsize - newmem->data;
3616                 newmem->current = 0;
3617                 newmem->mark = 0;
3618                 newmem->purge = r_framedata_mem;
3619                 r_framedata_mem = newmem;
3620         }
3621 }
3622
3623 void R_FrameData_NewFrame(void)
3624 {
3625         R_FrameData_Resize(false);
3626         if (!r_framedata_mem)
3627                 return;
3628         // if we ran out of space on the last frame, free the old memory now
3629         while (r_framedata_mem->purge)
3630         {
3631                 // repeatedly remove the second item in the list, leaving only head
3632                 r_framedata_mem_t *next = r_framedata_mem->purge->purge;
3633                 Mem_Free(r_framedata_mem->purge);
3634                 r_framedata_mem->purge = next;
3635         }
3636         // reset the current mem pointer
3637         r_framedata_mem->current = 0;
3638         r_framedata_mem->mark = 0;
3639 }
3640
3641 void *R_FrameData_Alloc(size_t size)
3642 {
3643         void *data;
3644         float newvalue;
3645
3646         // align to 16 byte boundary - the data pointer is already aligned, so we
3647         // only need to ensure the size of every allocation is also aligned
3648         size = (size + 15) & ~15;
3649
3650         while (!r_framedata_mem || r_framedata_mem->current + size > r_framedata_mem->size)
3651         {
3652                 // emergency - we ran out of space, allocate more memory
3653                 // note: this has no upper-bound, we'll fail to allocate memory eventually and just die
3654                 newvalue = r_framedatasize.value * 2.0f;
3655                 // upper bound based on architecture - if we try to allocate more than this we could overflow, better to loop until we error out on allocation failure
3656                 if (sizeof(size_t) >= 8)
3657                         newvalue = bound(0.25f, newvalue, (float)(1ll << 42));
3658                 else
3659                         newvalue = bound(0.25f, newvalue, (float)(1 << 10));
3660                 // this might not be a growing it, but we'll allocate another buffer every time
3661                 Cvar_SetValueQuick(&r_framedatasize, newvalue);
3662                 R_FrameData_Resize(true);
3663         }
3664
3665         data = r_framedata_mem->data + r_framedata_mem->current;
3666         r_framedata_mem->current += size;
3667
3668         // count the usage for stats
3669         r_refdef.stats[r_stat_framedatacurrent] = max(r_refdef.stats[r_stat_framedatacurrent], (int)r_framedata_mem->current);
3670         r_refdef.stats[r_stat_framedatasize] = max(r_refdef.stats[r_stat_framedatasize], (int)r_framedata_mem->size);
3671
3672         return (void *)data;
3673 }
3674
3675 void *R_FrameData_Store(size_t size, void *data)
3676 {
3677         void *d = R_FrameData_Alloc(size);
3678         if (d && data)
3679                 memcpy(d, data, size);
3680         return d;
3681 }
3682
3683 void R_FrameData_SetMark(void)
3684 {
3685         if (!r_framedata_mem)
3686                 return;
3687         r_framedata_mem->mark = r_framedata_mem->current;
3688 }
3689
3690 void R_FrameData_ReturnToMark(void)
3691 {
3692         if (!r_framedata_mem)
3693                 return;
3694         r_framedata_mem->current = r_framedata_mem->mark;
3695 }
3696
3697 //==================================================================================
3698
3699 // avoid reusing the same buffer objects on consecutive frames
3700 #define R_BUFFERDATA_CYCLE 3
3701
3702 typedef struct r_bufferdata_buffer_s
3703 {
3704         struct r_bufferdata_buffer_s *purge; // older buffer to free on next frame
3705         size_t size; // how much usable space
3706         size_t current; // how much space in use
3707         r_meshbuffer_t *buffer; // the buffer itself
3708 }
3709 r_bufferdata_buffer_t;
3710
3711 static int r_bufferdata_cycle = 0; // incremented and wrapped each frame
3712 static r_bufferdata_buffer_t *r_bufferdata_buffer[R_BUFFERDATA_CYCLE][R_BUFFERDATA_COUNT];
3713
3714 /// frees all dynamic buffers
3715 void R_BufferData_Reset(void)
3716 {
3717         int cycle, type;
3718         r_bufferdata_buffer_t **p, *mem;
3719         for (cycle = 0;cycle < R_BUFFERDATA_CYCLE;cycle++)
3720         {
3721                 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3722                 {
3723                         // free all buffers
3724                         p = &r_bufferdata_buffer[cycle][type];
3725                         while (*p)
3726                         {
3727                                 mem = *p;
3728                                 *p = (*p)->purge;
3729                                 if (mem->buffer)
3730                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3731                                 Mem_Free(mem);
3732                         }
3733                 }
3734         }
3735 }
3736
3737 // resize buffer as needed (this actually makes a new one, the old one will be recycled next frame)
3738 static void R_BufferData_Resize(r_bufferdata_type_t type, qboolean mustgrow, size_t minsize)
3739 {
3740         r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3741         size_t size;
3742         float newvalue = r_buffermegs[type].value;
3743
3744         // increase the cvar if we have to (but only if we already have a mem)
3745         if (mustgrow && mem)
3746                 newvalue *= 2.0f;
3747         newvalue = bound(0.25f, newvalue, 256.0f);
3748         while (newvalue * 1024*1024 < minsize)
3749                 newvalue *= 2.0f;
3750
3751         // clamp the cvar to valid range
3752         newvalue = bound(0.25f, newvalue, 256.0f);
3753         if (r_buffermegs[type].value != newvalue)
3754                 Cvar_SetValueQuick(&r_buffermegs[type], newvalue);
3755
3756         // calculate size in bytes
3757         size = (size_t)(newvalue * 1024*1024);
3758         size = bound(131072, size, 256*1024*1024);
3759
3760         // allocate a new buffer if the size is different (purge old one later)
3761         // or if we were told we must grow the buffer
3762         if (!mem || mem->size != size || mustgrow)
3763         {
3764                 mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem));
3765                 mem->size = size;
3766                 mem->current = 0;
3767                 if (type == R_BUFFERDATA_VERTEX)
3768                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbuffervertex", false, false, true, false);
3769                 else if (type == R_BUFFERDATA_INDEX16)
3770                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex16", true, false, true, true);
3771                 else if (type == R_BUFFERDATA_INDEX32)
3772                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex32", true, false, true, false);
3773                 else if (type == R_BUFFERDATA_UNIFORM)
3774                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferuniform", false, true, true, false);
3775                 mem->purge = r_bufferdata_buffer[r_bufferdata_cycle][type];
3776                 r_bufferdata_buffer[r_bufferdata_cycle][type] = mem;
3777         }
3778 }
3779
3780 void R_BufferData_NewFrame(void)
3781 {
3782         int type;
3783         r_bufferdata_buffer_t **p, *mem;
3784         // cycle to the next frame's buffers
3785         r_bufferdata_cycle = (r_bufferdata_cycle + 1) % R_BUFFERDATA_CYCLE;
3786         // if we ran out of space on the last time we used these buffers, free the old memory now
3787         for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3788         {
3789                 if (r_bufferdata_buffer[r_bufferdata_cycle][type])
3790                 {
3791                         R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072);
3792                         // free all but the head buffer, this is how we recycle obsolete
3793                         // buffers after they are no longer in use
3794                         p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge;
3795                         while (*p)
3796                         {
3797                                 mem = *p;
3798                                 *p = (*p)->purge;
3799                                 if (mem->buffer)
3800                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3801                                 Mem_Free(mem);
3802                         }
3803                         // reset the current offset
3804                         r_bufferdata_buffer[r_bufferdata_cycle][type]->current = 0;
3805                 }
3806         }
3807 }
3808
3809 r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset)
3810 {
3811         r_bufferdata_buffer_t *mem;
3812         int offset = 0;
3813         int padsize;
3814
3815         *returnbufferoffset = 0;
3816
3817         // align size to a byte boundary appropriate for the buffer type, this
3818         // makes all allocations have aligned start offsets
3819         if (type == R_BUFFERDATA_UNIFORM)
3820                 padsize = (datasize + r_uniformbufferalignment - 1) & ~(r_uniformbufferalignment - 1);
3821         else
3822                 padsize = (datasize + 15) & ~15;
3823
3824         // if we ran out of space in this buffer we must allocate a new one
3825         if (!r_bufferdata_buffer[r_bufferdata_cycle][type] || r_bufferdata_buffer[r_bufferdata_cycle][type]->current + padsize > r_bufferdata_buffer[r_bufferdata_cycle][type]->size)
3826                 R_BufferData_Resize(type, true, padsize);
3827
3828         // if the resize did not give us enough memory, fail
3829         if (!r_bufferdata_buffer[r_bufferdata_cycle][type] || r_bufferdata_buffer[r_bufferdata_cycle][type]->current + padsize > r_bufferdata_buffer[r_bufferdata_cycle][type]->size)
3830                 Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
3831
3832         mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3833         offset = (int)mem->current;
3834         mem->current += padsize;
3835
3836         // upload the data to the buffer at the chosen offset
3837         if (offset == 0)
3838                 R_Mesh_UpdateMeshBuffer(mem->buffer, NULL, mem->size, false, 0);
3839         R_Mesh_UpdateMeshBuffer(mem->buffer, data, datasize, true, offset);
3840
3841         // count the usage for stats
3842         r_refdef.stats[r_stat_bufferdatacurrent_vertex + type] = max(r_refdef.stats[r_stat_bufferdatacurrent_vertex + type], (int)mem->current);
3843         r_refdef.stats[r_stat_bufferdatasize_vertex + type] = max(r_refdef.stats[r_stat_bufferdatasize_vertex + type], (int)mem->size);
3844
3845         // return the buffer offset
3846         *returnbufferoffset = offset;
3847
3848         return mem->buffer;
3849 }
3850
3851 //==================================================================================
3852
3853 // LordHavoc: animcache originally written by Echon, rewritten since then
3854
3855 /**
3856  * Animation cache prevents re-generating mesh data for an animated model
3857  * multiple times in one frame for lighting, shadowing, reflections, etc.
3858  */
3859
3860 void R_AnimCache_Free(void)
3861 {
3862 }
3863
3864 void R_AnimCache_ClearCache(void)
3865 {
3866         int i;
3867         entity_render_t *ent;
3868
3869         for (i = 0;i < r_refdef.scene.numentities;i++)
3870         {
3871                 ent = r_refdef.scene.entities[i];
3872                 ent->animcache_vertex3f = NULL;
3873                 ent->animcache_vertex3f_vertexbuffer = NULL;
3874                 ent->animcache_vertex3f_bufferoffset = 0;
3875                 ent->animcache_normal3f = NULL;
3876                 ent->animcache_normal3f_vertexbuffer = NULL;
3877                 ent->animcache_normal3f_bufferoffset = 0;
3878                 ent->animcache_svector3f = NULL;
3879                 ent->animcache_svector3f_vertexbuffer = NULL;
3880                 ent->animcache_svector3f_bufferoffset = 0;
3881                 ent->animcache_tvector3f = NULL;
3882                 ent->animcache_tvector3f_vertexbuffer = NULL;
3883                 ent->animcache_tvector3f_bufferoffset = 0;
3884                 ent->animcache_vertexmesh = NULL;
3885                 ent->animcache_vertexmesh_vertexbuffer = NULL;
3886                 ent->animcache_vertexmesh_bufferoffset = 0;
3887                 ent->animcache_skeletaltransform3x4 = NULL;
3888                 ent->animcache_skeletaltransform3x4buffer = NULL;
3889                 ent->animcache_skeletaltransform3x4offset = 0;
3890                 ent->animcache_skeletaltransform3x4size = 0;
3891         }
3892 }
3893
3894 static void R_AnimCache_UpdateEntityMeshBuffers(entity_render_t *ent, int numvertices)
3895 {
3896         int i;
3897
3898         // check if we need the meshbuffers
3899         if (!vid.useinterleavedarrays)
3900                 return;
3901
3902         if (!ent->animcache_vertexmesh && ent->animcache_normal3f)
3903                 ent->animcache_vertexmesh = (r_vertexmesh_t *)R_FrameData_Alloc(sizeof(r_vertexmesh_t)*numvertices);
3904         // TODO: upload vertexbuffer?
3905         if (ent->animcache_vertexmesh)
3906         {
3907                 r_refdef.stats[r_stat_animcache_vertexmesh_count] += 1;
3908                 r_refdef.stats[r_stat_animcache_vertexmesh_vertices] += numvertices;
3909                 r_refdef.stats[r_stat_animcache_vertexmesh_maxvertices] = max(r_refdef.stats[r_stat_animcache_vertexmesh_maxvertices], numvertices);
3910                 memcpy(ent->animcache_vertexmesh, ent->model->surfmesh.data_vertexmesh, sizeof(r_vertexmesh_t)*numvertices);
3911                 for (i = 0;i < numvertices;i++)
3912                         memcpy(ent->animcache_vertexmesh[i].vertex3f, ent->animcache_vertex3f + 3*i, sizeof(float[3]));
3913                 if (ent->animcache_svector3f)
3914                         for (i = 0;i < numvertices;i++)
3915                                 memcpy(ent->animcache_vertexmesh[i].svector3f, ent->animcache_svector3f + 3*i, sizeof(float[3]));
3916                 if (ent->animcache_tvector3f)
3917                         for (i = 0;i < numvertices;i++)
3918                                 memcpy(ent->animcache_vertexmesh[i].tvector3f, ent->animcache_tvector3f + 3*i, sizeof(float[3]));
3919                 if (ent->animcache_normal3f)
3920                         for (i = 0;i < numvertices;i++)
3921                                 memcpy(ent->animcache_vertexmesh[i].normal3f, ent->animcache_normal3f + 3*i, sizeof(float[3]));
3922         }
3923 }
3924
3925 qboolean R_AnimCache_GetEntity(entity_render_t *ent, qboolean wantnormals, qboolean wanttangents)
3926 {
3927         dp_model_t *model = ent->model;
3928         int numvertices;
3929
3930         // see if this ent is worth caching
3931         if (!model || !model->Draw || !model->AnimateVertices)
3932                 return false;
3933         // nothing to cache if it contains no animations and has no skeleton
3934         if (!model->surfmesh.isanimated && !(model->num_bones && ent->skeleton && ent->skeleton->relativetransforms))
3935                 return false;
3936         // see if it is already cached for gpuskeletal
3937         if (ent->animcache_skeletaltransform3x4)
3938                 return false;
3939         // see if it is already cached as a mesh
3940         if (ent->animcache_vertex3f)
3941         {
3942                 // check if we need to add normals or tangents
3943                 if (ent->animcache_normal3f)
3944                         wantnormals = false;
3945                 if (ent->animcache_svector3f)
3946                         wanttangents = false;
3947                 if (!wantnormals && !wanttangents)
3948                         return false;
3949         }
3950
3951         // check which kind of cache we need to generate
3952         if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
3953         {
3954                 // cache the skeleton so the vertex shader can use it
3955                 r_refdef.stats[r_stat_animcache_skeletal_count] += 1;
3956                 r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones;
3957                 r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones);
3958                 ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones);
3959                 Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4); 
3960                 // note: this can fail if the buffer is at the grow limit
3961                 ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones;
3962                 ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset);
3963         }
3964         else if (ent->animcache_vertex3f)
3965         {
3966                 // mesh was already cached but we may need to add normals/tangents
3967                 // (this only happens with multiple views, reflections, cameras, etc)
3968                 if (wantnormals || wanttangents)
3969                 {
3970                         numvertices = model->surfmesh.num_vertices;
3971                         if (wantnormals)
3972                                 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3973                         if (wanttangents)
3974                         {
3975                                 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3976                                 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3977                         }
3978                         model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
3979                         R_AnimCache_UpdateEntityMeshBuffers(ent, model->surfmesh.num_vertices);
3980                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3981                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3982                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3983                 }
3984         }
3985         else
3986         {
3987                 // generate mesh cache
3988                 numvertices = model->surfmesh.num_vertices;
3989                 ent->animcache_vertex3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3990                 if (wantnormals)
3991                         ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3992                 if (wanttangents)
3993                 {
3994                         ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3995                         ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3996                 }
3997                 model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
3998                 R_AnimCache_UpdateEntityMeshBuffers(ent, model->surfmesh.num_vertices);
3999                 if (wantnormals || wanttangents)
4000                 {
4001                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
4002                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
4003                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
4004                 }
4005                 r_refdef.stats[r_stat_animcache_shape_count] += 1;
4006                 r_refdef.stats[r_stat_animcache_shape_vertices] += numvertices;
4007                 r_refdef.stats[r_stat_animcache_shape_maxvertices] = max(r_refdef.stats[r_stat_animcache_shape_maxvertices], numvertices);
4008         }
4009         return true;
4010 }
4011
4012 void R_AnimCache_CacheVisibleEntities(void)
4013 {
4014         int i;
4015
4016         // TODO: thread this
4017         // NOTE: R_PrepareRTLights() also caches entities
4018
4019         for (i = 0;i < r_refdef.scene.numentities;i++)
4020                 if (r_refdef.viewcache.entityvisible[i])
4021                         R_AnimCache_GetEntity(r_refdef.scene.entities[i], true, true);
4022 }
4023
4024 //==================================================================================
4025
4026 qboolean R_CanSeeBox(int numsamples, vec_t eyejitter, vec_t entboxenlarge, vec_t entboxexpand, vec_t pad, vec3_t eye, vec3_t entboxmins, vec3_t entboxmaxs)
4027 {
4028         int i;
4029         vec3_t eyemins, eyemaxs;
4030         vec3_t boxmins, boxmaxs;
4031         vec3_t padmins, padmaxs;
4032         vec3_t start;
4033         vec3_t end;
4034         dp_model_t *model = r_refdef.scene.worldmodel;
4035         static vec3_t positions[] = {
4036                 { 0.5f, 0.5f, 0.5f },
4037                 { 0.0f, 0.0f, 0.0f },
4038                 { 0.0f, 0.0f, 1.0f },
4039                 { 0.0f, 1.0f, 0.0f },
4040                 { 0.0f, 1.0f, 1.0f },
4041                 { 1.0f, 0.0f, 0.0f },
4042                 { 1.0f, 0.0f, 1.0f },
4043                 { 1.0f, 1.0f, 0.0f },
4044                 { 1.0f, 1.0f, 1.0f },
4045         };
4046
4047         // sample count can be set to -1 to skip this logic, for flicker-prone objects
4048         if (numsamples < 0)
4049                 return true;
4050
4051         // view origin is not used for culling in portal/reflection/refraction renders or isometric views
4052         if (!r_refdef.view.usevieworiginculling)
4053                 return true;
4054
4055         if (!r_cullentities_trace_entityocclusion.integer && (!model || !model->brush.TraceLineOfSight))
4056                 return true;
4057
4058         // expand the eye box a little
4059         eyemins[0] = eye[0] - eyejitter;
4060         eyemaxs[0] = eye[0] + eyejitter;
4061         eyemins[1] = eye[1] - eyejitter;
4062         eyemaxs[1] = eye[1] + eyejitter;
4063         eyemins[2] = eye[2] - eyejitter;
4064         eyemaxs[2] = eye[2] + eyejitter;
4065         // expand the box a little
4066         boxmins[0] = (entboxenlarge + 1) * entboxmins[0] - entboxenlarge * entboxmaxs[0] - entboxexpand;
4067         boxmaxs[0] = (entboxenlarge + 1) * entboxmaxs[0] - entboxenlarge * entboxmins[0] + entboxexpand;
4068         boxmins[1] = (entboxenlarge + 1) * entboxmins[1] - entboxenlarge * entboxmaxs[1] - entboxexpand;
4069         boxmaxs[1] = (entboxenlarge + 1) * entboxmaxs[1] - entboxenlarge * entboxmins[1] + entboxexpand;
4070         boxmins[2] = (entboxenlarge + 1) * entboxmins[2] - entboxenlarge * entboxmaxs[2] - entboxexpand;
4071         boxmaxs[2] = (entboxenlarge + 1) * entboxmaxs[2] - entboxenlarge * entboxmins[2] + entboxexpand;
4072         // make an even larger box for the acceptable area
4073         padmins[0] = boxmins[0] - pad;
4074         padmaxs[0] = boxmaxs[0] + pad;
4075         padmins[1] = boxmins[1] - pad;
4076         padmaxs[1] = boxmaxs[1] + pad;
4077         padmins[2] = boxmins[2] - pad;
4078         padmaxs[2] = boxmaxs[2] + pad;
4079
4080         // return true if eye overlaps enlarged box
4081         if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs))
4082                 return true;
4083
4084         // try specific positions in the box first - note that these can be cached
4085         if (r_cullentities_trace_entityocclusion.integer)
4086         {
4087                 for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++)
4088                 {
4089                         VectorCopy(eye, start);
4090                         end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0];
4091                         end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1];
4092                         end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2];
4093                         //trace_t trace = CL_TraceLine(start, end, MOVE_NOMONSTERS, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, 0.0f, true, false, NULL, true, true);
4094                         trace_t trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
4095                         // not picky - if the trace ended anywhere in the box we're good
4096                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4097                                 return true;
4098                 }
4099         }
4100         else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4101                 return true;
4102
4103         // try various random positions
4104         for (i = 0; i < numsamples; i++)
4105         {
4106                 VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
4107                 VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
4108                 if (r_cullentities_trace_entityocclusion.integer)
4109                 {
4110                         trace_t trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
4111                         // not picky - if the trace ended anywhere in the box we're good
4112                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4113                                 return true;
4114                 }
4115                 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4116                         return true;
4117         }
4118
4119         return false;
4120 }
4121
4122
4123 static void R_View_UpdateEntityVisible (void)
4124 {
4125         int i;
4126         int renderimask;
4127         int samples;
4128         entity_render_t *ent;
4129
4130         if (r_refdef.envmap || r_fb.water.hideplayer)
4131                 renderimask = RENDER_EXTERIORMODEL | RENDER_VIEWMODEL;
4132         else if (chase_active.integer || r_fb.water.renderingscene)
4133                 renderimask = RENDER_VIEWMODEL;
4134         else
4135                 renderimask = RENDER_EXTERIORMODEL;
4136         if (!r_drawviewmodel.integer)
4137                 renderimask |= RENDER_VIEWMODEL;
4138         if (!r_drawexteriormodel.integer)
4139                 renderimask |= RENDER_EXTERIORMODEL;
4140         memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
4141         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
4142         {
4143                 // worldmodel can check visibility
4144                 for (i = 0;i < r_refdef.scene.numentities;i++)
4145                 {
4146                         ent = r_refdef.scene.entities[i];
4147                         if (!(ent->flags & renderimask))
4148                         if (!R_CullBox(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
4149                         if ((ent->flags & (RENDER_NODEPTHTEST | RENDER_WORLDOBJECT | RENDER_VIEWMODEL)) || r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs(r_refdef.scene.worldmodel, r_refdef.viewcache.world_leafvisible, ent->mins, ent->maxs))
4150                                 r_refdef.viewcache.entityvisible[i] = true;
4151                 }
4152         }
4153         else
4154         {
4155                 // no worldmodel or it can't check visibility
4156                 for (i = 0;i < r_refdef.scene.numentities;i++)
4157                 {
4158                         ent = r_refdef.scene.entities[i];
4159                         if (!(ent->flags & renderimask))
4160                         if (!R_CullBox(ent->mins, ent->maxs) || (ent->model && ent->model->type == mod_sprite && (ent->model->sprite.sprnum_type == SPR_LABEL || ent->model->sprite.sprnum_type == SPR_LABEL_SCALE)))
4161                                 r_refdef.viewcache.entityvisible[i] = true;
4162                 }
4163         }
4164         if (r_cullentities_trace.integer)
4165         {
4166                 for (i = 0;i < r_refdef.scene.numentities;i++)
4167                 {
4168                         if (!r_refdef.viewcache.entityvisible[i])
4169                                 continue;
4170                         ent = r_refdef.scene.entities[i];
4171                         if (!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
4172                         {
4173                                 samples = ent->last_trace_visibility == 0 ? r_cullentities_trace_tempentitysamples.integer : r_cullentities_trace_samples.integer;
4174                                 if (R_CanSeeBox(samples, r_cullentities_trace_eyejitter.value, r_cullentities_trace_enlarge.value, r_cullentities_trace_expand.value, r_cullentities_trace_pad.value, r_refdef.view.origin, ent->mins, ent->maxs))
4175                                         ent->last_trace_visibility = realtime;
4176                                 if (ent->last_trace_visibility < realtime - r_cullentities_trace_delay.value)
4177                                         r_refdef.viewcache.entityvisible[i] = 0;
4178                         }
4179                 }
4180         }
4181 }
4182
4183 /// only used if skyrendermasked, and normally returns false
4184 static int R_DrawBrushModelsSky (void)
4185 {
4186         int i, sky;
4187         entity_render_t *ent;
4188
4189         sky = false;
4190         for (i = 0;i < r_refdef.scene.numentities;i++)
4191         {
4192                 if (!r_refdef.viewcache.entityvisible[i])
4193                         continue;
4194                 ent = r_refdef.scene.entities[i];
4195                 if (!ent->model || !ent->model->DrawSky)
4196                         continue;
4197                 ent->model->DrawSky(ent);
4198                 sky = true;
4199         }
4200         return sky;
4201 }
4202
4203 static void R_DrawNoModel(entity_render_t *ent);
4204 static void R_DrawModels(void)
4205 {
4206         int i;
4207         entity_render_t *ent;
4208
4209         for (i = 0;i < r_refdef.scene.numentities;i++)
4210         {
4211                 if (!r_refdef.viewcache.entityvisible[i])
4212                         continue;
4213                 ent = r_refdef.scene.entities[i];
4214                 r_refdef.stats[r_stat_entities]++;
4215                 /*
4216                 if (ent->model && !strncmp(ent->model->name, "models/proto_", 13))
4217                 {
4218                         vec3_t f, l, u, o;
4219                         Matrix4x4_ToVectors(&ent->matrix, f, l, u, o);
4220                         Con_Printf("R_DrawModels\n");
4221                         Con_Printf("model %s O %f %f %f F %f %f %f L %f %f %f U %f %f %f\n", ent->model->name, o[0], o[1], o[2], f[0], f[1], f[2], l[0], l[1], l[2], u[0], u[1], u[2]);
4222                         Con_Printf("group: %i %f %i %f %i %f %i %f\n", ent->framegroupblend[0].frame, ent->framegroupblend[0].lerp, ent->framegroupblend[1].frame, ent->framegroupblend[1].lerp, ent->framegroupblend[2].frame, ent->framegroupblend[2].lerp, ent->framegroupblend[3].frame, ent->framegroupblend[3].lerp);
4223                         Con_Printf("blend: %i %f %i %f %i %f %i %f %i %f %i %f %i %f %i %f\n", ent->frameblend[0].subframe, ent->frameblend[0].lerp, ent->frameblend[1].subframe, ent->frameblend[1].lerp, ent->frameblend[2].subframe, ent->frameblend[2].lerp, ent->frameblend[3].subframe, ent->frameblend[3].lerp, ent->frameblend[4].subframe, ent->frameblend[4].lerp, ent->frameblend[5].subframe, ent->frameblend[5].lerp, ent->frameblend[6].subframe, ent->frameblend[6].lerp, ent->frameblend[7].subframe, ent->frameblend[7].lerp);
4224                 }
4225                 */
4226                 if (ent->model && ent->model->Draw != NULL)
4227                         ent->model->Draw(ent);
4228                 else
4229                         R_DrawNoModel(ent);
4230         }
4231 }
4232
4233 static void R_DrawModelsDepth(void)
4234 {
4235         int i;
4236         entity_render_t *ent;
4237
4238         for (i = 0;i < r_refdef.scene.numentities;i++)
4239         {
4240                 if (!r_refdef.viewcache.entityvisible[i])
4241                         continue;
4242                 ent = r_refdef.scene.entities[i];
4243                 if (ent->model && ent->model->DrawDepth != NULL)
4244                         ent->model->DrawDepth(ent);
4245         }
4246 }
4247
4248 static void R_DrawModelsDebug(void)
4249 {
4250         int i;
4251         entity_render_t *ent;
4252
4253         for (i = 0;i < r_refdef.scene.numentities;i++)
4254         {
4255                 if (!r_refdef.viewcache.entityvisible[i])
4256                         continue;
4257                 ent = r_refdef.scene.entities[i];
4258                 if (ent->model && ent->model->DrawDebug != NULL)
4259                         ent->model->DrawDebug(ent);
4260         }
4261 }
4262
4263 static void R_DrawModelsAddWaterPlanes(void)
4264 {
4265         int i;
4266         entity_render_t *ent;
4267
4268         for (i = 0;i < r_refdef.scene.numentities;i++)
4269         {
4270                 if (!r_refdef.viewcache.entityvisible[i])
4271                         continue;
4272                 ent = r_refdef.scene.entities[i];
4273                 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
4274                         ent->model->DrawAddWaterPlanes(ent);
4275         }
4276 }
4277
4278 static float irisvecs[7][3] = {{0, 0, 0}, {-1, 0, 0}, {1, 0, 0}, {0, -1, 0}, {0, 1, 0}, {0, 0, -1}, {0, 0, 1}};
4279
4280 void R_HDR_UpdateIrisAdaptation(const vec3_t point)
4281 {
4282         if (r_hdr_irisadaptation.integer)
4283         {
4284                 vec3_t p;
4285                 vec3_t ambient;
4286                 vec3_t diffuse;
4287                 vec3_t diffusenormal;
4288                 vec3_t forward;
4289                 vec_t brightness = 0.0f;
4290                 vec_t goal;
4291                 vec_t current;
4292                 vec_t d;
4293                 int c;
4294                 VectorCopy(r_refdef.view.forward, forward);
4295                 for (c = 0;c < (int)(sizeof(irisvecs)/sizeof(irisvecs[0]));c++)
4296                 {
4297                         p[0] = point[0] + irisvecs[c][0] * r_hdr_irisadaptation_radius.value;
4298                         p[1] = point[1] + irisvecs[c][1] * r_hdr_irisadaptation_radius.value;
4299                         p[2] = point[2] + irisvecs[c][2] * r_hdr_irisadaptation_radius.value;
4300                         R_CompleteLightPoint(ambient, diffuse, diffusenormal, p, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity);
4301                         d = DotProduct(forward, diffusenormal);
4302                         brightness += VectorLength(ambient);
4303                         if (d > 0)
4304                                 brightness += d * VectorLength(diffuse);
4305                 }
4306                 brightness *= 1.0f / c;
4307                 brightness += 0.00001f; // make sure it's never zero
4308                 goal = r_hdr_irisadaptation_multiplier.value / brightness;
4309                 goal = bound(r_hdr_irisadaptation_minvalue.value, goal, r_hdr_irisadaptation_maxvalue.value);
4310                 current = r_hdr_irisadaptation_value.value;
4311                 if (current < goal)
4312                         current = min(current + r_hdr_irisadaptation_fade_up.value * cl.realframetime, goal);
4313                 else if (current > goal)
4314                         current = max(current - r_hdr_irisadaptation_fade_down.value * cl.realframetime, goal);
4315                 if (fabs(r_hdr_irisadaptation_value.value - current) > 0.0001f)
4316                         Cvar_SetValueQuick(&r_hdr_irisadaptation_value, current);
4317         }
4318         else if (r_hdr_irisadaptation_value.value != 1.0f)
4319                 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, 1.0f);
4320 }
4321
4322 static void R_View_SetFrustum(const int *scissor)
4323 {
4324         int i;
4325         double fpx = +1, fnx = -1, fpy = +1, fny = -1;
4326         vec3_t forward, left, up, origin, v;
4327
4328         if(scissor)
4329         {
4330                 // flipped x coordinates (because x points left here)
4331                 fpx =  1.0 - 2.0 * (scissor[0]              - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4332                 fnx =  1.0 - 2.0 * (scissor[0] + scissor[2] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4333                 // non-flipped y coordinates
4334                 fny = -1.0 + 2.0 * (scissor[1]              - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4335                 fpy = -1.0 + 2.0 * (scissor[1] + scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4336         }
4337
4338         // we can't trust r_refdef.view.forward and friends in reflected scenes
4339         Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin);
4340
4341 #if 0
4342         r_refdef.view.frustum[0].normal[0] = 0 - 1.0 / r_refdef.view.frustum_x;
4343         r_refdef.view.frustum[0].normal[1] = 0 - 0;
4344         r_refdef.view.frustum[0].normal[2] = -1 - 0;
4345         r_refdef.view.frustum[1].normal[0] = 0 + 1.0 / r_refdef.view.frustum_x;
4346         r_refdef.view.frustum[1].normal[1] = 0 + 0;
4347         r_refdef.view.frustum[1].normal[2] = -1 + 0;
4348         r_refdef.view.frustum[2].normal[0] = 0 - 0;
4349         r_refdef.view.frustum[2].normal[1] = 0 - 1.0 / r_refdef.view.frustum_y;
4350         r_refdef.view.frustum[2].normal[2] = -1 - 0;
4351         r_refdef.view.frustum[3].normal[0] = 0 + 0;
4352         r_refdef.view.frustum[3].normal[1] = 0 + 1.0 / r_refdef.view.frustum_y;
4353         r_refdef.view.frustum[3].normal[2] = -1 + 0;
4354 #endif
4355
4356 #if 0
4357         zNear = r_refdef.nearclip;
4358         nudge = 1.0 - 1.0 / (1<<23);
4359         r_refdef.view.frustum[4].normal[0] = 0 - 0;
4360         r_refdef.view.frustum[4].normal[1] = 0 - 0;
4361         r_refdef.view.frustum[4].normal[2] = -1 - -nudge;
4362         r_refdef.view.frustum[4].dist = 0 - -2 * zNear * nudge;
4363         r_refdef.view.frustum[5].normal[0] = 0 + 0;
4364         r_refdef.view.frustum[5].normal[1] = 0 + 0;
4365         r_refdef.view.frustum[5].normal[2] = -1 + -nudge;
4366         r_refdef.view.frustum[5].dist = 0 + -2 * zNear * nudge;
4367 #endif
4368
4369
4370
4371 #if 0
4372         r_refdef.view.frustum[0].normal[0] = m[3] - m[0];
4373         r_refdef.view.frustum[0].normal[1] = m[7] - m[4];
4374         r_refdef.view.frustum[0].normal[2] = m[11] - m[8];
4375         r_refdef.view.frustum[0].dist = m[15] - m[12];
4376
4377         r_refdef.view.frustum[1].normal[0] = m[3] + m[0];
4378         r_refdef.view.frustum[1].normal[1] = m[7] + m[4];
4379         r_refdef.view.frustum[1].normal[2] = m[11] + m[8];
4380         r_refdef.view.frustum[1].dist = m[15] + m[12];
4381
4382         r_refdef.view.frustum[2].normal[0] = m[3] - m[1];
4383         r_refdef.view.frustum[2].normal[1] = m[7] - m[5];
4384         r_refdef.view.frustum[2].normal[2] = m[11] - m[9];
4385         r_refdef.view.frustum[2].dist = m[15] - m[13];
4386
4387         r_refdef.view.frustum[3].normal[0] = m[3] + m[1];
4388         r_refdef.view.frustum[3].normal[1] = m[7] + m[5];
4389         r_refdef.view.frustum[3].normal[2] = m[11] + m[9];
4390         r_refdef.view.frustum[3].dist = m[15] + m[13];
4391
4392         r_refdef.view.frustum[4].normal[0] = m[3] - m[2];
4393         r_refdef.view.frustum[4].normal[1] = m[7] - m[6];
4394         r_refdef.view.frustum[4].normal[2] = m[11] - m[10];
4395         r_refdef.view.frustum[4].dist = m[15] - m[14];
4396
4397         r_refdef.view.frustum[5].normal[0] = m[3] + m[2];
4398         r_refdef.view.frustum[5].normal[1] = m[7] + m[6];
4399         r_refdef.view.frustum[5].normal[2] = m[11] + m[10];
4400         r_refdef.view.frustum[5].dist = m[15] + m[14];
4401 #endif
4402
4403         if (r_refdef.view.useperspective)
4404         {
4405                 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
4406                 VectorMAMAM(1024, forward, fnx * 1024.0 * r_refdef.view.frustum_x, left, fny * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[0]);
4407                 VectorMAMAM(1024, forward, fpx * 1024.0 * r_refdef.view.frustum_x, left, fny * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[1]);
4408                 VectorMAMAM(1024, forward, fnx * 1024.0 * r_refdef.view.frustum_x, left, fpy * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[2]);
4409                 VectorMAMAM(1024, forward, fpx * 1024.0 * r_refdef.view.frustum_x, left, fpy * 1024.0 * r_refdef.view.frustum_y, up, r_refdef.view.frustumcorner[3]);
4410
4411                 // then the normals from the corners relative to origin
4412                 CrossProduct(r_refdef.view.frustumcorner[2], r_refdef.view.frustumcorner[0], r_refdef.view.frustum[0].normal);
4413                 CrossProduct(r_refdef.view.frustumcorner[1], r_refdef.view.frustumcorner[3], r_refdef.view.frustum[1].normal);
4414                 CrossProduct(r_refdef.view.frustumcorner[0], r_refdef.view.frustumcorner[1], r_refdef.view.frustum[2].normal);
4415                 CrossProduct(r_refdef.view.frustumcorner[3], r_refdef.view.frustumcorner[2], r_refdef.view.frustum[3].normal);
4416
4417                 // in a NORMAL view, forward cross left == up
4418                 // in a REFLECTED view, forward cross left == down
4419                 // so our cross products above need to be adjusted for a left handed coordinate system
4420                 CrossProduct(forward, left, v);
4421                 if(DotProduct(v, up) < 0)
4422                 {
4423                         VectorNegate(r_refdef.view.frustum[0].normal, r_refdef.view.frustum[0].normal);
4424                         VectorNegate(r_refdef.view.frustum[1].normal, r_refdef.view.frustum[1].normal);
4425                         VectorNegate(r_refdef.view.frustum[2].normal, r_refdef.view.frustum[2].normal);
4426                         VectorNegate(r_refdef.view.frustum[3].normal, r_refdef.view.frustum[3].normal);
4427                 }
4428
4429                 // Leaving those out was a mistake, those were in the old code, and they
4430                 // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix
4431                 // I couldn't reproduce it after adding those normalizations. --blub
4432                 VectorNormalize(r_refdef.view.frustum[0].normal);
4433                 VectorNormalize(r_refdef.view.frustum[1].normal);
4434                 VectorNormalize(r_refdef.view.frustum[2].normal);
4435                 VectorNormalize(r_refdef.view.frustum[3].normal);
4436
4437                 // make the corners absolute
4438                 VectorAdd(r_refdef.view.frustumcorner[0], r_refdef.view.origin, r_refdef.view.frustumcorner[0]);
4439                 VectorAdd(r_refdef.view.frustumcorner[1], r_refdef.view.origin, r_refdef.view.frustumcorner[1]);
4440                 VectorAdd(r_refdef.view.frustumcorner[2], r_refdef.view.origin, r_refdef.view.frustumcorner[2]);
4441                 VectorAdd(r_refdef.view.frustumcorner[3], r_refdef.view.origin, r_refdef.view.frustumcorner[3]);
4442
4443                 // one more normal
4444                 VectorCopy(forward, r_refdef.view.frustum[4].normal);
4445
4446                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal);
4447                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal);
4448                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal);
4449                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal);
4450                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip;
4451         }
4452         else
4453         {
4454                 VectorScale(left, -1.0f, r_refdef.view.frustum[0].normal);
4455                 VectorScale(left,  1.0f, r_refdef.view.frustum[1].normal);
4456                 VectorScale(up, -1.0f, r_refdef.view.frustum[2].normal);
4457                 VectorScale(up,  1.0f, r_refdef.view.frustum[3].normal);
4458                 VectorScale(forward, -1.0f, r_refdef.view.frustum[4].normal);
4459                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal) - r_refdef.view.ortho_x;
4460                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal) - r_refdef.view.ortho_x;
4461                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal) - r_refdef.view.ortho_y;
4462                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal) - r_refdef.view.ortho_y;
4463                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) - r_refdef.farclip;
4464         }
4465         r_refdef.view.numfrustumplanes = 5;
4466
4467         if (r_refdef.view.useclipplane)
4468         {
4469                 r_refdef.view.numfrustumplanes = 6;
4470                 r_refdef.view.frustum[5] = r_refdef.view.clipplane;
4471         }
4472
4473         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
4474                 PlaneClassify(r_refdef.view.frustum + i);
4475
4476         // LordHavoc: note to all quake engine coders, Quake had a special case
4477         // for 90 degrees which assumed a square view (wrong), so I removed it,
4478         // Quake2 has it disabled as well.
4479
4480         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
4481         //RotatePointAroundVector( r_refdef.view.frustum[0].normal, up, forward, -(90 - r_refdef.fov_x / 2));
4482         //r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, frustum[0].normal);
4483         //PlaneClassify(&frustum[0]);
4484
4485         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
4486         //RotatePointAroundVector( r_refdef.view.frustum[1].normal, up, forward, (90 - r_refdef.fov_x / 2));
4487         //r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, frustum[1].normal);
4488         //PlaneClassify(&frustum[1]);
4489
4490         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
4491         //RotatePointAroundVector( r_refdef.view.frustum[2].normal, left, forward, -(90 - r_refdef.fov_y / 2));
4492         //r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, frustum[2].normal);
4493         //PlaneClassify(&frustum[2]);
4494
4495         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
4496         //RotatePointAroundVector( r_refdef.view.frustum[3].normal, left, forward, (90 - r_refdef.fov_y / 2));
4497         //r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, frustum[3].normal);
4498         //PlaneClassify(&frustum[3]);
4499
4500         // nearclip plane
4501         //VectorCopy(forward, r_refdef.view.frustum[4].normal);
4502         //r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, frustum[4].normal) + r_nearclip.value;
4503         //PlaneClassify(&frustum[4]);
4504 }
4505
4506 static void R_View_UpdateWithScissor(const int *myscissor)
4507 {
4508         R_Main_ResizeViewCache();
4509         R_View_SetFrustum(myscissor);
4510         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4511         R_View_UpdateEntityVisible();
4512 }
4513
4514 static void R_View_Update(void)
4515 {
4516         R_Main_ResizeViewCache();
4517         R_View_SetFrustum(NULL);
4518         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4519         R_View_UpdateEntityVisible();
4520 }
4521
4522 float viewscalefpsadjusted = 1.0f;
4523
4524 static void R_GetScaledViewSize(int width, int height, int *outwidth, int *outheight)
4525 {
4526         float scale = r_viewscale.value * sqrt(viewscalefpsadjusted);
4527         scale = bound(0.03125f, scale, 1.0f);
4528         *outwidth = (int)ceil(width * scale);
4529         *outheight = (int)ceil(height * scale);
4530 }
4531
4532 void R_SetupView(qboolean allowwaterclippingplane, int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4533 {
4534         const float *customclipplane = NULL;
4535         float plane[4];
4536         int /*rtwidth,*/ rtheight;
4537         if (r_refdef.view.useclipplane && allowwaterclippingplane)
4538         {
4539                 // LadyHavoc: couldn't figure out how to make this approach work the same in DPSOFTRAST
4540                 vec_t dist = r_refdef.view.clipplane.dist - r_water_clippingplanebias.value;
4541                 vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
4542                 if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
4543                         dist = r_refdef.view.clipplane.dist;
4544                 plane[0] = r_refdef.view.clipplane.normal[0];
4545                 plane[1] = r_refdef.view.clipplane.normal[1];
4546                 plane[2] = r_refdef.view.clipplane.normal[2];
4547                 plane[3] = -dist;
4548                 customclipplane = plane;
4549         }
4550
4551         //rtwidth = viewfbo ? R_TextureWidth(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.width;
4552         rtheight = viewfbo ? R_TextureHeight(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.height;
4553
4554         if (!r_refdef.view.useperspective)
4555                 R_Viewport_InitOrtho3D(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.ortho_x, r_refdef.view.ortho_y, -r_refdef.farclip, r_refdef.farclip, customclipplane);
4556         else if (vid.stencil && r_useinfinitefarclip.integer)
4557                 R_Viewport_InitPerspectiveInfinite(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, customclipplane);
4558         else
4559                 R_Viewport_InitPerspective(&r_refdef.view.viewport, &r_refdef.view.matrix, viewx, rtheight - viewheight - viewy, viewwidth, viewheight, r_refdef.view.frustum_x, r_refdef.view.frustum_y, r_refdef.nearclip, r_refdef.farclip, customclipplane);
4560         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4561         R_SetViewport(&r_refdef.view.viewport);
4562 }
4563
4564 void R_EntityMatrix(const matrix4x4_t *matrix)
4565 {
4566         if (gl_modelmatrixchanged || memcmp(matrix, &gl_modelmatrix, sizeof(matrix4x4_t)))
4567         {
4568                 gl_modelmatrixchanged = false;
4569                 gl_modelmatrix = *matrix;
4570                 Matrix4x4_Concat(&gl_modelviewmatrix, &gl_viewmatrix, &gl_modelmatrix);
4571                 Matrix4x4_Concat(&gl_modelviewprojectionmatrix, &gl_projectionmatrix, &gl_modelviewmatrix);
4572                 Matrix4x4_ToArrayFloatGL(&gl_modelviewmatrix, gl_modelview16f);
4573                 Matrix4x4_ToArrayFloatGL(&gl_modelviewprojectionmatrix, gl_modelviewprojection16f);
4574                 CHECKGLERROR
4575                 switch(vid.renderpath)
4576                 {
4577                 case RENDERPATH_GL20:
4578                 case RENDERPATH_GLES2:
4579                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
4580                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
4581                         break;
4582                 }
4583         }
4584 }
4585
4586 void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2)
4587 {
4588         r_viewport_t viewport;
4589
4590         CHECKGLERROR
4591
4592         // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
4593         R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, vid.height - viewheight - viewy, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
4594         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4595         R_SetViewport(&viewport);
4596         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
4597         GL_Color(1, 1, 1, 1);
4598         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4599         GL_BlendFunc(GL_ONE, GL_ZERO);
4600         GL_ScissorTest(false);
4601         GL_DepthMask(false);
4602         GL_DepthRange(0, 1);
4603         GL_DepthTest(false);
4604         GL_DepthFunc(GL_LEQUAL);
4605         R_EntityMatrix(&identitymatrix);
4606         R_Mesh_ResetTextureState();
4607         GL_PolygonOffset(0, 0);
4608         R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
4609         switch(vid.renderpath)
4610         {
4611         case RENDERPATH_GL20:
4612         case RENDERPATH_GLES2:
4613                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4614                 break;
4615         }
4616         GL_CullFace(GL_NONE);
4617
4618         CHECKGLERROR
4619 }
4620
4621 void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4622 {
4623         R_ResetViewRendering2D_Common(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight, 1.0f, 1.0f);
4624 }
4625
4626 void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4627 {
4628         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
4629         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4630         GL_Color(1, 1, 1, 1);
4631         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4632         GL_BlendFunc(GL_ONE, GL_ZERO);
4633         GL_ScissorTest(true);
4634         GL_DepthMask(true);
4635         GL_DepthRange(0, 1);
4636         GL_DepthTest(true);
4637         GL_DepthFunc(GL_LEQUAL);
4638         R_EntityMatrix(&identitymatrix);
4639         R_Mesh_ResetTextureState();
4640         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4641         R_SetStencil(false, 255, GL_KEEP, GL_KEEP, GL_KEEP, GL_ALWAYS, 128, 255);
4642         switch(vid.renderpath)
4643         {
4644         case RENDERPATH_GL20:
4645         case RENDERPATH_GLES2:
4646                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4647                 break;
4648         }
4649         GL_CullFace(r_refdef.view.cullface_back);
4650 }
4651
4652 /*
4653 ================
4654 R_RenderView_UpdateViewVectors
4655 ================
4656 */
4657 void R_RenderView_UpdateViewVectors(void)
4658 {
4659         // break apart the view matrix into vectors for various purposes
4660         // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
4661         // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc
4662         Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
4663         VectorNegate(r_refdef.view.left, r_refdef.view.right);
4664         // make an inverted copy of the view matrix for tracking sprites
4665         Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
4666 }
4667
4668 void R_RenderTarget_FreeUnused(qboolean force)
4669 {
4670         int i, j, end;
4671         end = Mem_ExpandableArray_IndexRange(&r_fb.rendertargets);
4672         for (i = 0; i < end; i++)
4673         {
4674                 r_rendertarget_t *r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4675                 // free resources for rendertargets that have not been used for a while
4676                 // (note: this check is run after the frame render, so any targets used
4677                 // this frame will not be affected even at low framerates)
4678                 if (r && (realtime - r->lastusetime > 0.2 || force))
4679                 {
4680                         if (r->fbo)
4681                                 R_Mesh_DestroyFramebufferObject(r->fbo);
4682                         for (j = 0; j < sizeof(r->colortexture) / sizeof(r->colortexture[0]); j++)
4683                                 if (r->colortexture[j])
4684                                         R_FreeTexture(r->colortexture[j]);
4685                         if (r->depthtexture)
4686                                 R_FreeTexture(r->depthtexture);
4687                         Mem_ExpandableArray_FreeRecord(&r_fb.rendertargets, r);
4688                 }
4689         }
4690 }
4691
4692 static void R_CalcTexCoordsForView(float x, float y, float w, float h, float tw, float th, float *texcoord2f)
4693 {
4694         float iw = 1.0f / tw, ih = 1.0f / th, x1, y1, x2, y2;
4695         x1 = x * iw;
4696         x2 = (x + w) * iw;
4697         y1 = (th - y) * ih;
4698         y2 = (th - y - h) * ih;
4699         texcoord2f[0] = x1;
4700         texcoord2f[2] = x2;
4701         texcoord2f[4] = x2;
4702         texcoord2f[6] = x1;
4703         texcoord2f[1] = y1;
4704         texcoord2f[3] = y1;
4705         texcoord2f[5] = y2;
4706         texcoord2f[7] = y2;
4707 }
4708
4709 r_rendertarget_t *R_RenderTarget_Get(int texturewidth, int textureheight, textype_t depthtextype, qboolean depthisrenderbuffer, textype_t colortextype0, textype_t colortextype1, textype_t colortextype2, textype_t colortextype3)
4710 {
4711         int i, j, end;
4712         r_rendertarget_t *r = NULL;
4713         char vabuf[256];
4714         // first try to reuse an existing slot if possible
4715         end = Mem_ExpandableArray_IndexRange(&r_fb.rendertargets);
4716         for (i = 0; i < end; i++)
4717         {
4718                 r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4719                 if (r && r->lastusetime != realtime && r->texturewidth == texturewidth && r->textureheight == textureheight && r->depthtextype == depthtextype && r->colortextype[0] == colortextype0 && r->colortextype[1] == colortextype1 && r->colortextype[2] == colortextype2 && r->colortextype[3] == colortextype3)
4720                         break;
4721         }
4722         if (i == end)
4723         {
4724                 // no unused exact match found, so we have to make one in the first unused slot
4725                 r = (r_rendertarget_t *)Mem_ExpandableArray_AllocRecord(&r_fb.rendertargets);
4726                 r->texturewidth = texturewidth;
4727                 r->textureheight = textureheight;
4728                 r->colortextype[0] = colortextype0;
4729                 r->colortextype[1] = colortextype1;
4730                 r->colortextype[2] = colortextype2;
4731                 r->colortextype[3] = colortextype3;
4732                 r->depthtextype = depthtextype;
4733                 r->depthisrenderbuffer = depthisrenderbuffer;
4734                 for (j = 0; j < 4; j++)
4735                         if (r->colortextype[j])
4736                                 r->colortexture[j] = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "rendertarget%i_%i_type%i", i, j, (int)r->colortextype[j]), r->texturewidth, r->textureheight, NULL, r->colortextype[j], TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
4737                 if (r->depthtextype)
4738                 {
4739                         if (r->depthisrenderbuffer)
4740                                 r->depthtexture = R_LoadTextureRenderBuffer(r_main_texturepool, va(vabuf, sizeof(vabuf), "renderbuffer%i_depth_type%i", i, (int)r->depthtextype), r->texturewidth, r->textureheight, r->depthtextype);
4741                         else
4742                                 r->depthtexture = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "rendertarget%i_depth_type%i", i, j, (int)r->depthtextype), r->texturewidth, r->textureheight, NULL, r->depthtextype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
4743                 }
4744                 r->fbo = R_Mesh_CreateFramebufferObject(r->depthtexture, r->colortexture[0], r->colortexture[1], r->colortexture[2], r->colortexture[3]);
4745         }
4746         r_refdef.stats[r_stat_rendertargets_used]++;
4747         r_refdef.stats[r_stat_rendertargets_pixels] += r->texturewidth * r->textureheight;
4748         r->lastusetime = realtime;
4749         R_CalcTexCoordsForView(0, 0, r->texturewidth, r->textureheight, r->texturewidth, r->textureheight, r->texcoord2f);
4750         return r;
4751 }
4752
4753 static void R_Water_StartFrame(void)
4754 {
4755         int waterwidth, waterheight;
4756
4757         if (vid.width > (int)vid.maxtexturesize_2d || vid.height > (int)vid.maxtexturesize_2d)
4758                 return;
4759
4760         // set waterwidth and waterheight to the water resolution that will be
4761         // used (often less than the screen resolution for faster rendering)
4762         waterwidth = (int)bound(1, r_refdef.view.width * r_water_resolutionmultiplier.value, r_refdef.view.width);
4763         waterheight = (int)bound(1, r_refdef.view.height * r_water_resolutionmultiplier.value, r_refdef.view.height);
4764         R_GetScaledViewSize(waterwidth, waterheight, &waterwidth, &waterheight);
4765
4766         if (!r_water.integer || r_showsurfaces.integer)
4767                 waterwidth = waterheight = 0;
4768
4769         // set up variables that will be used in shader setup
4770         r_fb.water.waterwidth = waterwidth;
4771         r_fb.water.waterheight = waterheight;
4772         r_fb.water.texturewidth = waterwidth;
4773         r_fb.water.textureheight = waterheight;
4774         r_fb.water.camerawidth = waterwidth;
4775         r_fb.water.cameraheight = waterheight;
4776         r_fb.water.screenscale[0] = 0.5f;
4777         r_fb.water.screenscale[1] = 0.5f;
4778         r_fb.water.screencenter[0] = 0.5f;
4779         r_fb.water.screencenter[1] = 0.5f;
4780         r_fb.water.enabled = waterwidth != 0;
4781
4782         r_fb.water.maxwaterplanes = MAX_WATERPLANES;
4783         r_fb.water.numwaterplanes = 0;
4784 }
4785
4786 void R_Water_AddWaterPlane(msurface_t *surface, int entno)
4787 {
4788         int planeindex, bestplaneindex, vertexindex;
4789         vec3_t mins, maxs, normal, center, v, n;
4790         vec_t planescore, bestplanescore;
4791         mplane_t plane;
4792         r_waterstate_waterplane_t *p;
4793         texture_t *t = R_GetCurrentTexture(surface->texture);
4794
4795         rsurface.texture = t;
4796         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, 1, ((const msurface_t **)&surface));
4797         // if the model has no normals, it's probably off-screen and they were not generated, so don't add it anyway
4798         if (!rsurface.batchnormal3f || rsurface.batchnumvertices < 1)
4799                 return;
4800         // average the vertex normals, find the surface bounds (after deformvertexes)
4801         Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f, v);
4802         Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f, n);
4803         VectorCopy(n, normal);
4804         VectorCopy(v, mins);
4805         VectorCopy(v, maxs);
4806         for (vertexindex = 1;vertexindex < rsurface.batchnumvertices;vertexindex++)
4807         {
4808                 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f + vertexindex*3, v);
4809                 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f + vertexindex*3, n);
4810                 VectorAdd(normal, n, normal);
4811                 mins[0] = min(mins[0], v[0]);
4812                 mins[1] = min(mins[1], v[1]);
4813                 mins[2] = min(mins[2], v[2]);
4814                 maxs[0] = max(maxs[0], v[0]);
4815                 maxs[1] = max(maxs[1], v[1]);
4816                 maxs[2] = max(maxs[2], v[2]);
4817         }
4818         VectorNormalize(normal);
4819         VectorMAM(0.5f, mins, 0.5f, maxs, center);
4820
4821         VectorCopy(normal, plane.normal);
4822         VectorNormalize(plane.normal);
4823         plane.dist = DotProduct(center, plane.normal);
4824         PlaneClassify(&plane);
4825         if (PlaneDiff(r_refdef.view.origin, &plane) < 0)
4826         {
4827                 // skip backfaces (except if nocullface is set)
4828 //              if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE))
4829 //                      return;
4830                 VectorNegate(plane.normal, plane.normal);
4831                 plane.dist *= -1;
4832                 PlaneClassify(&plane);
4833         }
4834
4835
4836         // find a matching plane if there is one
4837         bestplaneindex = -1;
4838         bestplanescore = 1048576.0f;
4839         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4840         {
4841                 if(p->camera_entity == t->camera_entity)
4842                 {
4843                         planescore = 1.0f - DotProduct(plane.normal, p->plane.normal) + fabs(plane.dist - p->plane.dist) * 0.001f;
4844                         if (bestplaneindex < 0 || bestplanescore > planescore)
4845                         {
4846                                 bestplaneindex = planeindex;
4847                                 bestplanescore = planescore;
4848                         }
4849                 }
4850         }
4851         planeindex = bestplaneindex;
4852
4853         // if this surface does not fit any known plane rendered this frame, add one
4854         if (planeindex < 0 || bestplanescore > 0.001f)
4855         {
4856                 if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
4857                 {
4858                         // store the new plane
4859                         planeindex = r_fb.water.numwaterplanes++;
4860                         p = r_fb.water.waterplanes + planeindex;
4861                         p->plane = plane;
4862                         // clear materialflags and pvs
4863                         p->materialflags = 0;
4864                         p->pvsvalid = false;
4865                         p->camera_entity = t->camera_entity;
4866                         VectorCopy(mins, p->mins);
4867                         VectorCopy(maxs, p->maxs);
4868                 }
4869                 else
4870                 {
4871                         // We're totally screwed.
4872                         return;
4873                 }
4874         }
4875         else
4876         {
4877                 // merge mins/maxs when we're adding this surface to the plane
4878                 p = r_fb.water.waterplanes + planeindex;
4879                 p->mins[0] = min(p->mins[0], mins[0]);
4880                 p->mins[1] = min(p->mins[1], mins[1]);
4881                 p->mins[2] = min(p->mins[2], mins[2]);
4882                 p->maxs[0] = max(p->maxs[0], maxs[0]);
4883                 p->maxs[1] = max(p->maxs[1], maxs[1]);
4884                 p->maxs[2] = max(p->maxs[2], maxs[2]);
4885         }
4886         // merge this surface's materialflags into the waterplane
4887         p->materialflags |= t->currentmaterialflags;
4888         if(!(p->materialflags & MATERIALFLAG_CAMERA))
4889         {
4890                 // merge this surface's PVS into the waterplane
4891                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
4892                  && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
4893                 {
4894                         r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
4895                         p->pvsvalid = true;
4896                 }
4897         }
4898 }
4899
4900 extern cvar_t r_drawparticles;
4901 extern cvar_t r_drawdecals;
4902
4903 static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int viewx, int viewy, int viewwidth, int viewheight)
4904 {
4905         int myscissor[4];
4906         r_refdef_view_t originalview;
4907         r_refdef_view_t myview;
4908         int planeindex, qualityreduction = 0, old_r_dynamic = 0, old_r_shadows = 0, old_r_worldrtlight = 0, old_r_dlight = 0, old_r_particles = 0, old_r_decals = 0;
4909         r_waterstate_waterplane_t *p;
4910         vec3_t visorigin;
4911         r_rendertarget_t *rt;
4912
4913         originalview = r_refdef.view;
4914
4915         // lowquality hack, temporarily shut down some cvars and restore afterwards
4916         qualityreduction = r_water_lowquality.integer;
4917         if (qualityreduction > 0)
4918         {
4919                 if (qualityreduction >= 1)
4920                 {
4921                         old_r_shadows = r_shadows.integer;
4922                         old_r_worldrtlight = r_shadow_realtime_world.integer;
4923                         old_r_dlight = r_shadow_realtime_dlight.integer;
4924                         Cvar_SetValueQuick(&r_shadows, 0);
4925                         Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
4926                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, 0);
4927                 }
4928                 if (qualityreduction >= 2)
4929                 {
4930                         old_r_dynamic = r_dynamic.integer;
4931                         old_r_particles = r_drawparticles.integer;
4932                         old_r_decals = r_drawdecals.integer;
4933                         Cvar_SetValueQuick(&r_dynamic, 0);
4934                         Cvar_SetValueQuick(&r_drawparticles, 0);
4935                         Cvar_SetValueQuick(&r_drawdecals, 0);
4936                 }
4937         }
4938
4939         for (planeindex = 0, p = r_fb.water.waterplanes; planeindex < r_fb.water.numwaterplanes; planeindex++, p++)
4940         {
4941                 p->rt_reflection = NULL;
4942                 p->rt_refraction = NULL;
4943                 p->rt_camera = NULL;
4944         }
4945
4946         // render views
4947         r_refdef.view = originalview;
4948         r_refdef.view.showdebug = false;
4949         r_refdef.view.width = r_fb.water.waterwidth;
4950         r_refdef.view.height = r_fb.water.waterheight;
4951         r_refdef.view.useclipplane = true;
4952         myview = r_refdef.view;
4953         r_fb.water.renderingscene = true;
4954         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4955         {
4956                 if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
4957                         continue;
4958
4959                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
4960                 {
4961                         rt = R_RenderTarget_Get(r_fb.water.waterwidth, r_fb.water.waterheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, r_fb.rt_screen->colortextype[0], TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
4962                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4963                                 goto error;
4964                         r_refdef.view = myview;
4965                         Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
4966                         Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
4967                         if(r_water_scissormode.integer)
4968                         {
4969                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4970                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4971                                 {
4972                                         p->rt_reflection = NULL;
4973                                         p->rt_refraction = NULL;
4974                                         p->rt_camera = NULL;
4975                                         continue;
4976                                 }
4977                         }
4978
4979                         r_refdef.view.clipplane = p->plane;
4980                         // reflected view origin may be in solid, so don't cull with it
4981                         r_refdef.view.usevieworiginculling = false;
4982                         // reverse the cullface settings for this render
4983                         r_refdef.view.cullface_front = GL_FRONT;
4984                         r_refdef.view.cullface_back = GL_BACK;
4985                         // combined pvs (based on what can be seen from each surface center)
4986                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4987                         {
4988                                 r_refdef.view.usecustompvs = true;
4989                                 if (p->pvsvalid)
4990                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4991                                 else
4992                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4993                         }
4994
4995                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 2) && !chase_active.integer);
4996                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4997                         GL_ScissorTest(false);
4998                         R_ClearScreen(r_refdef.fogenabled);
4999                         GL_ScissorTest(true);
5000                         if(r_water_scissormode.integer & 2)
5001                                 R_View_UpdateWithScissor(myscissor);
5002                         else
5003                                 R_View_Update();
5004                         R_AnimCache_CacheVisibleEntities();
5005                         if(r_water_scissormode.integer & 1)
5006                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
5007                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5008
5009                         r_fb.water.hideplayer = false;
5010                         p->rt_reflection = rt;
5011                 }
5012
5013                 // render the normal view scene and copy into texture
5014                 // (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)
5015                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
5016                 {
5017                         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);
5018                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
5019                                 goto error;
5020                         r_refdef.view = myview;
5021                         if(r_water_scissormode.integer)
5022                         {
5023                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
5024                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
5025                                 {
5026                                         p->rt_reflection = NULL;
5027                                         p->rt_refraction = NULL;
5028                                         p->rt_camera = NULL;
5029                                         continue;
5030                                 }
5031                         }
5032
5033                         // combined pvs (based on what can be seen from each surface center)
5034                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
5035                         {
5036                                 r_refdef.view.usecustompvs = true;
5037                                 if (p->pvsvalid)
5038                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
5039                                 else
5040                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
5041                         }
5042
5043                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
5044
5045                         r_refdef.view.clipplane = p->plane;
5046                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5047                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5048
5049                         if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity)
5050                         {
5051                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5052                                 r_fb.water.hideplayer = false; // we don't want to hide the player model from these ones
5053                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5054                                 R_RenderView_UpdateViewVectors();
5055                                 if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5056                                 {
5057                                         r_refdef.view.usecustompvs = true;
5058                                         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);
5059                                 }
5060                         }
5061
5062                         PlaneClassify(&r_refdef.view.clipplane);
5063
5064                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5065                         GL_ScissorTest(false);
5066                         R_ClearScreen(r_refdef.fogenabled);
5067                         GL_ScissorTest(true);
5068                         if(r_water_scissormode.integer & 2)
5069                                 R_View_UpdateWithScissor(myscissor);
5070                         else
5071                                 R_View_Update();
5072                         R_AnimCache_CacheVisibleEntities();
5073                         if(r_water_scissormode.integer & 1)
5074                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
5075                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5076
5077                         r_fb.water.hideplayer = false;
5078                         p->rt_refraction = rt;
5079                 }
5080                 else if (p->materialflags & MATERIALFLAG_CAMERA)
5081                 {
5082                         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);
5083                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
5084                                 goto error;
5085                         r_refdef.view = myview;
5086
5087                         r_refdef.view.clipplane = p->plane;
5088                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
5089                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
5090
5091                         r_refdef.view.width = r_fb.water.camerawidth;
5092                         r_refdef.view.height = r_fb.water.cameraheight;
5093                         r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0);
5094                         r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0);
5095                         r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView
5096                         r_refdef.view.ortho_y = 90; // abused as angle by VM_CL_R_SetView
5097
5098                         if(p->camera_entity)
5099                         {
5100                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
5101                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
5102                         }
5103
5104                         // note: all of the view is used for displaying... so
5105                         // there is no use in scissoring
5106
5107                         // reverse the cullface settings for this render
5108                         r_refdef.view.cullface_front = GL_FRONT;
5109                         r_refdef.view.cullface_back = GL_BACK;
5110                         // also reverse the view matrix
5111                         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
5112                         R_RenderView_UpdateViewVectors();
5113                         if(p->camera_entity && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
5114                         {
5115                                 r_refdef.view.usecustompvs = true;
5116                                 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);
5117                         }
5118                         
5119                         // camera needs no clipplane
5120                         r_refdef.view.useclipplane = false;
5121                         // TODO: is the camera origin always valid?  if so we don't need to clear this
5122                         r_refdef.view.usevieworiginculling = false;
5123
5124                         PlaneClassify(&r_refdef.view.clipplane);
5125
5126                         r_fb.water.hideplayer = false;
5127
5128                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5129                         GL_ScissorTest(false);
5130                         R_ClearScreen(r_refdef.fogenabled);
5131                         GL_ScissorTest(true);
5132                         R_View_Update();
5133                         R_AnimCache_CacheVisibleEntities();
5134                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5135
5136                         r_fb.water.hideplayer = false;
5137                         p->rt_camera = rt;
5138                 }
5139
5140         }
5141         r_fb.water.renderingscene = false;
5142         r_refdef.view = originalview;
5143         R_ResetViewRendering3D(fbo, depthtexture, colortexture, viewx, viewy, viewwidth, viewheight);
5144         R_View_Update();
5145         R_AnimCache_CacheVisibleEntities();
5146         goto finish;
5147 error:
5148         r_refdef.view = originalview;
5149         r_fb.water.renderingscene = false;
5150         Cvar_SetValueQuick(&r_water, 0);
5151         Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed!  Turned off r_water.\n");
5152 finish:
5153         // lowquality hack, restore cvars
5154         if (qualityreduction > 0)
5155         {
5156                 if (qualityreduction >= 1)
5157                 {
5158                         Cvar_SetValueQuick(&r_shadows, old_r_shadows);
5159                         Cvar_SetValueQuick(&r_shadow_realtime_world, old_r_worldrtlight);
5160                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, old_r_dlight);
5161                 }
5162                 if (qualityreduction >= 2)
5163                 {
5164                         Cvar_SetValueQuick(&r_dynamic, old_r_dynamic);
5165                         Cvar_SetValueQuick(&r_drawparticles, old_r_particles);
5166                         Cvar_SetValueQuick(&r_drawdecals, old_r_decals);
5167                 }
5168         }
5169 }
5170
5171 static void R_Bloom_StartFrame(void)
5172 {
5173         int bloomtexturewidth, bloomtextureheight, screentexturewidth, screentextureheight;
5174         int viewwidth, viewheight;
5175         textype_t textype = TEXTYPE_COLORBUFFER;
5176
5177         // clear the pointers to rendertargets from last frame as they're stale
5178         r_fb.rt_screen = NULL;
5179         r_fb.rt_bloom = NULL;
5180
5181         switch (vid.renderpath)
5182         {
5183         case RENDERPATH_GL20:
5184                 r_fb.usedepthtextures = r_usedepthtextures.integer != 0;
5185                 if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
5186                 if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
5187                 // for simplicity, bloom requires FBO render to texture, which basically all video drivers support now
5188                 if (!vid.support.ext_framebuffer_object)
5189                         return;
5190                 break;
5191         case RENDERPATH_GLES2:
5192                 r_fb.usedepthtextures = false;
5193                 break;
5194         }
5195
5196         if (r_viewscale_fpsscaling.integer)
5197         {
5198                 double actualframetime;
5199                 double targetframetime;
5200                 double adjust;
5201                 actualframetime = r_refdef.lastdrawscreentime;
5202                 targetframetime = (1.0 / r_viewscale_fpsscaling_target.value);
5203                 adjust = (targetframetime - actualframetime) * r_viewscale_fpsscaling_multiply.value;
5204                 adjust = bound(-r_viewscale_fpsscaling_stepmax.value, adjust, r_viewscale_fpsscaling_stepmax.value);
5205                 if (r_viewscale_fpsscaling_stepsize.value > 0)
5206                         adjust = (int)(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5207                 viewscalefpsadjusted += adjust;
5208                 viewscalefpsadjusted = bound(r_viewscale_fpsscaling_min.value, viewscalefpsadjusted, 1.0f);
5209         }
5210         else
5211                 viewscalefpsadjusted = 1.0f;
5212
5213         R_GetScaledViewSize(r_refdef.view.width, r_refdef.view.height, &viewwidth, &viewheight);
5214
5215         // set bloomwidth and bloomheight to the bloom resolution that will be
5216         // used (often less than the screen resolution for faster rendering)
5217         r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, vid.width);
5218         r_fb.bloomheight = r_fb.bloomwidth * vid.height / vid.width;
5219         r_fb.bloomheight = bound(1, r_fb.bloomheight, vid.height);
5220         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d);
5221         r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d);
5222
5223         // calculate desired texture sizes
5224         screentexturewidth = viewwidth;
5225         screentextureheight = viewheight;
5226         bloomtexturewidth = r_fb.bloomwidth;
5227         bloomtextureheight = r_fb.bloomheight;
5228
5229         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))
5230         {
5231                 Cvar_SetValueQuick(&r_bloom, 0);
5232                 Cvar_SetValueQuick(&r_motionblur, 0);
5233                 Cvar_SetValueQuick(&r_damageblur, 0);
5234         }
5235
5236         // allocate motionblur ghost texture if needed - this is the only persistent texture and is only useful on the main view
5237         if (r_refdef.view.ismain && (r_fb.screentexturewidth != screentexturewidth || r_fb.screentextureheight != screentextureheight || r_fb.textype != textype))
5238         {
5239                 if (r_fb.ghosttexture)
5240                         R_FreeTexture(r_fb.ghosttexture);
5241                 r_fb.ghosttexture = NULL;
5242
5243                 r_fb.screentexturewidth = screentexturewidth;
5244                 r_fb.screentextureheight = screentextureheight;
5245                 r_fb.textype = textype;
5246
5247                 if (r_fb.screentexturewidth && r_fb.screentextureheight)
5248                 {
5249                         if (r_motionblur.value > 0 || r_damageblur.value > 0)
5250                                 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);
5251                         r_fb.ghosttexture_valid = false;
5252                 }
5253         }
5254
5255         if (r_bloom.integer)
5256         {
5257                 // bloom texture is a different resolution
5258                 r_fb.bloomwidth = bound(1, r_bloom_resolution.integer, r_refdef.view.width);
5259                 r_fb.bloomheight = r_fb.bloomwidth * r_refdef.view.height / r_refdef.view.width;
5260                 r_fb.bloomheight = bound(1, r_fb.bloomheight, r_refdef.view.height);
5261         }
5262         else
5263                 r_fb.bloomwidth = r_fb.bloomheight = 0;
5264
5265         r_fb.rt_screen = R_RenderTarget_Get(screentexturewidth, screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5266
5267         r_refdef.view.clear = true;
5268 }
5269
5270 static void R_Bloom_MakeTexture(void)
5271 {
5272         int x, range, dir;
5273         float xoffset, yoffset, r, brighten;
5274         float colorscale = r_bloom_colorscale.value;
5275         r_viewport_t bloomviewport;
5276         r_rendertarget_t *prev, *cur;
5277         textype_t textype = r_fb.rt_screen->colortextype[0];
5278
5279         r_refdef.stats[r_stat_bloom]++;
5280
5281         R_Viewport_InitOrtho(&bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
5282
5283         // scale down screen texture to the bloom texture size
5284         CHECKGLERROR
5285         prev = r_fb.rt_screen;
5286         cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5287         R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5288         R_SetViewport(&bloomviewport);
5289         GL_CullFace(GL_NONE);
5290         GL_DepthTest(false);
5291         GL_BlendFunc(GL_ONE, GL_ZERO);
5292         GL_Color(colorscale, colorscale, colorscale, 1);
5293         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5294         // TODO: do boxfilter scale-down in shader?
5295         R_SetupShader_Generic(prev->colortexture[0], NULL, GL_MODULATE, 1, false, true, true);
5296         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5297         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5298         // we now have a properly scaled bloom image
5299
5300         // multiply bloom image by itself as many times as desired to darken it
5301         // TODO: if people actually use this it could be done more quickly in the previous shader pass
5302         for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
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                 x *= 2;
5308                 r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1
5309                 if(x <= 2)
5310                         GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 128);
5311                 GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
5312                 GL_Color(1,1,1,1); // no fix factor supported here
5313                 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5314                 R_SetupShader_Generic(prev->colortexture[0], NULL, GL_MODULATE, 1, false, true, false);
5315                 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5316                 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5317         }
5318
5319         range = r_bloom_blur.integer * r_fb.bloomwidth / 320;
5320         brighten = r_bloom_brighten.value;
5321         brighten = sqrt(brighten);
5322         if(range >= 1)
5323                 brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
5324
5325         for (dir = 0;dir < 2;dir++)
5326         {
5327                 prev = cur;
5328                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5329                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5330                 // blend on at multiple vertical offsets to achieve a vertical blur
5331                 // TODO: do offset blends using GLSL
5332                 // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
5333                 GL_BlendFunc(GL_ONE, GL_ZERO);
5334                 R_SetupShader_Generic(prev->colortexture[0], NULL, GL_MODULATE, 1, false, true, false);
5335                 for (x = -range;x <= range;x++)
5336                 {
5337                         if (!dir){xoffset = 0;yoffset = x;}
5338                         else {xoffset = x;yoffset = 0;}
5339                         xoffset /= (float)prev->texturewidth;
5340                         yoffset /= (float)prev->textureheight;
5341                         // compute a texcoord array with the specified x and y offset
5342                         r_fb.offsettexcoord2f[0] = xoffset+prev->texcoord2f[0];
5343                         r_fb.offsettexcoord2f[1] = yoffset+prev->texcoord2f[1];
5344                         r_fb.offsettexcoord2f[2] = xoffset+prev->texcoord2f[2];
5345                         r_fb.offsettexcoord2f[3] = yoffset+prev->texcoord2f[3];
5346                         r_fb.offsettexcoord2f[4] = xoffset+prev->texcoord2f[4];
5347                         r_fb.offsettexcoord2f[5] = yoffset+prev->texcoord2f[5];
5348                         r_fb.offsettexcoord2f[6] = xoffset+prev->texcoord2f[6];
5349                         r_fb.offsettexcoord2f[7] = yoffset+prev->texcoord2f[7];
5350                         // this r value looks like a 'dot' particle, fading sharply to
5351                         // black at the edges
5352                         // (probably not realistic but looks good enough)
5353                         //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
5354                         //r = brighten/(range*2+1);
5355                         r = brighten / (range * 2 + 1);
5356                         if(range >= 1)
5357                                 r *= (1 - x*x/(float)((range+1)*(range+1)));
5358                         if (r <= 0)
5359                                 continue;
5360                         GL_Color(r, r, r, 1);
5361                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f);
5362                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5363                         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5364                         GL_BlendFunc(GL_ONE, GL_ONE);
5365                 }
5366         }
5367
5368         // now we have the bloom image, so keep track of it
5369         r_fb.rt_bloom = cur;
5370 }
5371
5372 static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5373 {
5374         dpuint64 permutation;
5375         float uservecs[4][4];
5376         rtexture_t *viewtexture;
5377         rtexture_t *bloomtexture;
5378
5379         R_EntityMatrix(&identitymatrix);
5380
5381         if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
5382         {
5383                 // declare variables
5384                 float blur_factor, blur_mouseaccel, blur_velocity;
5385                 static float blur_average; 
5386                 static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
5387
5388                 // set a goal for the factoring
5389                 blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value) 
5390                         / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
5391                 blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value) 
5392                         / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
5393                 blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value) 
5394                         + (blur_mouseaccel * r_motionblur_mousefactor.value));
5395
5396                 // from the goal, pick an averaged value between goal and last value
5397                 cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
5398                 blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
5399
5400                 // enforce minimum amount of blur 
5401                 blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
5402
5403                 //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
5404
5405                 // calculate values into a standard alpha
5406                 cl.motionbluralpha = 1 - exp(-
5407                                 (
5408                                         (r_motionblur.value * blur_factor / 80)
5409                                         +
5410                                         (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
5411                                 )
5412                                 /
5413                                 max(0.0001, cl.time - cl.oldtime) // fps independent
5414                                 );
5415
5416                 // randomization for the blur value to combat persistent ghosting
5417                 cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
5418                 cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
5419
5420                 // apply the blur
5421                 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5422                 if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
5423                 {
5424                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5425                         GL_Color(1, 1, 1, cl.motionbluralpha);
5426                         R_CalcTexCoordsForView(0, 0, viewwidth, viewheight, viewwidth, viewheight, r_fb.ghosttexcoord2f);
5427                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.ghosttexcoord2f);
5428                         R_SetupShader_Generic(r_fb.ghosttexture, NULL, GL_MODULATE, 1, false, true, true);
5429                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5430                         r_refdef.stats[r_stat_bloom_drawpixels] += viewwidth * viewheight;
5431                 }
5432
5433                 // updates old view angles for next pass
5434                 VectorCopy(cl.viewangles, blur_oldangles);
5435
5436                 // copy view into the ghost texture
5437                 R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, viewx, viewy, viewwidth, viewheight);
5438                 r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight;
5439                 r_fb.ghosttexture_valid = true;
5440         }
5441
5442         if (r_fb.bloomwidth)
5443         {
5444                 // make the bloom texture
5445                 R_Bloom_MakeTexture();
5446         }
5447
5448 #if _MSC_VER >= 1400
5449 #define sscanf sscanf_s
5450 #endif
5451         memset(uservecs, 0, sizeof(uservecs));
5452         if (r_glsl_postprocess_uservec1_enable.integer)
5453                 sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
5454         if (r_glsl_postprocess_uservec2_enable.integer)
5455                 sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
5456         if (r_glsl_postprocess_uservec3_enable.integer)
5457                 sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
5458         if (r_glsl_postprocess_uservec4_enable.integer)
5459                 sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
5460
5461         // render to the screen fbo
5462         R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5463         GL_Color(1, 1, 1, 1);
5464         GL_BlendFunc(GL_ONE, GL_ZERO);
5465
5466         viewtexture = r_fb.rt_screen->colortexture[0];
5467         bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL;
5468
5469         if (r_rendertarget_debug.integer >= 0)
5470         {
5471                 r_rendertarget_t *rt = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, r_rendertarget_debug.integer);
5472                 if (rt && rt->colortexture[0])
5473                 {
5474                         viewtexture = rt->colortexture[0];
5475                         bloomtexture = NULL;
5476                 }
5477         }
5478
5479         R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.rt_screen->texcoord2f, bloomtexture ? r_fb.rt_bloom->texcoord2f : NULL);
5480         switch(vid.renderpath)
5481         {
5482         case RENDERPATH_GL20:
5483         case RENDERPATH_GLES2:
5484                 permutation =
5485                         (r_fb.bloomwidth ? SHADERPERMUTATION_BLOOM : 0)
5486                         | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
5487                         | (!vid_gammatables_trivial ? SHADERPERMUTATION_GAMMARAMPS : 0)
5488                         | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
5489                         | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
5490                 R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation);
5491                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First     , viewtexture);
5492                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second    , bloomtexture);
5493                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps       );
5494                 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]);
5495                 if (r_glsl_permutation->loc_PixelSize               >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize         , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
5496                 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]);
5497                 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]);
5498                 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]);
5499                 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]);
5500                 if (r_glsl_permutation->loc_Saturation              >= 0) qglUniform1f(r_glsl_permutation->loc_Saturation        , r_glsl_saturation.value);
5501                 if (r_glsl_permutation->loc_PixelToScreenTexCoord   >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/vid.width, 1.0f/vid.height);
5502                 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);
5503                 break;
5504         }
5505         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5506         r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height;
5507 }
5508
5509 matrix4x4_t r_waterscrollmatrix;
5510
5511 void R_UpdateFog(void)
5512 {
5513         // Nehahra fog
5514         if (gamemode == GAME_NEHAHRA)
5515         {
5516                 if (gl_fogenable.integer)
5517                 {
5518                         r_refdef.oldgl_fogenable = true;
5519                         r_refdef.fog_density = gl_fogdensity.value;
5520                         r_refdef.fog_red = gl_fogred.value;
5521                         r_refdef.fog_green = gl_foggreen.value;
5522                         r_refdef.fog_blue = gl_fogblue.value;
5523                         r_refdef.fog_alpha = 1;
5524                         r_refdef.fog_start = 0;
5525                         r_refdef.fog_end = gl_skyclip.value;
5526                         r_refdef.fog_height = 1<<30;
5527                         r_refdef.fog_fadedepth = 128;
5528                 }
5529                 else if (r_refdef.oldgl_fogenable)
5530                 {
5531                         r_refdef.oldgl_fogenable = false;
5532                         r_refdef.fog_density = 0;
5533                         r_refdef.fog_red = 0;
5534                         r_refdef.fog_green = 0;
5535                         r_refdef.fog_blue = 0;
5536                         r_refdef.fog_alpha = 0;
5537                         r_refdef.fog_start = 0;
5538                         r_refdef.fog_end = 0;
5539                         r_refdef.fog_height = 1<<30;
5540                         r_refdef.fog_fadedepth = 128;
5541                 }
5542         }
5543
5544         // fog parms
5545         r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1);
5546         r_refdef.fog_start = max(0, r_refdef.fog_start);
5547         r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end);
5548
5549         if (r_refdef.fog_density && r_drawfog.integer)
5550         {
5551                 r_refdef.fogenabled = true;
5552                 // this is the point where the fog reaches 0.9986 alpha, which we
5553                 // consider a good enough cutoff point for the texture
5554                 // (0.9986 * 256 == 255.6)
5555                 if (r_fog_exp2.integer)
5556                         r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start;
5557                 else
5558                         r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start;
5559                 r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end);
5560                 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
5561                 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
5562                 if (strcmp(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename))
5563                         R_BuildFogHeightTexture();
5564                 // fog color was already set
5565                 // update the fog texture
5566                 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)
5567                         R_BuildFogTexture();
5568                 r_refdef.fog_height_texcoordscale = 1.0f / max(0.125f, r_refdef.fog_fadedepth);
5569                 r_refdef.fog_height_tablescale = r_refdef.fog_height_tablesize * r_refdef.fog_height_texcoordscale;
5570         }
5571         else
5572                 r_refdef.fogenabled = false;
5573
5574         // fog color
5575         if (r_refdef.fog_density)
5576         {
5577                 r_refdef.fogcolor[0] = r_refdef.fog_red;
5578                 r_refdef.fogcolor[1] = r_refdef.fog_green;
5579                 r_refdef.fogcolor[2] = r_refdef.fog_blue;
5580
5581                 Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height);
5582                 r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3];
5583                 r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0;
5584                 r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth);
5585
5586                 {
5587                         vec3_t fogvec;
5588                         VectorCopy(r_refdef.fogcolor, fogvec);
5589                         //   color.rgb *= ContrastBoost * SceneBrightness;
5590                         VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
5591                         r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
5592                         r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f);
5593                         r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f);
5594                 }
5595         }
5596 }
5597
5598 void R_UpdateVariables(void)
5599 {
5600         R_Textures_Frame();
5601
5602         r_refdef.scene.ambientintensity = r_ambient.value * (1.0f / 64.0f);
5603
5604         r_refdef.farclip = r_farclip_base.value;
5605         if (r_refdef.scene.worldmodel)
5606                 r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2;
5607         r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
5608
5609         if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
5610                 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
5611         r_refdef.polygonfactor = 0;
5612         r_refdef.polygonoffset = 0;
5613         r_refdef.shadowpolygonfactor = r_refdef.polygonfactor + r_shadow_polygonfactor.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
5614         r_refdef.shadowpolygonoffset = r_refdef.polygonoffset + r_shadow_polygonoffset.value * (r_shadow_frontsidecasting.integer ? 1 : -1);
5615
5616         r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
5617         r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil;
5618         r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer;
5619         r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil;
5620         r_refdef.scene.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
5621         if (FAKELIGHT_ENABLED)
5622         {
5623                 r_refdef.scene.lightmapintensity *= r_fakelight_intensity.value;
5624         }
5625         else if (r_refdef.scene.worldmodel)
5626         {
5627                 r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
5628         }
5629         if (r_showsurfaces.integer)
5630         {
5631                 r_refdef.scene.rtworld = false;
5632                 r_refdef.scene.rtworldshadows = false;
5633                 r_refdef.scene.rtdlight = false;
5634                 r_refdef.scene.rtdlightshadows = false;
5635                 r_refdef.scene.lightmapintensity = 0;
5636         }
5637
5638         r_gpuskeletal = false;
5639         switch(vid.renderpath)
5640         {
5641         case RENDERPATH_GL20:
5642                 r_gpuskeletal = vid.support.arb_uniform_buffer_object && r_glsl_skeletal.integer && !r_showsurfaces.integer; // FIXME add r_showsurfaces support to GLSL skeletal!
5643         case RENDERPATH_GLES2:
5644                 if(!vid_gammatables_trivial)
5645                 {
5646                         if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
5647                         {
5648                                 // build GLSL gamma texture
5649 #define RAMPWIDTH 256
5650                                 unsigned short ramp[RAMPWIDTH * 3];
5651                                 unsigned char rampbgr[RAMPWIDTH][4];
5652                                 int i;
5653
5654                                 r_texture_gammaramps_serial = vid_gammatables_serial;
5655
5656                                 VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
5657                                 for(i = 0; i < RAMPWIDTH; ++i)
5658                                 {
5659                                         rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5660                                         rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5661                                         rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
5662                                         rampbgr[i][3] = 0;
5663                                 }
5664                                 if (r_texture_gammaramps)
5665                                 {
5666                                         R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1);
5667                                 }
5668                                 else
5669                                 {
5670                                         r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
5671                                 }
5672                         }
5673                 }
5674                 else
5675                 {
5676                         // remove GLSL gamma texture
5677                 }
5678                 break;
5679         }
5680 }
5681
5682 static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT;
5683 static r_refdef_scene_t r_scenes_store[ RST_COUNT ];
5684 /*
5685 ================
5686 R_SelectScene
5687 ================
5688 */
5689 void R_SelectScene( r_refdef_scene_type_t scenetype ) {
5690         if( scenetype != r_currentscenetype ) {
5691                 // store the old scenetype
5692                 r_scenes_store[ r_currentscenetype ] = r_refdef.scene;
5693                 r_currentscenetype = scenetype;
5694                 // move in the new scene
5695                 r_refdef.scene = r_scenes_store[ r_currentscenetype ];
5696         }
5697 }
5698
5699 /*
5700 ================
5701 R_GetScenePointer
5702 ================
5703 */
5704 r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype )
5705 {
5706         // of course, we could also add a qboolean that provides a lock state and a ReleaseScenePointer function..
5707         if( scenetype == r_currentscenetype ) {
5708                 return &r_refdef.scene;
5709         } else {
5710                 return &r_scenes_store[ scenetype ];
5711         }
5712 }
5713
5714 static int R_SortEntities_Compare(const void *ap, const void *bp)
5715 {
5716         const entity_render_t *a = *(const entity_render_t **)ap;
5717         const entity_render_t *b = *(const entity_render_t **)bp;
5718
5719         // 1. compare model
5720         if(a->model < b->model)
5721                 return -1;
5722         if(a->model > b->model)
5723                 return +1;
5724
5725         // 2. compare skin
5726         // TODO possibly calculate the REAL skinnum here first using
5727         // skinscenes?
5728         if(a->skinnum < b->skinnum)
5729                 return -1;
5730         if(a->skinnum > b->skinnum)
5731                 return +1;
5732
5733         // everything we compared is equal
5734         return 0;
5735 }
5736 static void R_SortEntities(void)
5737 {
5738         // below or equal 2 ents, sorting never gains anything
5739         if(r_refdef.scene.numentities <= 2)
5740                 return;
5741         // sort
5742         qsort(r_refdef.scene.entities, r_refdef.scene.numentities, sizeof(*r_refdef.scene.entities), R_SortEntities_Compare);
5743 }
5744
5745 /*
5746 ================
5747 R_RenderView
5748 ================
5749 */
5750 extern cvar_t r_shadow_bouncegrid;
5751 extern cvar_t v_isometric;
5752 extern void V_MakeViewIsometric(void);
5753 void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5754 {
5755         matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
5756         int viewfbo = 0;
5757         rtexture_t *viewdepthtexture = NULL;
5758         rtexture_t *viewcolortexture = NULL;
5759         int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
5760
5761         // finish any 2D rendering that was queued
5762         DrawQ_Finish();
5763
5764         if (r_timereport_active)
5765                 R_TimeReport("start");
5766         r_textureframe++; // used only by R_GetCurrentTexture
5767         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5768
5769         if(R_CompileShader_CheckStaticParms())
5770                 R_GLSL_Restart_f();
5771
5772         if (!r_drawentities.integer)
5773                 r_refdef.scene.numentities = 0;
5774         else if (r_sortentities.integer)
5775                 R_SortEntities();
5776
5777         R_AnimCache_ClearCache();
5778
5779         /* adjust for stereo display */
5780         if(R_Stereo_Active())
5781         {
5782                 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);
5783                 Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);
5784         }
5785
5786         if (r_refdef.view.isoverlay)
5787         {
5788                 // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
5789                 R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
5790                 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
5791                 R_TimeReport("depthclear");
5792
5793                 r_refdef.view.showdebug = false;
5794
5795                 r_fb.water.enabled = false;
5796                 r_fb.water.numwaterplanes = 0;
5797
5798                 R_RenderScene(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5799
5800                 r_refdef.view.matrix = originalmatrix;
5801
5802                 CHECKGLERROR
5803                 return;
5804         }
5805
5806         if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/)
5807         {
5808                 r_refdef.view.matrix = originalmatrix;
5809                 return;
5810         }
5811
5812         r_refdef.view.usevieworiginculling = !r_trippy.value && r_refdef.view.useperspective;
5813         if (v_isometric.integer && r_refdef.view.ismain)
5814                 V_MakeViewIsometric();
5815
5816         r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value;
5817
5818         if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D)
5819                 // in sRGB fallback, behave similar to true sRGB: convert this
5820                 // value from linear to sRGB
5821                 r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale);
5822
5823         R_RenderView_UpdateViewVectors();
5824
5825         R_Shadow_UpdateWorldLightSelection();
5826
5827         // this will set up r_fb.rt_screen
5828         R_Bloom_StartFrame();
5829
5830         // apply bloom brightness offset
5831         if(r_fb.rt_bloom)
5832                 r_refdef.view.colorscale *= r_bloom_scenebrightness.value;
5833
5834         // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
5835         if (r_fb.rt_screen)
5836         {
5837                 viewfbo = r_fb.rt_screen->fbo;
5838                 viewdepthtexture = r_fb.rt_screen->depthtexture;
5839                 viewcolortexture = r_fb.rt_screen->colortexture[0];
5840                 viewx = 0;
5841                 viewy = 0;
5842                 viewwidth = width;
5843                 viewheight = height;
5844         }
5845
5846         R_Water_StartFrame();
5847
5848         CHECKGLERROR
5849         if (r_timereport_active)
5850                 R_TimeReport("viewsetup");
5851
5852         R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5853
5854         // clear the whole fbo every frame - otherwise the driver will consider
5855         // it to be an inter-frame texture and stall in multi-gpu configurations
5856         if (r_fb.rt_screen)
5857                 GL_ScissorTest(false);
5858         R_ClearScreen(r_refdef.fogenabled);
5859         if (r_timereport_active)
5860                 R_TimeReport("viewclear");
5861
5862         r_refdef.view.clear = true;
5863
5864         r_refdef.view.showdebug = true;
5865
5866         R_View_Update();
5867         if (r_timereport_active)
5868                 R_TimeReport("visibility");
5869
5870         R_AnimCache_CacheVisibleEntities();
5871         if (r_timereport_active)
5872                 R_TimeReport("animcache");
5873
5874         R_Shadow_UpdateBounceGridTexture();
5875         if (r_timereport_active && r_shadow_bouncegrid.integer)
5876                 R_TimeReport("bouncegrid");
5877
5878         r_fb.water.numwaterplanes = 0;
5879         if (r_fb.water.enabled)
5880                 R_RenderWaterPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5881
5882         // for the actual view render we use scissoring a fair amount, so scissor
5883         // test needs to be on
5884         if (r_fb.rt_screen)
5885                 GL_ScissorTest(true);
5886         GL_Scissor(viewx, viewy, viewwidth, viewheight);
5887         R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5888         r_fb.water.numwaterplanes = 0;
5889
5890         // postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring
5891         GL_ScissorTest(false);
5892
5893         R_BlendView(fbo, depthtexture, colortexture, x, y, width, height);
5894         if (r_timereport_active)
5895                 R_TimeReport("blendview");
5896
5897         r_refdef.view.matrix = originalmatrix;
5898
5899         CHECKGLERROR
5900
5901         // go back to 2d rendering
5902         DrawQ_Start();
5903 }
5904
5905 void R_RenderWaterPlanes(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5906 {
5907         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
5908         {
5909                 r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity);
5910                 if (r_timereport_active)
5911                         R_TimeReport("waterworld");
5912         }
5913
5914         // don't let sound skip if going slow
5915         if (r_refdef.scene.extraupdate)
5916                 S_ExtraUpdate ();
5917
5918         R_DrawModelsAddWaterPlanes();
5919         if (r_timereport_active)
5920                 R_TimeReport("watermodels");
5921
5922         if (r_fb.water.numwaterplanes)
5923         {
5924                 R_Water_ProcessPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5925                 if (r_timereport_active)
5926                         R_TimeReport("waterscenes");
5927         }
5928 }
5929
5930 extern cvar_t cl_locs_show;
5931 static void R_DrawLocs(void);
5932 static void R_DrawEntityBBoxes(prvm_prog_t *prog);
5933 static void R_DrawModelDecals(void);
5934 extern cvar_t cl_decals_newsystem;
5935 extern qboolean r_shadow_usingdeferredprepass;
5936 extern int r_shadow_shadowmapatlas_modelshadows_size;
5937 void R_RenderScene(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5938 {
5939         qboolean shadowmapping = false;
5940
5941         if (r_timereport_active)
5942                 R_TimeReport("beginscene");
5943
5944         r_refdef.stats[r_stat_renders]++;
5945
5946         R_UpdateFog();
5947
5948         // don't let sound skip if going slow
5949         if (r_refdef.scene.extraupdate)
5950                 S_ExtraUpdate ();
5951
5952         R_MeshQueue_BeginScene();
5953
5954         R_SkyStartFrame();
5955
5956         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);
5957
5958         if (r_timereport_active)
5959                 R_TimeReport("skystartframe");
5960
5961         if (cl.csqc_vidvars.drawworld)
5962         {
5963                 // don't let sound skip if going slow
5964                 if (r_refdef.scene.extraupdate)
5965                         S_ExtraUpdate ();
5966
5967                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawSky)
5968                 {
5969                         r_refdef.scene.worldmodel->DrawSky(r_refdef.scene.worldentity);
5970                         if (r_timereport_active)
5971                                 R_TimeReport("worldsky");
5972                 }
5973
5974                 if (R_DrawBrushModelsSky() && r_timereport_active)
5975                         R_TimeReport("bmodelsky");
5976
5977                 if (skyrendermasked && skyrenderlater)
5978                 {
5979                         // we have to force off the water clipping plane while rendering sky
5980                         R_SetupView(false, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5981                         R_Sky();
5982                         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5983                         if (r_timereport_active)
5984                                 R_TimeReport("sky");
5985                 }
5986         }
5987
5988         // save the framebuffer info for R_Shadow_RenderMode_Reset during this view render
5989         r_shadow_viewfbo = viewfbo;
5990         r_shadow_viewdepthtexture = viewdepthtexture;
5991         r_shadow_viewcolortexture = viewcolortexture;
5992         r_shadow_viewx = viewx;
5993         r_shadow_viewy = viewy;
5994         r_shadow_viewwidth = viewwidth;
5995         r_shadow_viewheight = viewheight;
5996
5997         R_Shadow_PrepareModelShadows();
5998         R_Shadow_PrepareLights();
5999         if (r_timereport_active)
6000                 R_TimeReport("preparelights");
6001
6002         // render all the shadowmaps that will be used for this view
6003         shadowmapping = R_Shadow_ShadowMappingEnabled();
6004         if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
6005         {
6006                 R_Shadow_DrawShadowMaps();
6007                 if (r_timereport_active)
6008                         R_TimeReport("shadowmaps");
6009         }
6010
6011         // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
6012         if (r_shadow_usingdeferredprepass)
6013                 R_Shadow_DrawPrepass();
6014
6015         // now we begin the forward pass of the view render
6016         if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
6017         {
6018                 r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
6019                 if (r_timereport_active)
6020                         R_TimeReport("worlddepth");
6021         }
6022         if (r_depthfirst.integer >= 2)
6023         {
6024                 R_DrawModelsDepth();
6025                 if (r_timereport_active)
6026                         R_TimeReport("modeldepth");
6027         }
6028
6029         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
6030         {
6031                 r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
6032                 if (r_timereport_active)
6033                         R_TimeReport("world");
6034         }
6035
6036         // don't let sound skip if going slow
6037         if (r_refdef.scene.extraupdate)
6038                 S_ExtraUpdate ();
6039
6040         R_DrawModels();
6041         if (r_timereport_active)
6042                 R_TimeReport("models");
6043
6044         // don't let sound skip if going slow
6045         if (r_refdef.scene.extraupdate)
6046                 S_ExtraUpdate ();
6047
6048         if ((r_shadows.integer == 1 || (r_shadows.integer > 0 && !shadowmapping)) && !r_shadows_drawafterrtlighting.integer && r_refdef.scene.lightmapintensity > 0)
6049         {
6050                 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
6051                 R_Shadow_DrawModelShadows();
6052                 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
6053                 // don't let sound skip if going slow
6054                 if (r_refdef.scene.extraupdate)
6055                         S_ExtraUpdate ();
6056         }
6057
6058         if (!r_shadow_usingdeferredprepass)
6059         {
6060                 R_Shadow_DrawLights();
6061                 if (r_timereport_active)
6062                         R_TimeReport("rtlights");
6063         }
6064
6065         // don't let sound skip if going slow
6066         if (r_refdef.scene.extraupdate)
6067                 S_ExtraUpdate ();
6068
6069         if ((r_shadows.integer == 1 || (r_shadows.integer > 0 && !shadowmapping)) && r_shadows_drawafterrtlighting.integer && r_refdef.scene.lightmapintensity > 0)
6070         {
6071                 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
6072                 R_Shadow_DrawModelShadows();
6073                 R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
6074                 // don't let sound skip if going slow
6075                 if (r_refdef.scene.extraupdate)
6076                         S_ExtraUpdate ();
6077         }
6078
6079         if (cl.csqc_vidvars.drawworld)
6080         {
6081                 if (cl_decals_newsystem.integer)
6082                 {
6083                         R_DrawModelDecals();
6084                         if (r_timereport_active)
6085                                 R_TimeReport("modeldecals");
6086                 }
6087                 else
6088                 {
6089                         R_DrawDecals();
6090                         if (r_timereport_active)
6091                                 R_TimeReport("decals");
6092                 }
6093
6094                 R_DrawParticles();
6095                 if (r_timereport_active)
6096                         R_TimeReport("particles");
6097
6098                 R_DrawExplosions();
6099                 if (r_timereport_active)
6100                         R_TimeReport("explosions");
6101         }
6102
6103         if (r_refdef.view.showdebug)
6104         {
6105                 if (cl_locs_show.integer)
6106                 {
6107                         R_DrawLocs();
6108                         if (r_timereport_active)
6109                                 R_TimeReport("showlocs");
6110                 }
6111
6112                 if (r_drawportals.integer)
6113                 {
6114                         R_DrawPortals();
6115                         if (r_timereport_active)
6116                                 R_TimeReport("portals");
6117                 }
6118
6119                 if (r_showbboxes_client.value > 0)
6120                 {
6121                         R_DrawEntityBBoxes(CLVM_prog);
6122                         if (r_timereport_active)
6123                                 R_TimeReport("clbboxes");
6124                 }
6125                 if (r_showbboxes.value > 0)
6126                 {
6127                         R_DrawEntityBBoxes(SVVM_prog);
6128                         if (r_timereport_active)
6129                                 R_TimeReport("svbboxes");
6130                 }
6131         }
6132
6133         if (r_transparent.integer)
6134         {
6135                 R_MeshQueue_RenderTransparent();
6136                 if (r_timereport_active)
6137                         R_TimeReport("drawtrans");
6138         }
6139
6140         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))
6141         {
6142                 r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity);
6143                 if (r_timereport_active)
6144                         R_TimeReport("worlddebug");
6145                 R_DrawModelsDebug();
6146                 if (r_timereport_active)
6147                         R_TimeReport("modeldebug");
6148         }
6149
6150         if (cl.csqc_vidvars.drawworld)
6151         {
6152                 R_Shadow_DrawCoronas();
6153                 if (r_timereport_active)
6154                         R_TimeReport("coronas");
6155         }
6156
6157         // don't let sound skip if going slow
6158         if (r_refdef.scene.extraupdate)
6159                 S_ExtraUpdate ();
6160 }
6161
6162 static const unsigned short bboxelements[36] =
6163 {
6164         5, 1, 3, 5, 3, 7,
6165         6, 2, 0, 6, 0, 4,
6166         7, 3, 2, 7, 2, 6,
6167         4, 0, 1, 4, 1, 5,
6168         4, 5, 7, 4, 7, 6,
6169         1, 0, 2, 1, 2, 3,
6170 };
6171
6172 #define BBOXEDGES 13
6173 static const float bboxedges[BBOXEDGES][6] = 
6174 {
6175         // whole box
6176         { 0, 0, 0, 1, 1, 1 },
6177         // bottom edges
6178         { 0, 0, 0, 0, 1, 0 },
6179         { 0, 0, 0, 1, 0, 0 },
6180         { 0, 1, 0, 1, 1, 0 },
6181         { 1, 0, 0, 1, 1, 0 },
6182         // top edges
6183         { 0, 0, 1, 0, 1, 1 },
6184         { 0, 0, 1, 1, 0, 1 },
6185         { 0, 1, 1, 1, 1, 1 },
6186         { 1, 0, 1, 1, 1, 1 },
6187         // vertical edges
6188         { 0, 0, 0, 0, 0, 1 },
6189         { 1, 0, 0, 1, 0, 1 },
6190         { 0, 1, 0, 0, 1, 1 },
6191         { 1, 1, 0, 1, 1, 1 },
6192 };
6193
6194 static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
6195 {
6196         int numvertices = BBOXEDGES * 8;
6197         float vertex3f[BBOXEDGES * 8 * 3], color4f[BBOXEDGES * 8 * 4];
6198         int numtriangles = BBOXEDGES * 12;
6199         unsigned short elements[BBOXEDGES * 36];
6200         int i, edge;
6201         float *v, *c, f1, f2, edgemins[3], edgemaxs[3];
6202
6203         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6204
6205         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6206         GL_DepthMask(false);
6207         GL_DepthRange(0, 1);
6208         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
6209
6210         for (edge = 0; edge < BBOXEDGES; edge++)
6211         {
6212                 for (i = 0; i < 3; i++)
6213                 {
6214                         edgemins[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][i] - 0.25f;
6215                         edgemaxs[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][3 + i] + 0.25f;
6216                 }
6217                 vertex3f[edge * 24 + 0] = edgemins[0]; vertex3f[edge * 24 + 1] = edgemins[1]; vertex3f[edge * 24 + 2] = edgemins[2];
6218                 vertex3f[edge * 24 + 3] = edgemaxs[0]; vertex3f[edge * 24 + 4] = edgemins[1]; vertex3f[edge * 24 + 5] = edgemins[2];
6219                 vertex3f[edge * 24 + 6] = edgemins[0]; vertex3f[edge * 24 + 7] = edgemaxs[1]; vertex3f[edge * 24 + 8] = edgemins[2];
6220                 vertex3f[edge * 24 + 9] = edgemaxs[0]; vertex3f[edge * 24 + 10] = edgemaxs[1]; vertex3f[edge * 24 + 11] = edgemins[2];
6221                 vertex3f[edge * 24 + 12] = edgemins[0]; vertex3f[edge * 24 + 13] = edgemins[1]; vertex3f[edge * 24 + 14] = edgemaxs[2];
6222                 vertex3f[edge * 24 + 15] = edgemaxs[0]; vertex3f[edge * 24 + 16] = edgemins[1]; vertex3f[edge * 24 + 17] = edgemaxs[2];
6223                 vertex3f[edge * 24 + 18] = edgemins[0]; vertex3f[edge * 24 + 19] = edgemaxs[1]; vertex3f[edge * 24 + 20] = edgemaxs[2];
6224                 vertex3f[edge * 24 + 21] = edgemaxs[0]; vertex3f[edge * 24 + 22] = edgemaxs[1]; vertex3f[edge * 24 + 23] = edgemaxs[2];
6225                 for (i = 0; i < 36; i++)
6226                         elements[edge * 36 + i] = edge * 8 + bboxelements[i];
6227         }
6228         R_FillColors(color4f, numvertices, cr, cg, cb, ca);
6229         if (r_refdef.fogenabled)
6230         {
6231                 for (i = 0, v = vertex3f, c = color4f; i < numvertices; i++, v += 3, c += 4)
6232                 {
6233                         f1 = RSurf_FogVertex(v);
6234                         f2 = 1 - f1;
6235                         c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
6236                         c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
6237                         c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
6238                 }
6239         }
6240         R_Mesh_PrepareVertices_Generic_Arrays(numvertices, vertex3f, color4f, NULL);
6241         R_Mesh_ResetTextureState();
6242         R_SetupShader_Generic_NoTexture(false, false);
6243         R_Mesh_Draw(0, numvertices, 0, numtriangles, NULL, NULL, 0, elements, NULL, 0);
6244 }
6245
6246 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6247 {
6248         // hacky overloading of the parameters
6249         prvm_prog_t *prog = (prvm_prog_t *)rtlight;
6250         int i;
6251         float color[4];
6252         prvm_edict_t *edict;
6253
6254         GL_CullFace(GL_NONE);
6255         R_SetupShader_Generic_NoTexture(false, false);
6256
6257         for (i = 0;i < numsurfaces;i++)
6258         {
6259                 edict = PRVM_EDICT_NUM(surfacelist[i]);
6260                 switch ((int)PRVM_serveredictfloat(edict, solid))
6261                 {
6262                         case SOLID_NOT:      Vector4Set(color, 1, 1, 1, 0.05);break;
6263                         case SOLID_TRIGGER:  Vector4Set(color, 1, 0, 1, 0.10);break;
6264                         case SOLID_BBOX:     Vector4Set(color, 0, 1, 0, 0.10);break;
6265                         case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
6266                         case SOLID_BSP:      Vector4Set(color, 0, 0, 1, 0.05);break;
6267                         case SOLID_CORPSE:   Vector4Set(color, 1, 0.5, 0, 0.05);break;
6268                         default:             Vector4Set(color, 0, 0, 0, 0.50);break;
6269                 }
6270                 if (prog == CLVM_prog)
6271                         color[3] *= r_showbboxes_client.value;
6272                 else
6273                         color[3] *= r_showbboxes.value;
6274                 color[3] = bound(0, color[3], 1);
6275                 GL_DepthTest(!r_showdisabledepthtest.integer);
6276                 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
6277         }
6278 }
6279
6280 static void R_DrawEntityBBoxes(prvm_prog_t *prog)
6281 {
6282         int i;
6283         prvm_edict_t *edict;
6284         vec3_t center;
6285
6286         if (prog == NULL)
6287                 return;
6288
6289         for (i = 0; i < prog->num_edicts; i++)
6290         {
6291                 edict = PRVM_EDICT_NUM(i);
6292                 if (edict->priv.server->free)
6293                         continue;
6294                 // exclude the following for now, as they don't live in world coordinate space and can't be solid:
6295                 if (PRVM_serveredictedict(edict, tag_entity) != 0)
6296                         continue;
6297                 if (PRVM_serveredictedict(edict, viewmodelforclient) != 0)
6298                         continue;
6299                 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
6300                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)prog);
6301         }
6302 }
6303
6304 static const int nomodelelement3i[24] =
6305 {
6306         5, 2, 0,
6307         5, 1, 2,
6308         5, 0, 3,
6309         5, 3, 1,
6310         0, 2, 4,
6311         2, 1, 4,
6312         3, 0, 4,
6313         1, 3, 4
6314 };
6315
6316 static const unsigned short nomodelelement3s[24] =
6317 {
6318         5, 2, 0,
6319         5, 1, 2,
6320         5, 0, 3,
6321         5, 3, 1,
6322         0, 2, 4,
6323         2, 1, 4,
6324         3, 0, 4,
6325         1, 3, 4
6326 };
6327
6328 static const float nomodelvertex3f[6*3] =
6329 {
6330         -16,   0,   0,
6331          16,   0,   0,
6332           0, -16,   0,
6333           0,  16,   0,
6334           0,   0, -16,
6335           0,   0,  16
6336 };
6337
6338 static const float nomodelcolor4f[6*4] =
6339 {
6340         0.0f, 0.0f, 0.5f, 1.0f,
6341         0.0f, 0.0f, 0.5f, 1.0f,
6342         0.0f, 0.5f, 0.0f, 1.0f,
6343         0.0f, 0.5f, 0.0f, 1.0f,
6344         0.5f, 0.0f, 0.0f, 1.0f,
6345         0.5f, 0.0f, 0.0f, 1.0f
6346 };
6347
6348 static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6349 {
6350         int i;
6351         float f1, f2, *c;
6352         float color4f[6*4];
6353
6354         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);
6355
6356         // this is only called once per entity so numsurfaces is always 1, and
6357         // surfacelist is always {0}, so this code does not handle batches
6358
6359         if (rsurface.ent_flags & RENDER_ADDITIVE)
6360         {
6361                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
6362                 GL_DepthMask(false);
6363         }
6364         else if (ent->alpha < 1)
6365         {
6366                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6367                 GL_DepthMask(false);
6368         }
6369         else
6370         {
6371                 GL_BlendFunc(GL_ONE, GL_ZERO);
6372                 GL_DepthMask(true);
6373         }
6374         GL_DepthRange(0, (rsurface.ent_flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
6375         GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
6376         GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
6377         GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
6378         memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
6379         for (i = 0, c = color4f;i < 6;i++, c += 4)
6380         {
6381                 c[0] *= ent->render_fullbright[0] * r_refdef.view.colorscale;
6382                 c[1] *= ent->render_fullbright[1] * r_refdef.view.colorscale;
6383                 c[2] *= ent->render_fullbright[2] * r_refdef.view.colorscale;
6384                 c[3] *= ent->alpha;
6385         }
6386         if (r_refdef.fogenabled)
6387         {
6388                 for (i = 0, c = color4f;i < 6;i++, c += 4)
6389                 {
6390                         f1 = RSurf_FogVertex(nomodelvertex3f + 3*i);
6391                         f2 = 1 - f1;
6392                         c[0] = (c[0] * f1 + r_refdef.fogcolor[0] * f2);
6393                         c[1] = (c[1] * f1 + r_refdef.fogcolor[1] * f2);
6394                         c[2] = (c[2] * f1 + r_refdef.fogcolor[2] * f2);
6395                 }
6396         }
6397 //      R_Mesh_ResetTextureState();
6398         R_SetupShader_Generic_NoTexture(false, false);
6399         R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
6400         R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
6401 }
6402
6403 void R_DrawNoModel(entity_render_t *ent)
6404 {
6405         vec3_t org;
6406         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
6407         if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1))
6408                 R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
6409         else
6410                 R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
6411 }
6412
6413 void R_CalcBeam_Vertex3f (float *vert, const float *org1, const float *org2, float width)
6414 {
6415         vec3_t right1, right2, diff, normal;
6416
6417         VectorSubtract (org2, org1, normal);
6418
6419         // calculate 'right' vector for start
6420         VectorSubtract (r_refdef.view.origin, org1, diff);
6421         CrossProduct (normal, diff, right1);
6422         VectorNormalize (right1);
6423
6424         // calculate 'right' vector for end
6425         VectorSubtract (r_refdef.view.origin, org2, diff);
6426         CrossProduct (normal, diff, right2);
6427         VectorNormalize (right2);
6428
6429         vert[ 0] = org1[0] + width * right1[0];
6430         vert[ 1] = org1[1] + width * right1[1];
6431         vert[ 2] = org1[2] + width * right1[2];
6432         vert[ 3] = org1[0] - width * right1[0];
6433         vert[ 4] = org1[1] - width * right1[1];
6434         vert[ 5] = org1[2] - width * right1[2];
6435         vert[ 6] = org2[0] - width * right2[0];
6436         vert[ 7] = org2[1] - width * right2[1];
6437         vert[ 8] = org2[2] - width * right2[2];
6438         vert[ 9] = org2[0] + width * right2[0];
6439         vert[10] = org2[1] + width * right2[1];
6440         vert[11] = org2[2] + width * right2[2];
6441 }
6442
6443 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)
6444 {
6445         vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
6446         vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
6447         vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
6448         vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
6449         vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
6450         vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
6451         vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
6452         vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
6453         vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
6454         vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
6455         vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
6456         vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
6457 }
6458
6459 static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
6460 {
6461         int i;
6462         float *vertex3f;
6463         float v[3];
6464         VectorSet(v, x, y, z);
6465         for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
6466                 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
6467                         break;
6468         if (i == mesh->numvertices)
6469         {
6470                 if (mesh->numvertices < mesh->maxvertices)
6471                 {
6472                         VectorCopy(v, vertex3f);
6473                         mesh->numvertices++;
6474                 }
6475                 return mesh->numvertices;
6476         }
6477         else
6478                 return i;
6479 }
6480
6481 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
6482 {
6483         int i;
6484         int *e, element[3];
6485         element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6486         element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6487         e = mesh->element3i + mesh->numtriangles * 3;
6488         for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
6489         {
6490                 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
6491                 if (mesh->numtriangles < mesh->maxtriangles)
6492                 {
6493                         *e++ = element[0];
6494                         *e++ = element[1];
6495                         *e++ = element[2];
6496                         mesh->numtriangles++;
6497                 }
6498                 element[1] = element[2];
6499         }
6500 }
6501
6502 static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
6503 {
6504         int i;
6505         int *e, element[3];
6506         element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6507         element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6508         e = mesh->element3i + mesh->numtriangles * 3;
6509         for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
6510         {
6511                 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
6512                 if (mesh->numtriangles < mesh->maxtriangles)
6513                 {
6514                         *e++ = element[0];
6515                         *e++ = element[1];
6516                         *e++ = element[2];
6517                         mesh->numtriangles++;
6518                 }
6519                 element[1] = element[2];
6520         }
6521 }
6522
6523 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
6524 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
6525 {
6526         int planenum, planenum2;
6527         int w;
6528         int tempnumpoints;
6529         mplane_t *plane, *plane2;
6530         double maxdist;
6531         double temppoints[2][256*3];
6532         // figure out how large a bounding box we need to properly compute this brush
6533         maxdist = 0;
6534         for (w = 0;w < numplanes;w++)
6535                 maxdist = max(maxdist, fabs(planes[w].dist));
6536         // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
6537         maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
6538         for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
6539         {
6540                 w = 0;
6541                 tempnumpoints = 4;
6542                 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
6543                 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
6544                 {
6545                         if (planenum2 == planenum)
6546                                 continue;
6547                         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);
6548                         w = !w;
6549                 }
6550                 if (tempnumpoints < 3)
6551                         continue;
6552                 // generate elements forming a triangle fan for this polygon
6553                 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
6554         }
6555 }
6556
6557 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)
6558 {
6559         texturelayer_t *layer;
6560         layer = t->currentlayers + t->currentnumlayers++;
6561         layer->type = type;
6562         layer->depthmask = depthmask;
6563         layer->blendfunc1 = blendfunc1;
6564         layer->blendfunc2 = blendfunc2;
6565         layer->texture = texture;
6566         layer->texmatrix = *matrix;
6567         layer->color[0] = r;
6568         layer->color[1] = g;
6569         layer->color[2] = b;
6570         layer->color[3] = a;
6571 }
6572
6573 static qboolean R_TestQ3WaveFunc(q3wavefunc_t func, const float *parms)
6574 {
6575         if(parms[0] == 0 && parms[1] == 0)
6576                 return false;
6577         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6578                 if(rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)] == 0)
6579                         return false;
6580         return true;
6581 }
6582
6583 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
6584 {
6585         double index, f;
6586         index = parms[2] + rsurface.shadertime * parms[3];
6587         index -= floor(index);
6588         switch (func & ((1 << Q3WAVEFUNC_USER_SHIFT) - 1))
6589         {
6590         default:
6591         case Q3WAVEFUNC_NONE:
6592         case Q3WAVEFUNC_NOISE:
6593         case Q3WAVEFUNC_COUNT:
6594                 f = 0;
6595                 break;
6596         case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
6597         case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
6598         case Q3WAVEFUNC_SAWTOOTH: f = index;break;
6599         case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
6600         case Q3WAVEFUNC_TRIANGLE:
6601                 index *= 4;
6602                 f = index - floor(index);
6603                 if (index < 1)
6604                 {
6605                         // f = f;
6606                 }
6607                 else if (index < 2)
6608                         f = 1 - f;
6609                 else if (index < 3)
6610                         f = -f;
6611                 else
6612                         f = -(1 - f);
6613                 break;
6614         }
6615         f = parms[0] + parms[1] * f;
6616         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6617                 f *= rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)];
6618         return (float) f;
6619 }
6620
6621 static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
6622 {
6623         int w, h, idx;
6624         float shadertime;
6625         float f;
6626         float offsetd[2];
6627         float tcmat[12];
6628         matrix4x4_t matrix, temp;
6629         // if shadertime exceeds about 9 hours (32768 seconds), just wrap it,
6630         // it's better to have one huge fixup every 9 hours than gradual
6631         // degradation over time which looks consistently bad after many hours.
6632         //
6633         // tcmod scroll in particular suffers from this degradation which can't be
6634         // effectively worked around even with floor() tricks because we don't
6635         // know if tcmod scroll is the last tcmod being applied, and for clampmap
6636         // a workaround involving floor() would be incorrect anyway...
6637         shadertime = rsurface.shadertime;
6638         if (shadertime >= 32768.0f)
6639                 shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f;
6640         switch(tcmod->tcmod)
6641         {
6642                 case Q3TCMOD_COUNT:
6643                 case Q3TCMOD_NONE:
6644                         if (currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6645                                 matrix = r_waterscrollmatrix;
6646                         else
6647                                 matrix = identitymatrix;
6648                         break;
6649                 case Q3TCMOD_ENTITYTRANSLATE:
6650                         // this is used in Q3 to allow the gamecode to control texcoord
6651                         // scrolling on the entity, which is not supported in darkplaces yet.
6652                         Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
6653                         break;
6654                 case Q3TCMOD_ROTATE:
6655                         Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
6656                         Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
6657                         Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
6658                         break;
6659                 case Q3TCMOD_SCALE:
6660                         Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
6661                         break;
6662                 case Q3TCMOD_SCROLL:
6663                         // this particular tcmod is a "bug for bug" compatible one with regards to
6664                         // Quake3, the wrapping is unnecessary with our shadetime fix but quake3
6665                         // specifically did the wrapping and so we must mimic that...
6666                         offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
6667                         offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
6668                         Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
6669                         break;
6670                 case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
6671                         w = (int) tcmod->parms[0];
6672                         h = (int) tcmod->parms[1];
6673                         f = rsurface.shadertime / (tcmod->parms[2] * w * h);
6674                         f = f - floor(f);
6675                         idx = (int) floor(f * w * h);
6676                         Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
6677                         break;
6678                 case Q3TCMOD_STRETCH:
6679                         f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
6680                         Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
6681                         break;
6682                 case Q3TCMOD_TRANSFORM:
6683                         VectorSet(tcmat +  0, tcmod->parms[0], tcmod->parms[1], 0);
6684                         VectorSet(tcmat +  3, tcmod->parms[2], tcmod->parms[3], 0);
6685                         VectorSet(tcmat +  6, 0                   , 0                , 1);
6686                         VectorSet(tcmat +  9, tcmod->parms[4], tcmod->parms[5], 0);
6687                         Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
6688                         break;
6689                 case Q3TCMOD_TURBULENT:
6690                         // this is handled in the RSurf_PrepareVertices function
6691                         matrix = identitymatrix;
6692                         break;
6693         }
6694         temp = *texmatrix;
6695         Matrix4x4_Concat(texmatrix, &matrix, &temp);
6696 }
6697
6698 static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
6699 {
6700         int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP;
6701         char name[MAX_QPATH];
6702         skinframe_t *skinframe;
6703         unsigned char pixels[296*194];
6704         strlcpy(cache->name, skinname, sizeof(cache->name));
6705         dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name);
6706         if (developer_loading.integer)
6707                 Con_Printf("loading %s\n", name);
6708         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
6709         if (!skinframe || !skinframe->base)
6710         {
6711                 unsigned char *f;
6712                 fs_offset_t filesize;
6713                 skinframe = NULL;
6714                 f = FS_LoadFile(name, tempmempool, true, &filesize);
6715                 if (f)
6716                 {
6717                         if (LoadPCX_QWSkin(f, (int)filesize, pixels, 296, 194))
6718                                 skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
6719                         Mem_Free(f);
6720                 }
6721         }
6722         cache->skinframe = skinframe;
6723 }
6724
6725 texture_t *R_GetCurrentTexture(texture_t *t)
6726 {
6727         int i, q;
6728         const entity_render_t *ent = rsurface.entity;
6729         dp_model_t *model = ent->model; // when calling this, ent must not be NULL
6730         q3shaderinfo_layer_tcmod_t *tcmod;
6731         float specularscale = 0.0f;
6732
6733         if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate)
6734                 return t->currentframe;
6735         t->update_lastrenderframe = r_textureframe;
6736         t->update_lastrenderentity = (void *)ent;
6737
6738         if(ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS)
6739                 t->camera_entity = ent->entitynumber;
6740         else
6741                 t->camera_entity = 0;
6742
6743         // switch to an alternate material if this is a q1bsp animated material
6744         {
6745                 texture_t *texture = t;
6746                 int s = rsurface.ent_skinnum;
6747                 if ((unsigned int)s >= (unsigned int)model->numskins)
6748                         s = 0;
6749                 if (model->skinscenes)
6750                 {
6751                         if (model->skinscenes[s].framecount > 1)
6752                                 s = model->skinscenes[s].firstframe + (unsigned int) (rsurface.shadertime * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
6753                         else
6754                                 s = model->skinscenes[s].firstframe;
6755                 }
6756                 if (s > 0)
6757                         t = t + s * model->num_surfaces;
6758                 if (t->animated)
6759                 {
6760                         // use an alternate animation if the entity's frame is not 0,
6761                         // and only if the texture has an alternate animation
6762                         if (t->animated == 2) // q2bsp
6763                                 t = t->anim_frames[0][ent->framegroupblend[0].frame % t->anim_total[0]];
6764                         else if (rsurface.ent_alttextures && t->anim_total[1])
6765                                 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
6766                         else
6767                                 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
6768                 }
6769                 texture->currentframe = t;
6770         }
6771
6772         // update currentskinframe to be a qw skin or animation frame
6773         if (rsurface.ent_qwskin >= 0)
6774         {
6775                 i = rsurface.ent_qwskin;
6776                 if (!r_qwskincache || r_qwskincache_size != cl.maxclients)
6777                 {
6778                         r_qwskincache_size = cl.maxclients;
6779                         if (r_qwskincache)
6780                                 Mem_Free(r_qwskincache);
6781                         r_qwskincache = (r_qwskincache_t *)Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size);
6782                 }
6783                 if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
6784                         R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
6785                 t->currentskinframe = r_qwskincache[i].skinframe;
6786                 if (t->materialshaderpass && t->currentskinframe == NULL)
6787                         t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6788         }
6789         else if (t->materialshaderpass && t->materialshaderpass->numframes >= 2)
6790                 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6791         if (t->backgroundshaderpass && t->backgroundshaderpass->numframes >= 2)
6792                 t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
6793
6794         t->currentmaterialflags = t->basematerialflags;
6795         t->currentalpha = rsurface.entity->alpha * t->basealpha;
6796         if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_water.integer || r_novis.integer || r_trippy.integer))
6797                 t->currentalpha *= r_wateralpha.value;
6798         if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay)
6799                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later
6800         if(!r_fb.water.enabled || r_refdef.view.isoverlay)
6801                 t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA);
6802
6803         // decide on which type of lighting to use for this surface
6804         if (rsurface.entity->render_modellight_forced)
6805                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6806         if (rsurface.entity->render_rtlight_disabled)
6807                 t->currentmaterialflags |= MATERIALFLAG_NORTLIGHT;
6808         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND && !(R_BlendFuncFlags(t->customblendfunc[0], t->customblendfunc[1]) & BLENDFUNC_ALLOWS_COLORMOD))
6809         {
6810                 // some CUSTOMBLEND blendfuncs are too weird, we have to ignore colormod and view colorscale
6811                 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_NORTLIGHT;
6812                 for (q = 0; q < 3; q++)
6813                 {
6814                         t->render_glowmod[q] = rsurface.entity->glowmod[q];
6815                         t->render_modellight_lightdir[q] = q == 2;
6816                         t->render_modellight_ambient[q] = 1;
6817                         t->render_modellight_diffuse[q] = 0;
6818                         t->render_modellight_specular[q] = 0;
6819                         t->render_lightmap_ambient[q] = 0;
6820                         t->render_lightmap_diffuse[q] = 0;
6821                         t->render_lightmap_specular[q] = 0;
6822                         t->render_rtlight_diffuse[q] = 0;
6823                         t->render_rtlight_specular[q] = 0;
6824                 }
6825         }
6826         else if ((t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !(rsurface.ent_flags & RENDER_LIGHT))
6827         {
6828                 // fullbright is basically MATERIALFLAG_MODELLIGHT but with ambient locked to 1,1,1 and no shading
6829                 t->currentmaterialflags = t->currentmaterialflags | MATERIALFLAG_NORTLIGHT | MATERIALFLAG_MODELLIGHT;
6830                 for (q = 0; q < 3; q++)
6831                 {
6832                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6833                         t->render_modellight_ambient[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6834                         t->render_modellight_lightdir[q] = q == 2;
6835                         t->render_modellight_diffuse[q] = 0;
6836                         t->render_modellight_specular[q] = 0;
6837                         t->render_lightmap_ambient[q] = 0;
6838                         t->render_lightmap_diffuse[q] = 0;
6839                         t->render_lightmap_specular[q] = 0;
6840                         t->render_rtlight_diffuse[q] = 0;
6841                         t->render_rtlight_specular[q] = 0;
6842                 }
6843         }
6844         else if (FAKELIGHT_ENABLED)
6845         {
6846                 // no modellight if using fakelight for the map
6847                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_NORTLIGHT) & ~(MATERIALFLAG_MODELLIGHT);
6848                 for (q = 0; q < 3; q++)
6849                 {
6850                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6851                         t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6852                         t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6853                         t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6854                         t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6855                         t->render_lightmap_ambient[q] = 0;
6856                         t->render_lightmap_diffuse[q] = 0;
6857                         t->render_lightmap_specular[q] = 0;
6858                         t->render_rtlight_diffuse[q] = 0;
6859                         t->render_rtlight_specular[q] = 0;
6860                 }
6861         }
6862         else if ((rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT)) || rsurface.modeltexcoordlightmap2f == NULL)
6863         {
6864                 // ambient + single direction light (modellight)
6865                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6866                 for (q = 0; q < 3; q++)
6867                 {
6868                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6869                         t->render_modellight_lightdir[q] = rsurface.entity->render_modellight_lightdir[q];
6870                         t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6871                         t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6872                         t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6873                         t->render_lightmap_ambient[q] = 0;
6874                         t->render_lightmap_diffuse[q] = 0;
6875                         t->render_lightmap_specular[q] = 0;
6876                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6877                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6878                 }
6879         }
6880         else
6881         {
6882                 // lightmap - 2x diffuse and specular brightness because bsp files have 0-2 colors as 0-1
6883                 for (q = 0; q < 3; q++)
6884                 {
6885                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6886                         t->render_modellight_lightdir[q] = q == 2;
6887                         t->render_modellight_ambient[q] = 0;
6888                         t->render_modellight_diffuse[q] = 0;
6889                         t->render_modellight_specular[q] = 0;
6890                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6891                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6892                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6893                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6894                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6895                 }
6896         }
6897
6898         if (t->currentmaterialflags & MATERIALFLAG_VERTEXCOLOR)
6899         {
6900                 // since MATERIALFLAG_VERTEXCOLOR uses the lightmapcolor4f vertex
6901                 // attribute, we punt it to the lightmap path and hope for the best,
6902                 // but lighting doesn't work.
6903                 //
6904                 // FIXME: this is fine for effects but CSQC polygons should be subject
6905                 // to lighting.
6906                 t->currentmaterialflags &= ~MATERIALFLAG_MODELLIGHT;
6907                 for (q = 0; q < 3; q++)
6908                 {
6909                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6910                         t->render_modellight_lightdir[q] = q == 2;
6911                         t->render_modellight_ambient[q] = 0;
6912                         t->render_modellight_diffuse[q] = 0;
6913                         t->render_modellight_specular[q] = 0;
6914                         t->render_lightmap_ambient[q] = 0;
6915                         t->render_lightmap_diffuse[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6916                         t->render_lightmap_specular[q] = 0;
6917                         t->render_rtlight_diffuse[q] = 0;
6918                         t->render_rtlight_specular[q] = 0;
6919                 }
6920         }
6921
6922         for (q = 0; q < 3; q++)
6923         {
6924                 t->render_colormap_pants[q] = rsurface.entity->colormap_pantscolor[q];
6925                 t->render_colormap_shirt[q] = rsurface.entity->colormap_shirtcolor[q];
6926         }
6927
6928         if (rsurface.ent_flags & RENDER_ADDITIVE)
6929                 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6930         else if (t->currentalpha < 1)
6931                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6932         // LordHavoc: prevent bugs where code checks add or alpha at higher priority than customblend by clearing these flags
6933         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6934                 t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA);
6935         if (rsurface.ent_flags & RENDER_DOUBLESIDED)
6936                 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
6937         if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
6938                 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
6939         if (t->backgroundshaderpass)
6940                 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
6941         if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
6942         {
6943                 if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA))
6944                         t->currentmaterialflags &= ~MATERIALFLAG_BLENDED;
6945         }
6946         else
6947                 t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA);
6948         if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)))
6949         {
6950                 // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on
6951                 t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST;
6952         }
6953         if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
6954                 t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
6955
6956         // there is no tcmod
6957         if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6958         {
6959                 t->currenttexmatrix = r_waterscrollmatrix;
6960                 t->currentbackgroundtexmatrix = r_waterscrollmatrix;
6961         }
6962         else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE))
6963         {
6964                 Matrix4x4_CreateIdentity(&t->currenttexmatrix);
6965                 Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
6966         }
6967
6968         if (t->materialshaderpass)
6969                 for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
6970                         R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
6971
6972         t->colormapping = VectorLength2(t->render_colormap_pants) + VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f);
6973         if (t->currentskinframe->qpixels)
6974                 R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
6975         t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
6976         if (!t->basetexture)
6977                 t->basetexture = r_texture_notexture;
6978         t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
6979         t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
6980         t->nmaptexture = t->currentskinframe->nmap;
6981         if (!t->nmaptexture)
6982                 t->nmaptexture = r_texture_blanknormalmap;
6983         t->glosstexture = r_texture_black;
6984         t->glowtexture = t->currentskinframe->glow;
6985         t->fogtexture = t->currentskinframe->fog;
6986         t->reflectmasktexture = t->currentskinframe->reflect;
6987         if (t->backgroundshaderpass)
6988         {
6989                 for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
6990                         R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
6991                 t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
6992                 t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
6993                 t->backgroundglosstexture = r_texture_black;
6994                 t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
6995                 if (!t->backgroundnmaptexture)
6996                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6997                 // make sure that if glow is going to be used, both textures are not NULL
6998                 if (!t->backgroundglowtexture && t->glowtexture)
6999                         t->backgroundglowtexture = r_texture_black;
7000                 if (!t->glowtexture && t->backgroundglowtexture)
7001                         t->glowtexture = r_texture_black;
7002         }
7003         else
7004         {
7005                 t->backgroundbasetexture = r_texture_white;
7006                 t->backgroundnmaptexture = r_texture_blanknormalmap;
7007                 t->backgroundglosstexture = r_texture_black;
7008                 t->backgroundglowtexture = NULL;
7009         }
7010         t->specularpower = r_shadow_glossexponent.value;
7011         // TODO: store reference values for these in the texture?
7012         if (r_shadow_gloss.integer > 0)
7013         {
7014                 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
7015                 {
7016                         if (r_shadow_glossintensity.value > 0)
7017                         {
7018                                 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
7019                                 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
7020                                 specularscale = r_shadow_glossintensity.value;
7021                         }
7022                 }
7023                 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
7024                 {
7025                         t->glosstexture = r_texture_white;
7026                         t->backgroundglosstexture = r_texture_white;
7027                         specularscale = r_shadow_gloss2intensity.value;
7028                         t->specularpower = r_shadow_gloss2exponent.value;
7029                 }
7030         }
7031         specularscale *= t->specularscalemod;
7032         t->specularpower *= t->specularpowermod;
7033
7034         // lightmaps mode looks bad with dlights using actual texturing, so turn
7035         // off the colormap and glossmap, but leave the normalmap on as it still
7036         // accurately represents the shading involved
7037         if (gl_lightmaps.integer)
7038         {
7039                 t->basetexture = r_texture_grey128;
7040                 t->pantstexture = r_texture_black;
7041                 t->shirttexture = r_texture_black;
7042                 if (gl_lightmaps.integer < 2)
7043                         t->nmaptexture = r_texture_blanknormalmap;
7044                 t->glosstexture = r_texture_black;
7045                 t->glowtexture = NULL;
7046                 t->fogtexture = NULL;
7047                 t->reflectmasktexture = NULL;
7048                 t->backgroundbasetexture = NULL;
7049                 if (gl_lightmaps.integer < 2)
7050                         t->backgroundnmaptexture = r_texture_blanknormalmap;
7051                 t->backgroundglosstexture = r_texture_black;
7052                 t->backgroundglowtexture = NULL;
7053                 specularscale = 0;
7054                 t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
7055         }
7056
7057         if (specularscale != 1.0f)
7058         {
7059                 for (q = 0; q < 3; q++)
7060                 {
7061                         t->render_modellight_specular[q] *= specularscale;
7062                         t->render_lightmap_specular[q] *= specularscale;
7063                         t->render_rtlight_specular[q] *= specularscale;
7064                 }
7065         }
7066
7067         t->currentnumlayers = 0;
7068         if (t->currentmaterialflags & MATERIALFLAG_WALL)
7069         {
7070                 int blendfunc1, blendfunc2;
7071                 qboolean depthmask;
7072                 if (t->currentmaterialflags & MATERIALFLAG_ADD)
7073                 {
7074                         blendfunc1 = GL_SRC_ALPHA;
7075                         blendfunc2 = GL_ONE;
7076                 }
7077                 else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
7078                 {
7079                         blendfunc1 = GL_SRC_ALPHA;
7080                         blendfunc2 = GL_ONE_MINUS_SRC_ALPHA;
7081                 }
7082                 else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
7083                 {
7084                         blendfunc1 = t->customblendfunc[0];
7085                         blendfunc2 = t->customblendfunc[1];
7086                 }
7087                 else
7088                 {
7089                         blendfunc1 = GL_ONE;
7090                         blendfunc2 = GL_ZERO;
7091                 }
7092                 depthmask = !(t->currentmaterialflags & MATERIALFLAG_BLENDED);
7093                 if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
7094                 {
7095                         // basic lit geometry
7096                         R_Texture_AddLayer(t, depthmask, blendfunc1, blendfunc2, TEXTURELAYERTYPE_LITTEXTURE, t->basetexture, &t->currenttexmatrix, 2, 2, 2, t->currentalpha);
7097                         // add pants/shirt if needed
7098                         if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7099                                 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);
7100                         if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7101                                 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);
7102                 }
7103                 else
7104                 {
7105                         // basic lit geometry
7106                         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);
7107                         // add pants/shirt if needed
7108                         if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7109                                 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);
7110                         if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7111                                 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);
7112                         // now add ambient passes if needed
7113                         if (VectorLength2(t->render_lightmap_ambient) >= (1.0f/1048576.0f))
7114                         {
7115                                 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);
7116                                 if (VectorLength2(t->render_colormap_pants) >= (1.0f / 1048576.0f) && t->pantstexture)
7117                                         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);
7118                                 if (VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f) && t->shirttexture)
7119                                         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);
7120                         }
7121                 }
7122                 if (t->glowtexture != NULL && !gl_lightmaps.integer)
7123                         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);
7124                 if (r_refdef.fogenabled && !(t->currentmaterialflags & MATERIALFLAG_ADD))
7125                 {
7126                         // if this is opaque use alpha blend which will darken the earlier
7127                         // passes cheaply.
7128                         //
7129                         // if this is an alpha blended material, all the earlier passes
7130                         // were darkened by fog already, so we only need to add the fog
7131                         // color ontop through the fog mask texture
7132                         //
7133                         // if this is an additive blended material, all the earlier passes
7134                         // were darkened by fog already, and we should not add fog color
7135                         // (because the background was not darkened, there is no fog color
7136                         // that was lost behind it).
7137                         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);
7138                 }
7139         }
7140
7141         return t;
7142 }
7143
7144 rsurfacestate_t rsurface;
7145
7146 void RSurf_ActiveModelEntity(const entity_render_t *ent, qboolean wantnormals, qboolean wanttangents, qboolean prepass)
7147 {
7148         dp_model_t *model = ent->model;
7149         //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
7150         //      return;
7151         rsurface.entity = (entity_render_t *)ent;
7152         rsurface.skeleton = ent->skeleton;
7153         memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
7154         rsurface.ent_skinnum = ent->skinnum;
7155         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;
7156         rsurface.ent_flags = ent->flags;
7157         if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
7158                 rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
7159         rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
7160         rsurface.matrix = ent->matrix;
7161         rsurface.inversematrix = ent->inversematrix;
7162         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7163         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7164         R_EntityMatrix(&rsurface.matrix);
7165         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7166         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7167         rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist * rsurface.inversematrixscale;
7168         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7169         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7170         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7171         memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
7172         rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
7173         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7174         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7175         if (ent->model->brush.submodel && !prepass)
7176         {
7177                 rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
7178                 rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
7179         }
7180         // if the animcache code decided it should use the shader path, skip the deform step
7181         rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4;
7182         rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer;
7183         rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset;
7184         rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size;
7185         rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0;
7186         if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4)
7187         {
7188                 if (ent->animcache_vertex3f)
7189                 {
7190                         r_refdef.stats[r_stat_batch_entitycache_count]++;
7191                         r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
7192                         r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
7193                         r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
7194                         rsurface.modelvertex3f = ent->animcache_vertex3f;
7195                         rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer;
7196                         rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset;
7197                         rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
7198                         rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL;
7199                         rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0;
7200                         rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
7201                         rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL;
7202                         rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0;
7203                         rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
7204                         rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL;
7205                         rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0;
7206                         rsurface.modelvertexmesh = ent->animcache_vertexmesh;
7207                         rsurface.modelvertexmesh_vertexbuffer = ent->animcache_vertexmesh_vertexbuffer;
7208                         rsurface.modelvertexmesh_bufferoffset = ent->animcache_vertexmesh_bufferoffset;
7209                 }
7210                 else if (wanttangents)
7211                 {
7212                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7213                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7214                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7215                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7216                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7217                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7218                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7219                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7220                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f);
7221                         rsurface.modelvertexmesh = NULL;
7222                         rsurface.modelvertexmesh_vertexbuffer = NULL;
7223                         rsurface.modelvertexmesh_bufferoffset = 0;
7224                         rsurface.modelvertex3f_vertexbuffer = NULL;
7225                         rsurface.modelvertex3f_bufferoffset = 0;
7226                         rsurface.modelvertex3f_vertexbuffer = 0;
7227                         rsurface.modelvertex3f_bufferoffset = 0;
7228                         rsurface.modelsvector3f_vertexbuffer = 0;
7229                         rsurface.modelsvector3f_bufferoffset = 0;
7230                         rsurface.modeltvector3f_vertexbuffer = 0;
7231                         rsurface.modeltvector3f_bufferoffset = 0;
7232                         rsurface.modelnormal3f_vertexbuffer = 0;
7233                         rsurface.modelnormal3f_bufferoffset = 0;
7234                 }
7235                 else if (wantnormals)
7236                 {
7237                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7238                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7239                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7240                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7241                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7242                         rsurface.modelsvector3f = NULL;
7243                         rsurface.modeltvector3f = NULL;
7244                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7245                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL);
7246                         rsurface.modelvertexmesh = NULL;
7247                         rsurface.modelvertexmesh_vertexbuffer = NULL;
7248                         rsurface.modelvertexmesh_bufferoffset = 0;
7249                         rsurface.modelvertex3f_vertexbuffer = NULL;
7250                         rsurface.modelvertex3f_bufferoffset = 0;
7251                         rsurface.modelvertex3f_vertexbuffer = 0;
7252                         rsurface.modelvertex3f_bufferoffset = 0;
7253                         rsurface.modelsvector3f_vertexbuffer = 0;
7254                         rsurface.modelsvector3f_bufferoffset = 0;
7255                         rsurface.modeltvector3f_vertexbuffer = 0;
7256                         rsurface.modeltvector3f_bufferoffset = 0;
7257                         rsurface.modelnormal3f_vertexbuffer = 0;
7258                         rsurface.modelnormal3f_bufferoffset = 0;
7259                 }
7260                 else
7261                 {
7262                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7263                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7264                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7265                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7266                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7267                         rsurface.modelsvector3f = NULL;
7268                         rsurface.modeltvector3f = NULL;
7269                         rsurface.modelnormal3f = NULL;
7270                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL);
7271                         rsurface.modelvertexmesh = NULL;
7272                         rsurface.modelvertexmesh_vertexbuffer = NULL;
7273                         rsurface.modelvertexmesh_bufferoffset = 0;
7274                         rsurface.modelvertex3f_vertexbuffer = NULL;
7275                         rsurface.modelvertex3f_bufferoffset = 0;
7276                         rsurface.modelvertex3f_vertexbuffer = 0;
7277                         rsurface.modelvertex3f_bufferoffset = 0;
7278                         rsurface.modelsvector3f_vertexbuffer = 0;
7279                         rsurface.modelsvector3f_bufferoffset = 0;
7280                         rsurface.modeltvector3f_vertexbuffer = 0;
7281                         rsurface.modeltvector3f_bufferoffset = 0;
7282                         rsurface.modelnormal3f_vertexbuffer = 0;
7283                         rsurface.modelnormal3f_bufferoffset = 0;
7284                 }
7285                 rsurface.modelgeneratedvertex = true;
7286         }
7287         else
7288         {
7289                 if (rsurface.entityskeletaltransform3x4)
7290                 {
7291                         r_refdef.stats[r_stat_batch_entityskeletal_count]++;
7292                         r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
7293                         r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
7294                         r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
7295                 }
7296                 else
7297                 {
7298                         r_refdef.stats[r_stat_batch_entitystatic_count]++;
7299                         r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
7300                         r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
7301                         r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
7302                 }
7303                 rsurface.modelvertex3f  = model->surfmesh.data_vertex3f;
7304                 rsurface.modelvertex3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7305                 rsurface.modelvertex3f_bufferoffset = model->surfmesh.vbooffset_vertex3f;
7306                 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
7307                 rsurface.modelsvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7308                 rsurface.modelsvector3f_bufferoffset = model->surfmesh.vbooffset_svector3f;
7309                 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
7310                 rsurface.modeltvector3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7311                 rsurface.modeltvector3f_bufferoffset = model->surfmesh.vbooffset_tvector3f;
7312                 rsurface.modelnormal3f  = model->surfmesh.data_normal3f;
7313                 rsurface.modelnormal3f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7314                 rsurface.modelnormal3f_bufferoffset = model->surfmesh.vbooffset_normal3f;
7315                 rsurface.modelvertexmesh = model->surfmesh.data_vertexmesh;
7316                 rsurface.modelvertexmesh_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7317                 rsurface.modelvertexmesh_bufferoffset = model->surfmesh.vbooffset_vertex3f;
7318                 rsurface.modelgeneratedvertex = false;
7319         }
7320         rsurface.modellightmapcolor4f  = model->surfmesh.data_lightmapcolor4f;
7321         rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7322         rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.vbooffset_lightmapcolor4f;
7323         rsurface.modeltexcoordtexture2f  = model->surfmesh.data_texcoordtexture2f;
7324         rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7325         rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.vbooffset_texcoordtexture2f;
7326         rsurface.modeltexcoordlightmap2f  = model->surfmesh.data_texcoordlightmap2f;
7327         rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7328         rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.vbooffset_texcoordlightmap2f;
7329         rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
7330         rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7331         rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.vbooffset_skeletalindex4ub;
7332         rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
7333         rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.vbo_vertexbuffer;
7334         rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.vbooffset_skeletalweight4ub;
7335         rsurface.modelelement3i = model->surfmesh.data_element3i;
7336         rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
7337         rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
7338         rsurface.modelelement3s = model->surfmesh.data_element3s;
7339         rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
7340         rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
7341         rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
7342         rsurface.modelnumvertices = model->surfmesh.num_vertices;
7343         rsurface.modelnumtriangles = model->surfmesh.num_triangles;
7344         rsurface.modelsurfaces = model->data_surfaces;
7345         rsurface.batchgeneratedvertex = false;
7346         rsurface.batchfirstvertex = 0;
7347         rsurface.batchnumvertices = 0;
7348         rsurface.batchfirsttriangle = 0;
7349         rsurface.batchnumtriangles = 0;
7350         rsurface.batchvertex3f  = NULL;
7351         rsurface.batchvertex3f_vertexbuffer = NULL;
7352         rsurface.batchvertex3f_bufferoffset = 0;
7353         rsurface.batchsvector3f = NULL;
7354         rsurface.batchsvector3f_vertexbuffer = NULL;
7355         rsurface.batchsvector3f_bufferoffset = 0;
7356         rsurface.batchtvector3f = NULL;
7357         rsurface.batchtvector3f_vertexbuffer = NULL;
7358         rsurface.batchtvector3f_bufferoffset = 0;
7359         rsurface.batchnormal3f  = NULL;
7360         rsurface.batchnormal3f_vertexbuffer = NULL;
7361         rsurface.batchnormal3f_bufferoffset = 0;
7362         rsurface.batchlightmapcolor4f = NULL;
7363         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7364         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7365         rsurface.batchtexcoordtexture2f = NULL;
7366         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7367         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7368         rsurface.batchtexcoordlightmap2f = NULL;
7369         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7370         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7371         rsurface.batchskeletalindex4ub = NULL;
7372         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7373         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7374         rsurface.batchskeletalweight4ub = NULL;
7375         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7376         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7377         rsurface.batchvertexmesh = NULL;
7378         rsurface.batchvertexmesh_vertexbuffer = NULL;
7379         rsurface.batchvertexmesh_bufferoffset = 0;
7380         rsurface.batchelement3i = NULL;
7381         rsurface.batchelement3i_indexbuffer = NULL;
7382         rsurface.batchelement3i_bufferoffset = 0;
7383         rsurface.batchelement3s = NULL;
7384         rsurface.batchelement3s_indexbuffer = NULL;
7385         rsurface.batchelement3s_bufferoffset = 0;
7386         rsurface.forcecurrenttextureupdate = false;
7387 }
7388
7389 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)
7390 {
7391         rsurface.entity = r_refdef.scene.worldentity;
7392         rsurface.skeleton = NULL;
7393         rsurface.ent_skinnum = 0;
7394         rsurface.ent_qwskin = -1;
7395         rsurface.ent_flags = entflags;
7396         rsurface.shadertime = r_refdef.scene.time - shadertime;
7397         rsurface.modelnumvertices = numvertices;
7398         rsurface.modelnumtriangles = numtriangles;
7399         rsurface.matrix = *matrix;
7400         rsurface.inversematrix = *inversematrix;
7401         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7402         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7403         R_EntityMatrix(&rsurface.matrix);
7404         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7405         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7406         rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
7407         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7408         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7409         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7410         memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
7411         rsurface.frameblend[0].lerp = 1;
7412         rsurface.ent_alttextures = false;
7413         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7414         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7415         rsurface.entityskeletaltransform3x4 = NULL;
7416         rsurface.entityskeletaltransform3x4buffer = NULL;
7417         rsurface.entityskeletaltransform3x4offset = 0;
7418         rsurface.entityskeletaltransform3x4size = 0;
7419         rsurface.entityskeletalnumtransforms = 0;
7420         r_refdef.stats[r_stat_batch_entitycustom_count]++;
7421         r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
7422         r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
7423         r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
7424         if (wanttangents)
7425         {
7426                 rsurface.modelvertex3f = (float *)vertex3f;
7427                 rsurface.modelsvector3f = svector3f ? (float *)svector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7428                 rsurface.modeltvector3f = tvector3f ? (float *)tvector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7429                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7430         }
7431         else if (wantnormals)
7432         {
7433                 rsurface.modelvertex3f = (float *)vertex3f;
7434                 rsurface.modelsvector3f = NULL;
7435                 rsurface.modeltvector3f = NULL;
7436                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7437         }
7438         else
7439         {
7440                 rsurface.modelvertex3f = (float *)vertex3f;
7441                 rsurface.modelsvector3f = NULL;
7442                 rsurface.modeltvector3f = NULL;
7443                 rsurface.modelnormal3f = NULL;
7444         }
7445         rsurface.modelvertexmesh = NULL;
7446         rsurface.modelvertexmesh_vertexbuffer = NULL;
7447         rsurface.modelvertexmesh_bufferoffset = 0;
7448         rsurface.modelvertex3f_vertexbuffer = 0;
7449         rsurface.modelvertex3f_bufferoffset = 0;
7450         rsurface.modelsvector3f_vertexbuffer = 0;
7451         rsurface.modelsvector3f_bufferoffset = 0;
7452         rsurface.modeltvector3f_vertexbuffer = 0;
7453         rsurface.modeltvector3f_bufferoffset = 0;
7454         rsurface.modelnormal3f_vertexbuffer = 0;
7455         rsurface.modelnormal3f_bufferoffset = 0;
7456         rsurface.modelgeneratedvertex = true;
7457         rsurface.modellightmapcolor4f  = (float *)color4f;
7458         rsurface.modellightmapcolor4f_vertexbuffer = 0;
7459         rsurface.modellightmapcolor4f_bufferoffset = 0;
7460         rsurface.modeltexcoordtexture2f  = (float *)texcoord2f;
7461         rsurface.modeltexcoordtexture2f_vertexbuffer = 0;
7462         rsurface.modeltexcoordtexture2f_bufferoffset = 0;
7463         rsurface.modeltexcoordlightmap2f  = NULL;
7464         rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
7465         rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
7466         rsurface.modelskeletalindex4ub = NULL;
7467         rsurface.modelskeletalindex4ub_vertexbuffer = NULL;
7468         rsurface.modelskeletalindex4ub_bufferoffset = 0;
7469         rsurface.modelskeletalweight4ub = NULL;
7470         rsurface.modelskeletalweight4ub_vertexbuffer = NULL;
7471         rsurface.modelskeletalweight4ub_bufferoffset = 0;
7472         rsurface.modelelement3i = (int *)element3i;
7473         rsurface.modelelement3i_indexbuffer = NULL;
7474         rsurface.modelelement3i_bufferoffset = 0;
7475         rsurface.modelelement3s = (unsigned short *)element3s;
7476         rsurface.modelelement3s_indexbuffer = NULL;
7477         rsurface.modelelement3s_bufferoffset = 0;
7478         rsurface.modellightmapoffsets = NULL;
7479         rsurface.modelsurfaces = NULL;
7480         rsurface.batchgeneratedvertex = false;
7481         rsurface.batchfirstvertex = 0;
7482         rsurface.batchnumvertices = 0;
7483         rsurface.batchfirsttriangle = 0;
7484         rsurface.batchnumtriangles = 0;
7485         rsurface.batchvertex3f  = NULL;
7486         rsurface.batchvertex3f_vertexbuffer = NULL;
7487         rsurface.batchvertex3f_bufferoffset = 0;
7488         rsurface.batchsvector3f = NULL;
7489         rsurface.batchsvector3f_vertexbuffer = NULL;
7490         rsurface.batchsvector3f_bufferoffset = 0;
7491         rsurface.batchtvector3f = NULL;
7492         rsurface.batchtvector3f_vertexbuffer = NULL;
7493         rsurface.batchtvector3f_bufferoffset = 0;
7494         rsurface.batchnormal3f  = NULL;
7495         rsurface.batchnormal3f_vertexbuffer = NULL;
7496         rsurface.batchnormal3f_bufferoffset = 0;
7497         rsurface.batchlightmapcolor4f = NULL;
7498         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7499         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7500         rsurface.batchtexcoordtexture2f = NULL;
7501         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7502         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7503         rsurface.batchtexcoordlightmap2f = NULL;
7504         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7505         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7506         rsurface.batchskeletalindex4ub = NULL;
7507         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7508         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7509         rsurface.batchskeletalweight4ub = NULL;
7510         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7511         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7512         rsurface.batchvertexmesh = NULL;
7513         rsurface.batchvertexmesh_vertexbuffer = NULL;
7514         rsurface.batchvertexmesh_bufferoffset = 0;
7515         rsurface.batchelement3i = NULL;
7516         rsurface.batchelement3i_indexbuffer = NULL;
7517         rsurface.batchelement3i_bufferoffset = 0;
7518         rsurface.batchelement3s = NULL;
7519         rsurface.batchelement3s_indexbuffer = NULL;
7520         rsurface.batchelement3s_bufferoffset = 0;
7521         rsurface.forcecurrenttextureupdate = true;
7522
7523         if (rsurface.modelnumvertices && rsurface.modelelement3i)
7524         {
7525                 if ((wantnormals || wanttangents) && !normal3f)
7526                 {
7527                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7528                         Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
7529                 }
7530                 if (wanttangents && !svector3f)
7531                 {
7532                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7533                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7534                         Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.modelsvector3f, rsurface.modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
7535                 }
7536         }
7537 }
7538
7539 float RSurf_FogPoint(const float *v)
7540 {
7541         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7542         float FogPlaneViewDist = r_refdef.fogplaneviewdist;
7543         float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3];
7544         float FogHeightFade = r_refdef.fogheightfade;
7545         float fogfrac;
7546         unsigned int fogmasktableindex;
7547         if (r_refdef.fogplaneviewabove)
7548                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7549         else
7550                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7551         fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier);
7552         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7553 }
7554
7555 float RSurf_FogVertex(const float *v)
7556 {
7557         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7558         float FogPlaneViewDist = rsurface.fogplaneviewdist;
7559         float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3];
7560         float FogHeightFade = rsurface.fogheightfade;
7561         float fogfrac;
7562         unsigned int fogmasktableindex;
7563         if (r_refdef.fogplaneviewabove)
7564                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7565         else
7566                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7567         fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.fogmasktabledistmultiplier);
7568         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7569 }
7570
7571 static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
7572 {
7573         int i;
7574         for (i = 0;i < numelements;i++)
7575                 outelement3i[i] = inelement3i[i] + adjust;
7576 }
7577
7578 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
7579 extern cvar_t gl_vbo;
7580 void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist)
7581 {
7582         int deformindex;
7583         int firsttriangle;
7584         int numtriangles;
7585         int firstvertex;
7586         int endvertex;
7587         int numvertices;
7588         int surfacefirsttriangle;
7589         int surfacenumtriangles;
7590         int surfacefirstvertex;
7591         int surfaceendvertex;
7592         int surfacenumvertices;
7593         int batchnumsurfaces = texturenumsurfaces;
7594         int batchnumvertices;
7595         int batchnumtriangles;
7596         int needsupdate;
7597         int i, j;
7598         qboolean gaps;
7599         qboolean dynamicvertex;
7600         float amplitude;
7601         float animpos;
7602         float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
7603         float waveparms[4];
7604         unsigned char *ub;
7605         q3shaderinfo_deform_t *deform;
7606         const msurface_t *surface, *firstsurface;
7607         r_vertexmesh_t *vertexmesh;
7608         if (!texturenumsurfaces)
7609                 return;
7610         // find vertex range of this surface batch
7611         gaps = false;
7612         firstsurface = texturesurfacelist[0];
7613         firsttriangle = firstsurface->num_firsttriangle;
7614         batchnumvertices = 0;
7615         batchnumtriangles = 0;
7616         firstvertex = endvertex = firstsurface->num_firstvertex;
7617         for (i = 0;i < texturenumsurfaces;i++)
7618         {
7619                 surface = texturesurfacelist[i];
7620                 if (surface != firstsurface + i)
7621                         gaps = true;
7622                 surfacefirstvertex = surface->num_firstvertex;
7623                 surfaceendvertex = surfacefirstvertex + surface->num_vertices;
7624                 surfacenumvertices = surface->num_vertices;
7625                 surfacenumtriangles = surface->num_triangles;
7626                 if (firstvertex > surfacefirstvertex)
7627                         firstvertex = surfacefirstvertex;
7628                 if (endvertex < surfaceendvertex)
7629                         endvertex = surfaceendvertex;
7630                 batchnumvertices += surfacenumvertices;
7631                 batchnumtriangles += surfacenumtriangles;
7632         }
7633
7634         r_refdef.stats[r_stat_batch_batches]++;
7635         if (gaps)
7636                 r_refdef.stats[r_stat_batch_withgaps]++;
7637         r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces;
7638         r_refdef.stats[r_stat_batch_vertices] += batchnumvertices;
7639         r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles;
7640
7641         // we now know the vertex range used, and if there are any gaps in it
7642         rsurface.batchfirstvertex = firstvertex;
7643         rsurface.batchnumvertices = endvertex - firstvertex;
7644         rsurface.batchfirsttriangle = firsttriangle;
7645         rsurface.batchnumtriangles = batchnumtriangles;
7646
7647         // this variable holds flags for which properties have been updated that
7648         // may require regenerating vertexmesh array...
7649         needsupdate = 0;
7650
7651         // check if any dynamic vertex processing must occur
7652         dynamicvertex = false;
7653
7654         // a cvar to force the dynamic vertex path to be taken, for debugging
7655         if (r_batch_debugdynamicvertexpath.integer)
7656         {
7657                 if (!dynamicvertex)
7658                 {
7659                         r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1;
7660                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces;
7661                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices;
7662                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles;
7663                 }
7664                 dynamicvertex = true;
7665         }
7666
7667         // if there is a chance of animated vertex colors, it's a dynamic batch
7668         if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_ARRAY_VERTEXCOLOR)) && texturesurfacelist[0]->lightmapinfo)
7669         {
7670                 if (!dynamicvertex)
7671                 {
7672                         r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1;
7673                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces;
7674                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices;
7675                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles;
7676                 }
7677                 dynamicvertex = true;
7678                 needsupdate |= BATCHNEED_VERTEXMESH_VERTEXCOLOR;
7679         }
7680
7681         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
7682         {
7683                 switch (deform->deform)
7684                 {
7685                 default:
7686                 case Q3DEFORM_PROJECTIONSHADOW:
7687                 case Q3DEFORM_TEXT0:
7688                 case Q3DEFORM_TEXT1:
7689                 case Q3DEFORM_TEXT2:
7690                 case Q3DEFORM_TEXT3:
7691                 case Q3DEFORM_TEXT4:
7692                 case Q3DEFORM_TEXT5:
7693                 case Q3DEFORM_TEXT6:
7694                 case Q3DEFORM_TEXT7:
7695                 case Q3DEFORM_NONE:
7696                         break;
7697                 case Q3DEFORM_AUTOSPRITE:
7698                         if (!dynamicvertex)
7699                         {
7700                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1;
7701                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces;
7702                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices;
7703                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles;
7704                         }
7705                         dynamicvertex = true;
7706                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD;
7707                         needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7708                         break;
7709                 case Q3DEFORM_AUTOSPRITE2:
7710                         if (!dynamicvertex)
7711                         {
7712                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1;
7713                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces;
7714                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices;
7715                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles;
7716                         }
7717                         dynamicvertex = true;
7718                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7719                         needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7720                         break;
7721                 case Q3DEFORM_NORMAL:
7722                         if (!dynamicvertex)
7723                         {
7724                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1;
7725                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces;
7726                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices;
7727                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles;
7728                         }
7729                         dynamicvertex = true;
7730                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7731                         needsupdate |= BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7732                         break;
7733                 case Q3DEFORM_WAVE:
7734                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7735                                 break; // if wavefunc is a nop, ignore this transform
7736                         if (!dynamicvertex)
7737                         {
7738                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_wave] += 1;
7739                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces;
7740                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices;
7741                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles;
7742                         }
7743                         dynamicvertex = true;
7744                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7745                         needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7746                         break;
7747                 case Q3DEFORM_BULGE:
7748                         if (!dynamicvertex)
7749                         {
7750                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1;
7751                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces;
7752                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices;
7753                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles;
7754                         }
7755                         dynamicvertex = true;
7756                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7757                         needsupdate |= BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR;
7758                         break;
7759                 case Q3DEFORM_MOVE:
7760                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7761                                 break; // if wavefunc is a nop, ignore this transform
7762                         if (!dynamicvertex)
7763                         {
7764                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1;
7765                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces;
7766                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices;
7767                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles;
7768                         }
7769                         dynamicvertex = true;
7770                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7771                         needsupdate |= BATCHNEED_VERTEXMESH_VERTEX;
7772                         break;
7773                 }
7774         }
7775         if (rsurface.texture->materialshaderpass)
7776         {
7777                 switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
7778                 {
7779                 default:
7780                 case Q3TCGEN_TEXTURE:
7781                         break;
7782                 case Q3TCGEN_LIGHTMAP:
7783                         if (!dynamicvertex)
7784                         {
7785                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
7786                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
7787                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
7788                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
7789                         }
7790                         dynamicvertex = true;
7791                         batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7792                         needsupdate |= BATCHNEED_VERTEXMESH_LIGHTMAP;
7793                         break;
7794                 case Q3TCGEN_VECTOR:
7795                         if (!dynamicvertex)
7796                         {
7797                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
7798                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
7799                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
7800                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
7801                         }
7802                         dynamicvertex = true;
7803                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7804                         needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
7805                         break;
7806                 case Q3TCGEN_ENVIRONMENT:
7807                         if (!dynamicvertex)
7808                         {
7809                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
7810                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
7811                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
7812                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
7813                         }
7814                         dynamicvertex = true;
7815                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
7816                         needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
7817                         break;
7818                 }
7819                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
7820                 {
7821                         if (!dynamicvertex)
7822                         {
7823                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
7824                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
7825                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
7826                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
7827                         }
7828                         dynamicvertex = true;
7829                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7830                         needsupdate |= BATCHNEED_VERTEXMESH_TEXCOORD;
7831                 }
7832         }
7833
7834         if (!rsurface.modelvertexmesh && (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)))
7835         {
7836                 if (!dynamicvertex)
7837                 {
7838                         r_refdef.stats[r_stat_batch_dynamic_batches_because_interleavedarrays] += 1;
7839                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_interleavedarrays] += batchnumsurfaces;
7840                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_interleavedarrays] += batchnumvertices;
7841                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_interleavedarrays] += batchnumtriangles;
7842                 }
7843                 dynamicvertex = true;
7844                 needsupdate |= (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP));
7845         }
7846
7847         // when the model data has no vertex buffer (dynamic mesh), we need to
7848         // eliminate gaps
7849         if (vid.useinterleavedarrays && !rsurface.modelvertexmesh_vertexbuffer)
7850                 batchneed |= BATCHNEED_NOGAPS;
7851
7852         // the caller can specify BATCHNEED_NOGAPS to force a batch with
7853         // firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex),
7854         // we ensure this by treating the vertex batch as dynamic...
7855         if ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0))
7856         {
7857                 if (!dynamicvertex)
7858                 {
7859                         r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1;
7860                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces;
7861                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices;
7862                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles;
7863                 }
7864                 dynamicvertex = true;
7865         }
7866
7867         if (dynamicvertex)
7868         {
7869                 // when copying, we need to consider the regeneration of vertexmesh, any dependencies it may have must be set...
7870                 if (batchneed & BATCHNEED_VERTEXMESH_VERTEX)      batchneed |= BATCHNEED_ARRAY_VERTEX;
7871                 if (batchneed & BATCHNEED_VERTEXMESH_NORMAL)      batchneed |= BATCHNEED_ARRAY_NORMAL;
7872                 if (batchneed & BATCHNEED_VERTEXMESH_VECTOR)      batchneed |= BATCHNEED_ARRAY_VECTOR;
7873                 if (batchneed & BATCHNEED_VERTEXMESH_VERTEXCOLOR) batchneed |= BATCHNEED_ARRAY_VERTEXCOLOR;
7874                 if (batchneed & BATCHNEED_VERTEXMESH_TEXCOORD)    batchneed |= BATCHNEED_ARRAY_TEXCOORD;
7875                 if (batchneed & BATCHNEED_VERTEXMESH_LIGHTMAP)    batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7876                 if (batchneed & BATCHNEED_VERTEXMESH_SKELETAL)    batchneed |= BATCHNEED_ARRAY_SKELETAL;
7877         }
7878
7879         // if needsupdate, we have to do a dynamic vertex batch for sure
7880         if (needsupdate & batchneed)
7881         {
7882                 if (!dynamicvertex)
7883                 {
7884                         r_refdef.stats[r_stat_batch_dynamic_batches_because_derived] += 1;
7885                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_derived] += batchnumsurfaces;
7886                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_derived] += batchnumvertices;
7887                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_derived] += batchnumtriangles;
7888                 }
7889                 dynamicvertex = true;
7890         }
7891
7892         // see if we need to build vertexmesh from arrays
7893         if (!rsurface.modelvertexmesh && (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)))
7894         {
7895                 if (!dynamicvertex)
7896                 {
7897                         r_refdef.stats[r_stat_batch_dynamic_batches_because_interleavedarrays] += 1;
7898                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_interleavedarrays] += batchnumsurfaces;
7899                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_interleavedarrays] += batchnumvertices;
7900                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_interleavedarrays] += batchnumtriangles;
7901                 }
7902                 dynamicvertex = true;
7903         }
7904
7905         // if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data
7906         if (dynamicvertex && rsurface.entityskeletaltransform3x4)
7907                 batchneed |= BATCHNEED_ARRAY_SKELETAL;
7908
7909         rsurface.batchvertex3f = rsurface.modelvertex3f;
7910         rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer;
7911         rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
7912         rsurface.batchsvector3f = rsurface.modelsvector3f;
7913         rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer;
7914         rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
7915         rsurface.batchtvector3f = rsurface.modeltvector3f;
7916         rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer;
7917         rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
7918         rsurface.batchnormal3f = rsurface.modelnormal3f;
7919         rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer;
7920         rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
7921         rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f;
7922         rsurface.batchlightmapcolor4f_vertexbuffer  = rsurface.modellightmapcolor4f_vertexbuffer;
7923         rsurface.batchlightmapcolor4f_bufferoffset  = rsurface.modellightmapcolor4f_bufferoffset;
7924         rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f;
7925         rsurface.batchtexcoordtexture2f_vertexbuffer  = rsurface.modeltexcoordtexture2f_vertexbuffer;
7926         rsurface.batchtexcoordtexture2f_bufferoffset  = rsurface.modeltexcoordtexture2f_bufferoffset;
7927         rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
7928         rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer;
7929         rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
7930         rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub;
7931         rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer;
7932         rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset;
7933         rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub;
7934         rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer;
7935         rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset;
7936         rsurface.batchvertexmesh = rsurface.modelvertexmesh;
7937         rsurface.batchvertexmesh_vertexbuffer = rsurface.modelvertexmesh_vertexbuffer;
7938         rsurface.batchvertexmesh_bufferoffset = rsurface.modelvertexmesh_bufferoffset;
7939         rsurface.batchelement3i = rsurface.modelelement3i;
7940         rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer;
7941         rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset;
7942         rsurface.batchelement3s = rsurface.modelelement3s;
7943         rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer;
7944         rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset;
7945         rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4;
7946         rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer;
7947         rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset;
7948         rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size;
7949         rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms;
7950
7951         // if any dynamic vertex processing has to occur in software, we copy the
7952         // entire surface list together before processing to rebase the vertices
7953         // to start at 0 (otherwise we waste a lot of room in a vertex buffer).
7954         //
7955         // if any gaps exist and we do not have a static vertex buffer, we have to
7956         // copy the surface list together to avoid wasting upload bandwidth on the
7957         // vertices in the gaps.
7958         //
7959         // if gaps exist and we have a static vertex buffer, we can choose whether
7960         // to combine the index buffer ranges into one dynamic index buffer or
7961         // simply issue multiple glDrawElements calls (BATCHNEED_ALLOWMULTIDRAW).
7962         //
7963         // in many cases the batch is reduced to one draw call.
7964
7965         rsurface.batchmultidraw = false;
7966         rsurface.batchmultidrawnumsurfaces = 0;
7967         rsurface.batchmultidrawsurfacelist = NULL;
7968
7969         if (!dynamicvertex)
7970         {
7971                 // static vertex data, just set pointers...
7972                 rsurface.batchgeneratedvertex = false;
7973                 // if there are gaps, we want to build a combined index buffer,
7974                 // otherwise use the original static buffer with an appropriate offset
7975                 if (gaps)
7976                 {
7977                         r_refdef.stats[r_stat_batch_copytriangles_batches] += 1;
7978                         r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces;
7979                         r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices;
7980                         r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles;
7981                         if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer)
7982                         {
7983                                 rsurface.batchmultidraw = true;
7984                                 rsurface.batchmultidrawnumsurfaces = texturenumsurfaces;
7985                                 rsurface.batchmultidrawsurfacelist = texturesurfacelist;
7986                                 return;
7987                         }
7988                         // build a new triangle elements array for this batch
7989                         rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7990                         rsurface.batchfirsttriangle = 0;
7991                         numtriangles = 0;
7992                         for (i = 0;i < texturenumsurfaces;i++)
7993                         {
7994                                 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7995                                 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7996                                 memcpy(rsurface.batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3]));
7997                                 numtriangles += surfacenumtriangles;
7998                         }
7999                         rsurface.batchelement3i_indexbuffer = NULL;
8000                         rsurface.batchelement3i_bufferoffset = 0;
8001                         rsurface.batchelement3s = NULL;
8002                         rsurface.batchelement3s_indexbuffer = NULL;
8003                         rsurface.batchelement3s_bufferoffset = 0;
8004                         if (endvertex <= 65536)
8005                         {
8006                                 // make a 16bit (unsigned short) index array if possible
8007                                 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
8008                                 for (i = 0;i < numtriangles*3;i++)
8009                                         rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
8010                         }
8011                         // upload buffer data for the copytriangles batch
8012                         if (((r_batch_dynamicbuffer.integer || gl_vbo_dynamicindex.integer) && vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo)
8013                         {
8014                                 if (rsurface.batchelement3s)
8015                                         rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
8016                                 else if (rsurface.batchelement3i)
8017                                         rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
8018                         }
8019                 }
8020                 else
8021                 {
8022                         r_refdef.stats[r_stat_batch_fast_batches] += 1;
8023                         r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces;
8024                         r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices;
8025                         r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles;
8026                 }
8027                 return;
8028         }
8029
8030         // something needs software processing, do it for real...
8031         // we only directly handle separate array data in this case and then
8032         // generate interleaved data if needed...
8033         rsurface.batchgeneratedvertex = true;
8034         r_refdef.stats[r_stat_batch_dynamic_batches] += 1;
8035         r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces;
8036         r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices;
8037         r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles;
8038
8039         // now copy the vertex data into a combined array and make an index array
8040         // (this is what Quake3 does all the time)
8041         // we also apply any skeletal animation here that would have been done in
8042         // the vertex shader, because most of the dynamic vertex animation cases
8043         // need actual vertex positions and normals
8044         //if (dynamicvertex)
8045         {
8046                 rsurface.batchvertexmesh = NULL;
8047                 rsurface.batchvertexmesh_vertexbuffer = NULL;
8048                 rsurface.batchvertexmesh_bufferoffset = 0;
8049                 rsurface.batchvertex3f = NULL;
8050                 rsurface.batchvertex3f_vertexbuffer = NULL;
8051                 rsurface.batchvertex3f_bufferoffset = 0;
8052                 rsurface.batchsvector3f = NULL;
8053                 rsurface.batchsvector3f_vertexbuffer = NULL;
8054                 rsurface.batchsvector3f_bufferoffset = 0;
8055                 rsurface.batchtvector3f = NULL;
8056                 rsurface.batchtvector3f_vertexbuffer = NULL;
8057                 rsurface.batchtvector3f_bufferoffset = 0;
8058                 rsurface.batchnormal3f = NULL;
8059                 rsurface.batchnormal3f_vertexbuffer = NULL;
8060                 rsurface.batchnormal3f_bufferoffset = 0;
8061                 rsurface.batchlightmapcolor4f = NULL;
8062                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8063                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8064                 rsurface.batchtexcoordtexture2f = NULL;
8065                 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8066                 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8067                 rsurface.batchtexcoordlightmap2f = NULL;
8068                 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
8069                 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
8070                 rsurface.batchskeletalindex4ub = NULL;
8071                 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
8072                 rsurface.batchskeletalindex4ub_bufferoffset = 0;
8073                 rsurface.batchskeletalweight4ub = NULL;
8074                 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
8075                 rsurface.batchskeletalweight4ub_bufferoffset = 0;
8076                 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
8077                 rsurface.batchelement3i_indexbuffer = NULL;
8078                 rsurface.batchelement3i_bufferoffset = 0;
8079                 rsurface.batchelement3s = NULL;
8080                 rsurface.batchelement3s_indexbuffer = NULL;
8081                 rsurface.batchelement3s_bufferoffset = 0;
8082                 rsurface.batchskeletaltransform3x4buffer = NULL;
8083                 rsurface.batchskeletaltransform3x4offset = 0;
8084                 rsurface.batchskeletaltransform3x4size = 0;
8085                 // we'll only be setting up certain arrays as needed
8086                 if (batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP))
8087                         rsurface.batchvertexmesh = (r_vertexmesh_t *)R_FrameData_Alloc(batchnumvertices * sizeof(r_vertexmesh_t));
8088                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
8089                         rsurface.batchvertex3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8090                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
8091                         rsurface.batchnormal3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8092                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
8093                 {
8094                         rsurface.batchsvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8095                         rsurface.batchtvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8096                 }
8097                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
8098                         rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8099                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
8100                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8101                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
8102                         rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8103                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
8104                 {
8105                         rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
8106                         rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
8107                 }
8108                 numvertices = 0;
8109                 numtriangles = 0;
8110                 for (i = 0;i < texturenumsurfaces;i++)
8111                 {
8112                         surfacefirstvertex = texturesurfacelist[i]->num_firstvertex;
8113                         surfacenumvertices = texturesurfacelist[i]->num_vertices;
8114                         surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
8115                         surfacenumtriangles = texturesurfacelist[i]->num_triangles;
8116                         // copy only the data requested
8117                         if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP)) && rsurface.modelvertexmesh)
8118                                 memcpy(rsurface.batchvertexmesh + numvertices, rsurface.modelvertexmesh + surfacefirstvertex, surfacenumvertices * sizeof(rsurface.batchvertexmesh[0]));
8119                         if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
8120                         {
8121                                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
8122                                 {
8123                                         if (rsurface.batchvertex3f)
8124                                                 memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8125                                         else
8126                                                 memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8127                                 }
8128                                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
8129                                 {
8130                                         if (rsurface.modelnormal3f)
8131                                                 memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8132                                         else
8133                                                 memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8134                                 }
8135                                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
8136                                 {
8137                                         if (rsurface.modelsvector3f)
8138                                         {
8139                                                 memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8140                                                 memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
8141                                         }
8142                                         else
8143                                         {
8144                                                 memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8145                                                 memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
8146                                         }
8147                                 }
8148                                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
8149                                 {
8150                                         if (rsurface.modellightmapcolor4f)
8151                                                 memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
8152                                         else
8153                                                 memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4]));
8154                                 }
8155                                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
8156                                 {
8157                                         if (rsurface.modeltexcoordtexture2f)
8158                                                 memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
8159                                         else
8160                                                 memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
8161                                 }
8162                                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
8163                                 {
8164                                         if (rsurface.modeltexcoordlightmap2f)
8165                                                 memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
8166                                         else
8167                                                 memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
8168                                 }
8169                                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
8170                                 {
8171                                         if (rsurface.modelskeletalindex4ub)
8172                                         {
8173                                                 memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
8174                                                 memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
8175                                         }
8176                                         else
8177                                         {
8178                                                 memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
8179                                                 memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
8180                                                 ub = rsurface.batchskeletalweight4ub + 4*numvertices;
8181                                                 for (j = 0;j < surfacenumvertices;j++)
8182                                                         ub[j*4] = 255;
8183                                         }
8184                                 }
8185                         }
8186                         RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
8187                         numvertices += surfacenumvertices;
8188                         numtriangles += surfacenumtriangles;
8189                 }
8190
8191                 // generate a 16bit index array as well if possible
8192                 // (in general, dynamic batches fit)
8193                 if (numvertices <= 65536)
8194                 {
8195                         rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
8196                         for (i = 0;i < numtriangles*3;i++)
8197                                 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
8198                 }
8199
8200                 // since we've copied everything, the batch now starts at 0
8201                 rsurface.batchfirstvertex = 0;
8202                 rsurface.batchnumvertices = batchnumvertices;
8203                 rsurface.batchfirsttriangle = 0;
8204                 rsurface.batchnumtriangles = batchnumtriangles;
8205         }
8206
8207         // apply skeletal animation that would have been done in the vertex shader
8208         if (rsurface.batchskeletaltransform3x4)
8209         {
8210                 const unsigned char *si;
8211                 const unsigned char *sw;
8212                 const float *t[4];
8213                 const float *b = rsurface.batchskeletaltransform3x4;
8214                 float *vp, *vs, *vt, *vn;
8215                 float w[4];
8216                 float m[3][4], n[3][4];
8217                 float tp[3], ts[3], tt[3], tn[3];
8218                 r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1;
8219                 r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces;
8220                 r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices;
8221                 r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles;
8222                 si = rsurface.batchskeletalindex4ub;
8223                 sw = rsurface.batchskeletalweight4ub;
8224                 vp = rsurface.batchvertex3f;
8225                 vs = rsurface.batchsvector3f;
8226                 vt = rsurface.batchtvector3f;
8227                 vn = rsurface.batchnormal3f;
8228                 memset(m[0], 0, sizeof(m));
8229                 memset(n[0], 0, sizeof(n));
8230                 for (i = 0;i < batchnumvertices;i++)
8231                 {
8232                         t[0] = b + si[0]*12;
8233                         if (sw[0] == 255)
8234                         {
8235                                 // common case - only one matrix
8236                                 m[0][0] = t[0][ 0];
8237                                 m[0][1] = t[0][ 1];
8238                                 m[0][2] = t[0][ 2];
8239                                 m[0][3] = t[0][ 3];
8240                                 m[1][0] = t[0][ 4];
8241                                 m[1][1] = t[0][ 5];
8242                                 m[1][2] = t[0][ 6];
8243                                 m[1][3] = t[0][ 7];
8244                                 m[2][0] = t[0][ 8];
8245                                 m[2][1] = t[0][ 9];
8246                                 m[2][2] = t[0][10];
8247                                 m[2][3] = t[0][11];
8248                         }
8249                         else if (sw[2] + sw[3])
8250                         {
8251                                 // blend 4 matrices
8252                                 t[1] = b + si[1]*12;
8253                                 t[2] = b + si[2]*12;
8254                                 t[3] = b + si[3]*12;
8255                                 w[0] = sw[0] * (1.0f / 255.0f);
8256                                 w[1] = sw[1] * (1.0f / 255.0f);
8257                                 w[2] = sw[2] * (1.0f / 255.0f);
8258                                 w[3] = sw[3] * (1.0f / 255.0f);
8259                                 // blend the matrices
8260                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3];
8261                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3];
8262                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3];
8263                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3];
8264                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3];
8265                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3];
8266                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3];
8267                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3];
8268                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3];
8269                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3];
8270                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3];
8271                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3];
8272                         }
8273                         else
8274                         {
8275                                 // blend 2 matrices
8276                                 t[1] = b + si[1]*12;
8277                                 w[0] = sw[0] * (1.0f / 255.0f);
8278                                 w[1] = sw[1] * (1.0f / 255.0f);
8279                                 // blend the matrices
8280                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1];
8281                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1];
8282                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1];
8283                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1];
8284                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1];
8285                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1];
8286                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1];
8287                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1];
8288                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1];
8289                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1];
8290                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1];
8291                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1];
8292                         }
8293                         si += 4;
8294                         sw += 4;
8295                         // modify the vertex
8296                         VectorCopy(vp, tp);
8297                         vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3];
8298                         vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3];
8299                         vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3];
8300                         vp += 3;
8301                         if (vn)
8302                         {
8303                                 // the normal transformation matrix is a set of cross products...
8304                                 CrossProduct(m[1], m[2], n[0]);
8305                                 CrossProduct(m[2], m[0], n[1]);
8306                                 CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m)
8307                                 VectorCopy(vn, tn);
8308                                 vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2];
8309                                 vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2];
8310                                 vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2];
8311                                 VectorNormalize(vn);
8312                                 vn += 3;
8313                                 if (vs)
8314                                 {
8315                                         VectorCopy(vs, ts);
8316                                         vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2];
8317                                         vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2];
8318                                         vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2];
8319                                         VectorNormalize(vs);
8320                                         vs += 3;
8321                                         VectorCopy(vt, tt);
8322                                         vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2];
8323                                         vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2];
8324                                         vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2];
8325                                         VectorNormalize(vt);
8326                                         vt += 3;
8327                                 }
8328                         }
8329                 }
8330                 rsurface.batchskeletaltransform3x4 = NULL;
8331                 rsurface.batchskeletalnumtransforms = 0;
8332         }
8333
8334         // q1bsp surfaces rendered in vertex color mode have to have colors
8335         // calculated based on lightstyles
8336         if ((batchneed & (BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_ARRAY_VERTEXCOLOR)) && texturesurfacelist[0]->lightmapinfo)
8337         {
8338                 // generate color arrays for the surfaces in this list
8339                 int c[4];
8340                 int scale;
8341                 int size3;
8342                 const int *offsets;
8343                 const unsigned char *lm;
8344                 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8345                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8346                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8347                 numvertices = 0;
8348                 for (i = 0;i < texturenumsurfaces;i++)
8349                 {
8350                         surface = texturesurfacelist[i];
8351                         offsets = rsurface.modellightmapoffsets + surface->num_firstvertex;
8352                         surfacenumvertices = surface->num_vertices;
8353                         if (surface->lightmapinfo->samples)
8354                         {
8355                                 for (j = 0;j < surfacenumvertices;j++)
8356                                 {
8357                                         lm = surface->lightmapinfo->samples + offsets[j];
8358                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]];
8359                                         VectorScale(lm, scale, c);
8360                                         if (surface->lightmapinfo->styles[1] != 255)
8361                                         {
8362                                                 size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
8363                                                 lm += size3;
8364                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]];
8365                                                 VectorMA(c, scale, lm, c);
8366                                                 if (surface->lightmapinfo->styles[2] != 255)
8367                                                 {
8368                                                         lm += size3;
8369                                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]];
8370                                                         VectorMA(c, scale, lm, c);
8371                                                         if (surface->lightmapinfo->styles[3] != 255)
8372                                                         {
8373                                                                 lm += size3;
8374                                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]];
8375                                                                 VectorMA(c, scale, lm, c);
8376                                                         }
8377                                                 }
8378                                         }
8379                                         c[0] >>= 7;
8380                                         c[1] >>= 7;
8381                                         c[2] >>= 7;
8382                                         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);
8383                                         numvertices++;
8384                                 }
8385                         }
8386                         else
8387                         {
8388                                 for (j = 0;j < surfacenumvertices;j++)
8389                                 {
8390                                         Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1);
8391                                         numvertices++;
8392                                 }
8393                         }
8394                 }
8395         }
8396
8397         // if vertices are deformed (sprite flares and things in maps, possibly
8398         // water waves, bulges and other deformations), modify the copied vertices
8399         // in place
8400         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
8401         {
8402                 float scale;
8403                 switch (deform->deform)
8404                 {
8405                 default:
8406                 case Q3DEFORM_PROJECTIONSHADOW:
8407                 case Q3DEFORM_TEXT0:
8408                 case Q3DEFORM_TEXT1:
8409                 case Q3DEFORM_TEXT2:
8410                 case Q3DEFORM_TEXT3:
8411                 case Q3DEFORM_TEXT4:
8412                 case Q3DEFORM_TEXT5:
8413                 case Q3DEFORM_TEXT6:
8414                 case Q3DEFORM_TEXT7:
8415                 case Q3DEFORM_NONE:
8416                         break;
8417                 case Q3DEFORM_AUTOSPRITE:
8418                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8419                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8420                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8421                         VectorNormalize(newforward);
8422                         VectorNormalize(newright);
8423                         VectorNormalize(newup);
8424 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8425 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8426 //                      rsurface.batchvertex3f_bufferoffset = 0;
8427 //                      rsurface.batchsvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f);
8428 //                      rsurface.batchsvector3f_vertexbuffer = NULL;
8429 //                      rsurface.batchsvector3f_bufferoffset = 0;
8430 //                      rsurface.batchtvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f);
8431 //                      rsurface.batchtvector3f_vertexbuffer = NULL;
8432 //                      rsurface.batchtvector3f_bufferoffset = 0;
8433 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8434 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8435 //                      rsurface.batchnormal3f_bufferoffset = 0;
8436                         // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1)
8437                         if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex))
8438                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8439                         if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex))
8440                                 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);
8441                         // a single autosprite surface can contain multiple sprites...
8442                         for (j = 0;j < batchnumvertices - 3;j += 4)
8443                         {
8444                                 VectorClear(center);
8445                                 for (i = 0;i < 4;i++)
8446                                         VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8447                                 VectorScale(center, 0.25f, center);
8448                                 VectorCopy(rsurface.batchnormal3f + 3*j, forward);
8449                                 VectorCopy(rsurface.batchsvector3f + 3*j, right);
8450                                 VectorCopy(rsurface.batchtvector3f + 3*j, up);
8451                                 for (i = 0;i < 4;i++)
8452                                 {
8453                                         VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v);
8454                                         VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.batchvertex3f + 3*(j+i));
8455                                 }
8456                         }
8457                         // if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check
8458                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8459                         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);
8460                         break;
8461                 case Q3DEFORM_AUTOSPRITE2:
8462                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8463                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8464                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8465                         VectorNormalize(newforward);
8466                         VectorNormalize(newright);
8467                         VectorNormalize(newup);
8468 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8469 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8470 //                      rsurface.batchvertex3f_bufferoffset = 0;
8471                         {
8472                                 const float *v1, *v2;
8473                                 vec3_t start, end;
8474                                 float f, l;
8475                                 struct
8476                                 {
8477                                         float length2;
8478                                         const float *v1;
8479                                         const float *v2;
8480                                 }
8481                                 shortest[2];
8482                                 memset(shortest, 0, sizeof(shortest));
8483                                 // a single autosprite surface can contain multiple sprites...
8484                                 for (j = 0;j < batchnumvertices - 3;j += 4)
8485                                 {
8486                                         VectorClear(center);
8487                                         for (i = 0;i < 4;i++)
8488                                                 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8489                                         VectorScale(center, 0.25f, center);
8490                                         // find the two shortest edges, then use them to define the
8491                                         // axis vectors for rotating around the central axis
8492                                         for (i = 0;i < 6;i++)
8493                                         {
8494                                                 v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]);
8495                                                 v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]);
8496                                                 l = VectorDistance2(v1, v2);
8497                                                 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
8498                                                 if (v1[2] != v2[2])
8499                                                         l += (1.0f / 1024.0f);
8500                                                 if (shortest[0].length2 > l || i == 0)
8501                                                 {
8502                                                         shortest[1] = shortest[0];
8503                                                         shortest[0].length2 = l;
8504                                                         shortest[0].v1 = v1;
8505                                                         shortest[0].v2 = v2;
8506                                                 }
8507                                                 else if (shortest[1].length2 > l || i == 1)
8508                                                 {
8509                                                         shortest[1].length2 = l;
8510                                                         shortest[1].v1 = v1;
8511                                                         shortest[1].v2 = v2;
8512                                                 }
8513                                         }
8514                                         VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
8515                                         VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
8516                                         // this calculates the right vector from the shortest edge
8517                                         // and the up vector from the edge midpoints
8518                                         VectorSubtract(shortest[0].v1, shortest[0].v2, right);
8519                                         VectorNormalize(right);
8520                                         VectorSubtract(end, start, up);
8521                                         VectorNormalize(up);
8522                                         // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
8523                                         VectorSubtract(rsurface.localvieworigin, center, forward);
8524                                         //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
8525                                         VectorNegate(forward, forward);
8526                                         VectorReflect(forward, 0, up, forward);
8527                                         VectorNormalize(forward);
8528                                         CrossProduct(up, forward, newright);
8529                                         VectorNormalize(newright);
8530                                         // rotate the quad around the up axis vector, this is made
8531                                         // especially easy by the fact we know the quad is flat,
8532                                         // so we only have to subtract the center position and
8533                                         // measure distance along the right vector, and then
8534                                         // multiply that by the newright vector and add back the
8535                                         // center position
8536                                         // we also need to subtract the old position to undo the
8537                                         // displacement from the center, which we do with a
8538                                         // DotProduct, the subtraction/addition of center is also
8539                                         // optimized into DotProducts here
8540                                         l = DotProduct(right, center);
8541                                         for (i = 0;i < 4;i++)
8542                                         {
8543                                                 v1 = rsurface.batchvertex3f + 3*(j+i);
8544                                                 f = DotProduct(right, v1) - l;
8545                                                 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.batchvertex3f + 3*(j+i));
8546                                         }
8547                                 }
8548                         }
8549                         if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL
8550                         {
8551 //                              rsurface.batchnormal3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8552 //                              rsurface.batchnormal3f_vertexbuffer = NULL;
8553 //                              rsurface.batchnormal3f_bufferoffset = 0;
8554                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8555                         }
8556                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8557                         {
8558 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8559 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8560 //                              rsurface.batchsvector3f_bufferoffset = 0;
8561 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8562 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8563 //                              rsurface.batchtvector3f_bufferoffset = 0;
8564                                 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);
8565                         }
8566                         break;
8567                 case Q3DEFORM_NORMAL:
8568                         // deform the normals to make reflections wavey
8569                         rsurface.batchnormal3f = (float *)R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8570                         rsurface.batchnormal3f_vertexbuffer = NULL;
8571                         rsurface.batchnormal3f_bufferoffset = 0;
8572                         for (j = 0;j < batchnumvertices;j++)
8573                         {
8574                                 float vertex[3];
8575                                 float *normal = rsurface.batchnormal3f + 3*j;
8576                                 VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
8577                                 normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f(      vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8578                                 normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8579                                 normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8580                                 VectorNormalize(normal);
8581                         }
8582                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8583                         {
8584 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8585 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8586 //                              rsurface.batchsvector3f_bufferoffset = 0;
8587 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8588 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8589 //                              rsurface.batchtvector3f_bufferoffset = 0;
8590                                 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);
8591                         }
8592                         break;
8593                 case Q3DEFORM_WAVE:
8594                         // deform vertex array to make wavey water and flags and such
8595                         waveparms[0] = deform->waveparms[0];
8596                         waveparms[1] = deform->waveparms[1];
8597                         waveparms[2] = deform->waveparms[2];
8598                         waveparms[3] = deform->waveparms[3];
8599                         if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms))
8600                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8601                         // this is how a divisor of vertex influence on deformation
8602                         animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
8603                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8604 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8605 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8606 //                      rsurface.batchvertex3f_bufferoffset = 0;
8607 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8608 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8609 //                      rsurface.batchnormal3f_bufferoffset = 0;
8610                         for (j = 0;j < batchnumvertices;j++)
8611                         {
8612                                 // if the wavefunc depends on time, evaluate it per-vertex
8613                                 if (waveparms[3])
8614                                 {
8615                                         waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos;
8616                                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8617                                 }
8618                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8619                         }
8620                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8621                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8622                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8623                         {
8624 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8625 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8626 //                              rsurface.batchsvector3f_bufferoffset = 0;
8627 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8628 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8629 //                              rsurface.batchtvector3f_bufferoffset = 0;
8630                                 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);
8631                         }
8632                         break;
8633                 case Q3DEFORM_BULGE:
8634                         // deform vertex array to make the surface have moving bulges
8635 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8636 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8637 //                      rsurface.batchvertex3f_bufferoffset = 0;
8638 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8639 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8640 //                      rsurface.batchnormal3f_bufferoffset = 0;
8641                         for (j = 0;j < batchnumvertices;j++)
8642                         {
8643                                 scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1];
8644                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8645                         }
8646                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8647                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8648                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8649                         {
8650 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8651 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8652 //                              rsurface.batchsvector3f_bufferoffset = 0;
8653 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8654 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8655 //                              rsurface.batchtvector3f_bufferoffset = 0;
8656                                 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);
8657                         }
8658                         break;
8659                 case Q3DEFORM_MOVE:
8660                         // deform vertex array
8661                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
8662                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8663                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
8664                         VectorScale(deform->parms, scale, waveparms);
8665 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8666 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8667 //                      rsurface.batchvertex3f_bufferoffset = 0;
8668                         for (j = 0;j < batchnumvertices;j++)
8669                                 VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.batchvertex3f + 3*j);
8670                         break;
8671                 }
8672         }
8673
8674         if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
8675         {
8676         // generate texcoords based on the chosen texcoord source
8677                 switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
8678                 {
8679                 default:
8680                 case Q3TCGEN_TEXTURE:
8681                         break;
8682                 case Q3TCGEN_LIGHTMAP:
8683         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8684         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8685         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8686                         if (rsurface.batchtexcoordlightmap2f)
8687                                 memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
8688                         break;
8689                 case Q3TCGEN_VECTOR:
8690         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8691         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8692         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8693                         for (j = 0;j < batchnumvertices;j++)
8694                         {
8695                                 rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
8696                                 rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
8697                         }
8698                         break;
8699                 case Q3TCGEN_ENVIRONMENT:
8700                         // make environment reflections using a spheremap
8701                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8702                         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8703                         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8704                         for (j = 0;j < batchnumvertices;j++)
8705                         {
8706                                 // identical to Q3A's method, but executed in worldspace so
8707                                 // carried models can be shiny too
8708
8709                                 float viewer[3], d, reflected[3], worldreflected[3];
8710
8711                                 VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
8712                                 // VectorNormalize(viewer);
8713
8714                                 d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
8715
8716                                 reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
8717                                 reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
8718                                 reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
8719                                 // note: this is proportinal to viewer, so we can normalize later
8720
8721                                 Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
8722                                 VectorNormalize(worldreflected);
8723
8724                                 // note: this sphere map only uses world x and z!
8725                                 // so positive and negative y will LOOK THE SAME.
8726                                 rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
8727                                 rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
8728                         }
8729                         break;
8730                 }
8731                 // the only tcmod that needs software vertex processing is turbulent, so
8732                 // check for it here and apply the changes if needed
8733                 // and we only support that as the first one
8734                 // (handling a mixture of turbulent and other tcmods would be problematic
8735                 //  without punting it entirely to a software path)
8736                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
8737                 {
8738                         amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
8739                         animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
8740         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8741         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8742         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8743                         for (j = 0;j < batchnumvertices;j++)
8744                         {
8745                                 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);
8746                                 rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1]                                ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8747                         }
8748                 }
8749         }
8750
8751         if (needsupdate & batchneed & (BATCHNEED_VERTEXMESH_VERTEX | BATCHNEED_VERTEXMESH_NORMAL | BATCHNEED_VERTEXMESH_VECTOR | BATCHNEED_VERTEXMESH_VERTEXCOLOR | BATCHNEED_VERTEXMESH_TEXCOORD | BATCHNEED_VERTEXMESH_LIGHTMAP))
8752         {
8753                 // convert the modified arrays to vertex structs
8754 //              rsurface.batchvertexmesh = R_FrameData_Alloc(batchnumvertices * sizeof(r_vertexmesh_t));
8755 //              rsurface.batchvertexmesh_vertexbuffer = NULL;
8756 //              rsurface.batchvertexmesh_bufferoffset = 0;
8757                 if (batchneed & BATCHNEED_VERTEXMESH_VERTEX)
8758                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8759                                 VectorCopy(rsurface.batchvertex3f + 3*j, vertexmesh->vertex3f);
8760                 if (batchneed & BATCHNEED_VERTEXMESH_NORMAL)
8761                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8762                                 VectorCopy(rsurface.batchnormal3f + 3*j, vertexmesh->normal3f);
8763                 if (batchneed & BATCHNEED_VERTEXMESH_VECTOR)
8764                 {
8765                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8766                         {
8767                                 VectorCopy(rsurface.batchsvector3f + 3*j, vertexmesh->svector3f);
8768                                 VectorCopy(rsurface.batchtvector3f + 3*j, vertexmesh->tvector3f);
8769                         }
8770                 }
8771                 if ((batchneed & BATCHNEED_VERTEXMESH_VERTEXCOLOR) && rsurface.batchlightmapcolor4f)
8772                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8773                                 Vector4Copy(rsurface.batchlightmapcolor4f + 4*j, vertexmesh->color4f);
8774                 if (batchneed & BATCHNEED_VERTEXMESH_TEXCOORD)
8775                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8776                                 Vector2Copy(rsurface.batchtexcoordtexture2f + 2*j, vertexmesh->texcoordtexture2f);
8777                 if ((batchneed & BATCHNEED_VERTEXMESH_LIGHTMAP) && rsurface.batchtexcoordlightmap2f)
8778                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8779                                 Vector2Copy(rsurface.batchtexcoordlightmap2f + 2*j, vertexmesh->texcoordlightmap2f);
8780                 if ((batchneed & BATCHNEED_VERTEXMESH_SKELETAL) && rsurface.batchskeletalindex4ub)
8781                 {
8782                         for (j = 0, vertexmesh = rsurface.batchvertexmesh;j < batchnumvertices;j++, vertexmesh++)
8783                         {
8784                                 Vector4Copy(rsurface.batchskeletalindex4ub + 4*j, vertexmesh->skeletalindex4ub);
8785                                 Vector4Copy(rsurface.batchskeletalweight4ub + 4*j, vertexmesh->skeletalweight4ub);
8786                         }
8787                 }
8788         }
8789
8790         // upload buffer data for the dynamic batch
8791         if (((r_batch_dynamicbuffer.integer || gl_vbo_dynamicvertex.integer || gl_vbo_dynamicindex.integer) && vid.support.arb_vertex_buffer_object && gl_vbo.integer) || vid.forcevbo)
8792         {
8793                 if (rsurface.batchvertexmesh)
8794                         rsurface.batchvertexmesh_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(r_vertexmesh_t), rsurface.batchvertexmesh, R_BUFFERDATA_VERTEX, &rsurface.batchvertexmesh_bufferoffset);
8795                 else
8796                 {
8797                         if (rsurface.batchvertex3f)
8798                                 rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
8799                         if (rsurface.batchsvector3f)
8800                                 rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
8801                         if (rsurface.batchtvector3f)
8802                                 rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
8803                         if (rsurface.batchnormal3f)
8804                                 rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
8805                         if (rsurface.batchlightmapcolor4f)
8806                                 rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
8807                         if (rsurface.batchtexcoordtexture2f)
8808                                 rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
8809                         if (rsurface.batchtexcoordlightmap2f)
8810                                 rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
8811                         if (rsurface.batchskeletalindex4ub)
8812                                 rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
8813                         if (rsurface.batchskeletalweight4ub)
8814                                 rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
8815                 }
8816                 if (rsurface.batchelement3s)
8817                         rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
8818                 else if (rsurface.batchelement3i)
8819                         rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
8820         }
8821 }
8822
8823 void RSurf_DrawBatch(void)
8824 {
8825         // sometimes a zero triangle surface (usually a degenerate patch) makes it
8826         // through the pipeline, killing it earlier in the pipeline would have
8827         // per-surface overhead rather than per-batch overhead, so it's best to
8828         // reject it here, before it hits glDraw.
8829         if (rsurface.batchnumtriangles == 0)
8830                 return;
8831 #if 0
8832         // batch debugging code
8833         if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f)
8834         {
8835                 int i;
8836                 int j;
8837                 int c;
8838                 const int *e;
8839                 e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3;
8840                 for (i = 0;i < rsurface.batchnumtriangles*3;i++)
8841                 {
8842                         c = e[i];
8843                         for (j = 0;j < rsurface.entity->model->num_surfaces;j++)
8844                         {
8845                                 if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
8846                                 {
8847                                         if (rsurface.modelsurfaces[j].texture != rsurface.texture)
8848                                                 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);
8849                                         break;
8850                                 }
8851                         }
8852                 }
8853         }
8854 #endif
8855         if (rsurface.batchmultidraw)
8856         {
8857                 // issue multiple draws rather than copying index data
8858                 int numsurfaces = rsurface.batchmultidrawnumsurfaces;
8859                 const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist;
8860                 int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle;
8861                 for (i = 0;i < numsurfaces;)
8862                 {
8863                         // combine consecutive surfaces as one draw
8864                         for (k = i, j = i + 1;j < numsurfaces;k = j, j++)
8865                                 if (surfacelist[j] != surfacelist[k] + 1)
8866                                         break;
8867                         firstvertex = surfacelist[i]->num_firstvertex;
8868                         endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices;
8869                         firsttriangle = surfacelist[i]->num_firsttriangle;
8870                         endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles;
8871                         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);
8872                         i = j;
8873                 }
8874         }
8875         else
8876         {
8877                 // there is only one consecutive run of index data (may have been combined)
8878                 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);
8879         }
8880 }
8881
8882 static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface)
8883 {
8884         // pick the closest matching water plane
8885         int planeindex, vertexindex, bestplaneindex = -1;
8886         float d, bestd;
8887         vec3_t vert;
8888         const float *v;
8889         r_waterstate_waterplane_t *p;
8890         qboolean prepared = false;
8891         bestd = 0;
8892         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
8893         {
8894                 if(p->camera_entity != rsurface.texture->camera_entity)
8895                         continue;
8896                 d = 0;
8897                 if(!prepared)
8898                 {
8899                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
8900                         prepared = true;
8901                         if(rsurface.batchnumvertices == 0)
8902                                 break;
8903                 }
8904                 for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
8905                 {
8906                         Matrix4x4_Transform(&rsurface.matrix, v, vert);
8907                         d += fabs(PlaneDiff(vert, &p->plane));
8908                 }
8909                 if (bestd > d || bestplaneindex < 0)
8910                 {
8911                         bestd = d;
8912                         bestplaneindex = planeindex;
8913                 }
8914         }
8915         return bestplaneindex;
8916         // NOTE: this MAY return a totally unrelated water plane; we can ignore
8917         // this situation though, as it might be better to render single larger
8918         // batches with useless stuff (backface culled for example) than to
8919         // render multiple smaller batches
8920 }
8921
8922 void RSurf_SetupDepthAndCulling(void)
8923 {
8924         // submodels are biased to avoid z-fighting with world surfaces that they
8925         // may be exactly overlapping (avoids z-fighting artifacts on certain
8926         // doors and things in Quake maps)
8927         GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
8928         GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
8929         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
8930         GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
8931 }
8932
8933 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8934 {
8935         int i, j;
8936         // transparent sky would be ridiculous
8937         if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8938                 return;
8939         R_SetupShader_Generic_NoTexture(false, false);
8940         skyrenderlater = true;
8941         RSurf_SetupDepthAndCulling();
8942         GL_DepthMask(true);
8943
8944         // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
8945         if (r_sky_scissor.integer)
8946         {
8947                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8948                 for (i = 0; i < texturenumsurfaces; i++)
8949                 {
8950                         const msurface_t *surf = texturesurfacelist[i];
8951                         const float *v;
8952                         float p[3];
8953                         float mins[3], maxs[3];
8954                         int scissor[4];
8955                         for (j = 0, v = rsurface.batchvertex3f + 3 * surf->num_firstvertex; j < surf->num_vertices; j++, v += 3)
8956                         {
8957                                 Matrix4x4_Transform(&rsurface.matrix, v, p);
8958                                 if (j > 0)
8959                                 {
8960                                         if (mins[0] > p[0]) mins[0] = p[0];
8961                                         if (mins[1] > p[1]) mins[1] = p[1];
8962                                         if (mins[2] > p[2]) mins[2] = p[2];
8963                                         if (maxs[0] < p[0]) maxs[0] = p[0];
8964                                         if (maxs[1] < p[1]) maxs[1] = p[1];
8965                                         if (maxs[2] < p[2]) maxs[2] = p[2];
8966                                 }
8967                                 else
8968                                 {
8969                                         VectorCopy(p, mins);
8970                                         VectorCopy(p, maxs);
8971                                 }
8972                         }
8973                         if (!R_ScissorForBBox(mins, maxs, scissor))
8974                         {
8975                                 if (skyscissor[2])
8976                                 {
8977                                         if (skyscissor[0] > scissor[0])
8978                                         {
8979                                                 skyscissor[2] += skyscissor[0] - scissor[0];
8980                                                 skyscissor[0] = scissor[0];
8981                                         }
8982                                         if (skyscissor[1] > scissor[1])
8983                                         {
8984                                                 skyscissor[3] += skyscissor[1] - scissor[1];
8985                                                 skyscissor[1] = scissor[1];
8986                                         }
8987                                         if (skyscissor[0] + skyscissor[2] < scissor[0] + scissor[2])
8988                                                 skyscissor[2] = scissor[0] + scissor[2] - skyscissor[0];
8989                                         if (skyscissor[1] + skyscissor[3] < scissor[1] + scissor[3])
8990                                                 skyscissor[3] = scissor[1] + scissor[3] - skyscissor[1];
8991                                 }
8992                                 else
8993                                         Vector4Copy(scissor, skyscissor);
8994                         }
8995                 }
8996         }
8997
8998         // LadyHavoc: HalfLife maps have freaky skypolys so don't use
8999         // skymasking on them, and Quake3 never did sky masking (unlike
9000         // software Quake and software Quake2), so disable the sky masking
9001         // in Quake3 maps as it causes problems with q3map2 sky tricks,
9002         // and skymasking also looks very bad when noclipping outside the
9003         // level, so don't use it then either.
9004         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)
9005         {
9006                 R_Mesh_ResetTextureState();
9007                 if (skyrendermasked)
9008                 {
9009                         R_SetupShader_DepthOrShadow(false, false, false);
9010                         // depth-only (masking)
9011                         GL_ColorMask(0, 0, 0, 0);
9012                         // just to make sure that braindead drivers don't draw
9013                         // anything despite that colormask...
9014                         GL_BlendFunc(GL_ZERO, GL_ONE);
9015                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9016                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9017                 }
9018                 else
9019                 {
9020                         R_SetupShader_Generic_NoTexture(false, false);
9021                         // fog sky
9022                         GL_BlendFunc(GL_ONE, GL_ZERO);
9023                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9024                         GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
9025                         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9026                 }
9027                 RSurf_DrawBatch();
9028                 if (skyrendermasked)
9029                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
9030         }
9031         R_Mesh_ResetTextureState();
9032         GL_Color(1, 1, 1, 1);
9033 }
9034
9035 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
9036 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
9037 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
9038 {
9039         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
9040                 return;
9041         if (prepass)
9042         {
9043                 // render screenspace normalmap to texture
9044                 GL_DepthMask(true);
9045                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false);
9046                 RSurf_DrawBatch();
9047                 return;
9048         }
9049
9050         // bind lightmap texture
9051
9052         // water/refraction/reflection/camera surfaces have to be handled specially
9053         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)))
9054         {
9055                 int start, end, startplaneindex;
9056                 for (start = 0;start < texturenumsurfaces;start = end)
9057                 {
9058                         startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]);
9059                         if(startplaneindex < 0)
9060                         {
9061                                 // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this.
9062                                 // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags);
9063                                 end = start + 1;
9064                                 continue;
9065                         }
9066                         for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++)
9067                                 ;
9068                         // now that we have a batch using the same planeindex, render it
9069                         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)))
9070                         {
9071                                 // render water or distortion background
9072                                 GL_DepthMask(true);
9073                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
9074                                 RSurf_DrawBatch();
9075                                 // blend surface on top
9076                                 GL_DepthMask(false);
9077                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false);
9078                                 RSurf_DrawBatch();
9079                         }
9080                         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
9081                         {
9082                                 // render surface with reflection texture as input
9083                                 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
9084                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false);
9085                                 RSurf_DrawBatch();
9086                         }
9087                 }
9088                 return;
9089         }
9090
9091         // render surface batch normally
9092         GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
9093         R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0);
9094         RSurf_DrawBatch();
9095 }
9096
9097 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth)
9098 {
9099         int vi;
9100         int j;
9101         r_vertexgeneric_t *batchvertex;
9102         float c[4];
9103         texture_t *t = rsurface.texture;
9104
9105 //      R_Mesh_ResetTextureState();
9106         R_SetupShader_Generic_NoTexture(false, false);
9107
9108         if(t && t->currentskinframe)
9109         {
9110                 memcpy(c, t->currentskinframe->avgcolor, sizeof(c));
9111                 c[3] *= t->currentalpha;
9112         }
9113         else
9114         {
9115                 c[0] = 1;
9116                 c[1] = 0;
9117                 c[2] = 1;
9118                 c[3] = 1;
9119         }
9120
9121         if (t->pantstexture || t->shirttexture)
9122         {
9123                 c[0] = 0.5 * (t->render_colormap_pants[0] * 0.3 + t->render_colormap_shirt[0] * 0.7);
9124                 c[1] = 0.5 * (t->render_colormap_pants[1] * 0.3 + t->render_colormap_shirt[1] * 0.7);
9125                 c[2] = 0.5 * (t->render_colormap_pants[2] * 0.3 + t->render_colormap_shirt[2] * 0.7);
9126         }
9127
9128         // brighten it up (as texture value 127 means "unlit")
9129         c[0] *= 2 * r_refdef.view.colorscale;
9130         c[1] *= 2 * r_refdef.view.colorscale;
9131         c[2] *= 2 * r_refdef.view.colorscale;
9132
9133         if(t->currentmaterialflags & MATERIALFLAG_WATERALPHA)
9134                 c[3] *= r_wateralpha.value;
9135
9136         if(t->currentmaterialflags & MATERIALFLAG_ALPHA && c[3] != 1)
9137         {
9138                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9139                 GL_DepthMask(false);
9140         }
9141         else if(t->currentmaterialflags & MATERIALFLAG_ADD)
9142         {
9143                 GL_BlendFunc(GL_ONE, GL_ONE);
9144                 GL_DepthMask(false);
9145         }
9146         else if(t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
9147         {
9148                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // can't do alpha test without texture, so let's blend instead
9149                 GL_DepthMask(false);
9150         }
9151         else if(t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
9152         {
9153                 GL_BlendFunc(t->customblendfunc[0], t->customblendfunc[1]);
9154                 GL_DepthMask(false);
9155         }
9156         else
9157         {
9158                 GL_BlendFunc(GL_ONE, GL_ZERO);
9159                 GL_DepthMask(writedepth);
9160         }
9161
9162         if (!r_refdef.view.showdebug)
9163         {
9164                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9165                 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchnumvertices);
9166                 for (j = 0, vi = 0;j < rsurface.batchnumvertices;j++, vi++)
9167                 {
9168                         VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
9169                         Vector4Set(batchvertex[vi].color4f, 0, 0, 0, 1);
9170                 }
9171                 R_Mesh_PrepareVertices_Generic_Unlock();
9172                 RSurf_DrawBatch();
9173         }
9174         else if (r_showsurfaces.integer == 4)
9175         {
9176                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9177                 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchnumvertices);
9178                 for (j = 0, vi = 0;j < rsurface.batchnumvertices;j++, vi++)
9179                 {
9180                         float d = (vi << 3) * (1.0f / 256.0f);
9181                         VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
9182                         Vector4Set(batchvertex[vi].color4f, d, d, d, 1);
9183                 }
9184                 R_Mesh_PrepareVertices_Generic_Unlock();
9185                 RSurf_DrawBatch();
9186         }
9187         else if (r_showsurfaces.integer == 2)
9188         {
9189                 const int *e;
9190                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9191                 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(3*rsurface.batchnumtriangles);
9192                 for (j = 0, e = rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle;j < rsurface.batchnumtriangles;j++, e += 3)
9193                 {
9194                         float d = ((j + rsurface.batchfirsttriangle) << 3) * (1.0f / 256.0f);
9195                         VectorCopy(rsurface.batchvertex3f + 3*e[0], batchvertex[j*3+0].vertex3f);
9196                         VectorCopy(rsurface.batchvertex3f + 3*e[1], batchvertex[j*3+1].vertex3f);
9197                         VectorCopy(rsurface.batchvertex3f + 3*e[2], batchvertex[j*3+2].vertex3f);
9198                         Vector4Set(batchvertex[j*3+0].color4f, d, d, d, 1);
9199                         Vector4Set(batchvertex[j*3+1].color4f, d, d, d, 1);
9200                         Vector4Set(batchvertex[j*3+2].color4f, d, d, d, 1);
9201                 }
9202                 R_Mesh_PrepareVertices_Generic_Unlock();
9203                 R_Mesh_Draw(0, rsurface.batchnumtriangles*3, 0, rsurface.batchnumtriangles, NULL, NULL, 0, NULL, NULL, 0);
9204         }
9205         else
9206         {
9207                 int texturesurfaceindex;
9208                 int k;
9209                 const msurface_t *surface;
9210                 float surfacecolor4f[4];
9211                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
9212                 batchvertex = R_Mesh_PrepareVertices_Generic_Lock(rsurface.batchfirstvertex + rsurface.batchnumvertices);
9213                 vi = 0;
9214                 for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
9215                 {
9216                         surface = texturesurfacelist[texturesurfaceindex];
9217                         k = (int)(((size_t)surface) / sizeof(msurface_t));
9218                         Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
9219                         for (j = 0;j < surface->num_vertices;j++)
9220                         {
9221                                 VectorCopy(rsurface.batchvertex3f + 3*vi, batchvertex[vi].vertex3f);
9222                                 Vector4Copy(surfacecolor4f, batchvertex[vi].color4f);
9223                                 vi++;
9224                         }
9225                 }
9226                 R_Mesh_PrepareVertices_Generic_Unlock();
9227                 RSurf_DrawBatch();
9228         }
9229 }
9230
9231 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean prepass)
9232 {
9233         CHECKGLERROR
9234         RSurf_SetupDepthAndCulling();
9235         if (r_showsurfaces.integer)
9236         {
9237                 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
9238                 return;
9239         }
9240         switch (vid.renderpath)
9241         {
9242         case RENDERPATH_GL20:
9243         case RENDERPATH_GLES2:
9244                 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
9245                 break;
9246         }
9247         CHECKGLERROR
9248 }
9249
9250 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9251 {
9252         int i, j;
9253         int texturenumsurfaces, endsurface;
9254         texture_t *texture;
9255         const msurface_t *surface;
9256         const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
9257
9258         RSurf_ActiveModelEntity(ent, true, true, false);
9259
9260         if (r_transparentdepthmasking.integer)
9261         {
9262                 qboolean setup = false;
9263                 for (i = 0;i < numsurfaces;i = j)
9264                 {
9265                         j = i + 1;
9266                         surface = rsurface.modelsurfaces + surfacelist[i];
9267                         texture = surface->texture;
9268                         rsurface.texture = R_GetCurrentTexture(texture);
9269                         rsurface.lightmaptexture = NULL;
9270                         rsurface.deluxemaptexture = NULL;
9271                         rsurface.uselightmaptexture = false;
9272                         // scan ahead until we find a different texture
9273                         endsurface = min(i + 1024, numsurfaces);
9274                         texturenumsurfaces = 0;
9275                         texturesurfacelist[texturenumsurfaces++] = surface;
9276                         for (;j < endsurface;j++)
9277                         {
9278                                 surface = rsurface.modelsurfaces + surfacelist[j];
9279                                 if (texture != surface->texture)
9280                                         break;
9281                                 texturesurfacelist[texturenumsurfaces++] = surface;
9282                         }
9283                         if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
9284                                 continue;
9285                         // render the range of surfaces as depth
9286                         if (!setup)
9287                         {
9288                                 setup = true;
9289                                 GL_ColorMask(0,0,0,0);
9290                                 GL_Color(1,1,1,1);
9291                                 GL_DepthTest(true);
9292                                 GL_BlendFunc(GL_ONE, GL_ZERO);
9293                                 GL_DepthMask(true);
9294 //                              R_Mesh_ResetTextureState();
9295                         }
9296                         RSurf_SetupDepthAndCulling();
9297                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9298                         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
9299                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9300                         RSurf_DrawBatch();
9301                 }
9302                 if (setup)
9303                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
9304         }
9305
9306         for (i = 0;i < numsurfaces;i = j)
9307         {
9308                 j = i + 1;
9309                 surface = rsurface.modelsurfaces + surfacelist[i];
9310                 texture = surface->texture;
9311                 rsurface.texture = R_GetCurrentTexture(texture);
9312                 // scan ahead until we find a different texture
9313                 endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
9314                 texturenumsurfaces = 0;
9315                 texturesurfacelist[texturenumsurfaces++] = surface;
9316                 if(FAKELIGHT_ENABLED)
9317                 {
9318                         rsurface.lightmaptexture = NULL;
9319                         rsurface.deluxemaptexture = NULL;
9320                         rsurface.uselightmaptexture = false;
9321                         for (;j < endsurface;j++)
9322                         {
9323                                 surface = rsurface.modelsurfaces + surfacelist[j];
9324                                 if (texture != surface->texture)
9325                                         break;
9326                                 texturesurfacelist[texturenumsurfaces++] = surface;
9327                         }
9328                 }
9329                 else
9330                 {
9331                         rsurface.lightmaptexture = surface->lightmaptexture;
9332                         rsurface.deluxemaptexture = surface->deluxemaptexture;
9333                         rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
9334                         for (;j < endsurface;j++)
9335                         {
9336                                 surface = rsurface.modelsurfaces + surfacelist[j];
9337                                 if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture)
9338                                         break;
9339                                 texturesurfacelist[texturenumsurfaces++] = surface;
9340                         }
9341                 }
9342                 // render the range of surfaces
9343                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false);
9344         }
9345         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
9346 }
9347
9348 static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
9349 {
9350         // transparent surfaces get pushed off into the transparent queue
9351         int surfacelistindex;
9352         const msurface_t *surface;
9353         vec3_t tempcenter, center;
9354         for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
9355         {
9356                 surface = texturesurfacelist[surfacelistindex];
9357                 if (r_transparent_sortsurfacesbynearest.integer)
9358                 {
9359                         tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]);
9360                         tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]);
9361                         tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]);
9362                 }
9363                 else
9364                 {
9365                         tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
9366                         tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
9367                         tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
9368                 }
9369                 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
9370                 if (rsurface.entity->transparent_offset) // transparent offset
9371                 {
9372                         center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset;
9373                         center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset;
9374                         center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset;
9375                 }
9376                 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);
9377         }
9378 }
9379
9380 static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist)
9381 {
9382         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
9383                 return;
9384         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
9385                 return;
9386         RSurf_SetupDepthAndCulling();
9387         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
9388         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
9389         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
9390         RSurf_DrawBatch();
9391 }
9392
9393 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qboolean writedepth, qboolean depthonly, qboolean prepass)
9394 {
9395         CHECKGLERROR
9396         if (depthonly)
9397                 R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
9398         else if (prepass)
9399         {
9400                 if (!rsurface.texture->currentnumlayers)
9401                         return;
9402                 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
9403                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9404                 else
9405                         R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass);
9406         }
9407         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3))
9408                 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
9409         else if (!rsurface.texture->currentnumlayers)
9410                 return;
9411         else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
9412         {
9413                 // in the deferred case, transparent surfaces were queued during prepass
9414                 if (!r_shadow_usingdeferredprepass)
9415                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
9416         }
9417         else
9418         {
9419                 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
9420                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass);
9421         }
9422         CHECKGLERROR
9423 }
9424
9425 static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qboolean writedepth, qboolean depthonly, qboolean prepass)
9426 {
9427         int i, j;
9428         texture_t *texture;
9429         R_FrameData_SetMark();
9430         // break the surface list down into batches by texture and use of lightmapping
9431         for (i = 0;i < numsurfaces;i = j)
9432         {
9433                 j = i + 1;
9434                 // texture is the base texture pointer, rsurface.texture is the
9435                 // current frame/skin the texture is directing us to use (for example
9436                 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
9437                 // use skin 1 instead)
9438                 texture = surfacelist[i]->texture;
9439                 rsurface.texture = R_GetCurrentTexture(texture);
9440                 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
9441                 {
9442                         // if this texture is not the kind we want, skip ahead to the next one
9443                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9444                                 ;
9445                         continue;
9446                 }
9447                 if(FAKELIGHT_ENABLED || depthonly || prepass)
9448                 {
9449                         rsurface.lightmaptexture = NULL;
9450                         rsurface.deluxemaptexture = NULL;
9451                         rsurface.uselightmaptexture = false;
9452                         // simply scan ahead until we find a different texture or lightmap state
9453                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
9454                                 ;
9455                 }
9456                 else
9457                 {
9458                         rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
9459                         rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
9460                         rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
9461                         // simply scan ahead until we find a different texture or lightmap state
9462                         for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
9463                                 ;
9464                 }
9465                 // render the range of surfaces
9466                 R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass);
9467         }
9468         R_FrameData_ReturnToMark();
9469 }
9470
9471 float locboxvertex3f[6*4*3] =
9472 {
9473         1,0,1, 1,0,0, 1,1,0, 1,1,1,
9474         0,1,1, 0,1,0, 0,0,0, 0,0,1,
9475         1,1,1, 1,1,0, 0,1,0, 0,1,1,
9476         0,0,1, 0,0,0, 1,0,0, 1,0,1,
9477         0,0,1, 1,0,1, 1,1,1, 0,1,1,
9478         1,0,0, 0,0,0, 0,1,0, 1,1,0
9479 };
9480
9481 unsigned short locboxelements[6*2*3] =
9482 {
9483          0, 1, 2, 0, 2, 3,
9484          4, 5, 6, 4, 6, 7,
9485          8, 9,10, 8,10,11,
9486         12,13,14, 12,14,15,
9487         16,17,18, 16,18,19,
9488         20,21,22, 20,22,23
9489 };
9490
9491 static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9492 {
9493         int i, j;
9494         cl_locnode_t *loc = (cl_locnode_t *)ent;
9495         vec3_t mins, size;
9496         float vertex3f[6*4*3];
9497         CHECKGLERROR
9498         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9499         GL_DepthMask(false);
9500         GL_DepthRange(0, 1);
9501         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9502         GL_DepthTest(true);
9503         GL_CullFace(GL_NONE);
9504         R_EntityMatrix(&identitymatrix);
9505
9506 //      R_Mesh_ResetTextureState();
9507
9508         i = surfacelist[0];
9509         GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9510                          ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9511                          ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9512                         surfacelist[0] < 0 ? 0.5f : 0.125f);
9513
9514         if (VectorCompare(loc->mins, loc->maxs))
9515         {
9516                 VectorSet(size, 2, 2, 2);
9517                 VectorMA(loc->mins, -0.5f, size, mins);
9518         }
9519         else
9520         {
9521                 VectorCopy(loc->mins, mins);
9522                 VectorSubtract(loc->maxs, loc->mins, size);
9523         }
9524
9525         for (i = 0;i < 6*4*3;)
9526                 for (j = 0;j < 3;j++, i++)
9527                         vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
9528
9529         R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
9530         R_SetupShader_Generic_NoTexture(false, false);
9531         R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
9532 }
9533
9534 void R_DrawLocs(void)
9535 {
9536         int index;
9537         cl_locnode_t *loc, *nearestloc;
9538         vec3_t center;
9539         nearestloc = CL_Locs_FindNearest(cl.movement_origin);
9540         for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
9541         {
9542                 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
9543                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
9544         }
9545 }
9546
9547 void R_DecalSystem_Reset(decalsystem_t *decalsystem)
9548 {
9549         if (decalsystem->decals)
9550                 Mem_Free(decalsystem->decals);
9551         memset(decalsystem, 0, sizeof(*decalsystem));
9552 }
9553
9554 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)
9555 {
9556         tridecal_t *decal;
9557         tridecal_t *decals;
9558         int i;
9559
9560         // expand or initialize the system
9561         if (decalsystem->maxdecals <= decalsystem->numdecals)
9562         {
9563                 decalsystem_t old = *decalsystem;
9564                 qboolean useshortelements;
9565                 decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2);
9566                 useshortelements = decalsystem->maxdecals * 3 <= 65536;
9567                 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)));
9568                 decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals);
9569                 decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12);
9570                 decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6);
9571                 decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
9572                 decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
9573                 if (decalsystem->numdecals)
9574                         memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
9575                 if (old.decals)
9576                         Mem_Free(old.decals);
9577                 for (i = 0;i < decalsystem->maxdecals*3;i++)
9578                         decalsystem->element3i[i] = i;
9579                 if (useshortelements)
9580                         for (i = 0;i < decalsystem->maxdecals*3;i++)
9581                                 decalsystem->element3s[i] = i;
9582         }
9583
9584         // grab a decal and search for another free slot for the next one
9585         decals = decalsystem->decals;
9586         decal = decalsystem->decals + (i = decalsystem->freedecal++);
9587         for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4f[0][3];i++)
9588                 ;
9589         decalsystem->freedecal = i;
9590         if (decalsystem->numdecals <= i)
9591                 decalsystem->numdecals = i + 1;
9592
9593         // initialize the decal
9594         decal->lived = 0;
9595         decal->triangleindex = triangleindex;
9596         decal->surfaceindex = surfaceindex;
9597         decal->decalsequence = decalsequence;
9598         decal->color4f[0][0] = c0[0];
9599         decal->color4f[0][1] = c0[1];
9600         decal->color4f[0][2] = c0[2];
9601         decal->color4f[0][3] = 1;
9602         decal->color4f[1][0] = c1[0];
9603         decal->color4f[1][1] = c1[1];
9604         decal->color4f[1][2] = c1[2];
9605         decal->color4f[1][3] = 1;
9606         decal->color4f[2][0] = c2[0];
9607         decal->color4f[2][1] = c2[1];
9608         decal->color4f[2][2] = c2[2];
9609         decal->color4f[2][3] = 1;
9610         decal->vertex3f[0][0] = v0[0];
9611         decal->vertex3f[0][1] = v0[1];
9612         decal->vertex3f[0][2] = v0[2];
9613         decal->vertex3f[1][0] = v1[0];
9614         decal->vertex3f[1][1] = v1[1];
9615         decal->vertex3f[1][2] = v1[2];
9616         decal->vertex3f[2][0] = v2[0];
9617         decal->vertex3f[2][1] = v2[1];
9618         decal->vertex3f[2][2] = v2[2];
9619         decal->texcoord2f[0][0] = t0[0];
9620         decal->texcoord2f[0][1] = t0[1];
9621         decal->texcoord2f[1][0] = t1[0];
9622         decal->texcoord2f[1][1] = t1[1];
9623         decal->texcoord2f[2][0] = t2[0];
9624         decal->texcoord2f[2][1] = t2[1];
9625         TriangleNormal(v0, v1, v2, decal->plane);
9626         VectorNormalize(decal->plane);
9627         decal->plane[3] = DotProduct(v0, decal->plane);
9628 }
9629
9630 extern cvar_t cl_decals_bias;
9631 extern cvar_t cl_decals_models;
9632 extern cvar_t cl_decals_newsystem_intensitymultiplier;
9633 // baseparms, parms, temps
9634 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)
9635 {
9636         int cornerindex;
9637         int index;
9638         float v[9][3];
9639         const float *vertex3f;
9640         const float *normal3f;
9641         int numpoints;
9642         float points[2][9][3];
9643         float temp[3];
9644         float tc[9][2];
9645         float f;
9646         float c[9][4];
9647         const int *e;
9648
9649         e = rsurface.modelelement3i + 3*triangleindex;
9650
9651         vertex3f = rsurface.modelvertex3f;
9652         normal3f = rsurface.modelnormal3f;
9653
9654         if (normal3f)
9655         {
9656                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9657                 {
9658                         index = 3*e[cornerindex];
9659                         VectorMA(vertex3f + index, cl_decals_bias.value, normal3f + index, v[cornerindex]);
9660                 }
9661         }
9662         else
9663         {
9664                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9665                 {
9666                         index = 3*e[cornerindex];
9667                         VectorCopy(vertex3f + index, v[cornerindex]);
9668                 }
9669         }
9670
9671         // cull backfaces
9672         //TriangleNormal(v[0], v[1], v[2], normal);
9673         //if (DotProduct(normal, localnormal) < 0.0f)
9674         //      continue;
9675         // clip by each of the box planes formed from the projection matrix
9676         // if anything survives, we emit the decal
9677         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]);
9678         if (numpoints < 3)
9679                 return;
9680         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]);
9681         if (numpoints < 3)
9682                 return;
9683         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]);
9684         if (numpoints < 3)
9685                 return;
9686         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]);
9687         if (numpoints < 3)
9688                 return;
9689         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]);
9690         if (numpoints < 3)
9691                 return;
9692         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]);
9693         if (numpoints < 3)
9694                 return;
9695         // some part of the triangle survived, so we have to accept it...
9696         if (dynamic)
9697         {
9698                 // dynamic always uses the original triangle
9699                 numpoints = 3;
9700                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9701                 {
9702                         index = 3*e[cornerindex];
9703                         VectorCopy(vertex3f + index, v[cornerindex]);
9704                 }
9705         }
9706         for (cornerindex = 0;cornerindex < numpoints;cornerindex++)
9707         {
9708                 // convert vertex positions to texcoords
9709                 Matrix4x4_Transform(projection, v[cornerindex], temp);
9710                 tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
9711                 tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
9712                 // calculate distance fade from the projection origin
9713                 f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
9714                 f = bound(0.0f, f, 1.0f);
9715                 c[cornerindex][0] = r * f;
9716                 c[cornerindex][1] = g * f;
9717                 c[cornerindex][2] = b * f;
9718                 c[cornerindex][3] = 1.0f;
9719                 //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
9720         }
9721         if (dynamic)
9722                 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);
9723         else
9724                 for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
9725                         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);
9726 }
9727 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)
9728 {
9729         matrix4x4_t projection;
9730         decalsystem_t *decalsystem;
9731         qboolean dynamic;
9732         dp_model_t *model;
9733         const msurface_t *surface;
9734         const msurface_t *surfaces;
9735         const int *surfacelist;
9736         const texture_t *texture;
9737         int numtriangles;
9738         int numsurfacelist;
9739         int surfacelistindex;
9740         int surfaceindex;
9741         int triangleindex;
9742         float localorigin[3];
9743         float localnormal[3];
9744         float localmins[3];
9745         float localmaxs[3];
9746         float localsize;
9747         //float normal[3];
9748         float planes[6][4];
9749         float angles[3];
9750         bih_t *bih;
9751         int bih_triangles_count;
9752         int bih_triangles[256];
9753         int bih_surfaces[256];
9754
9755         decalsystem = &ent->decalsystem;
9756         model = ent->model;
9757         if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST)))
9758         {
9759                 R_DecalSystem_Reset(&ent->decalsystem);
9760                 return;
9761         }
9762
9763         if (!model->brush.data_leafs && !cl_decals_models.integer)
9764         {
9765                 if (decalsystem->model)
9766                         R_DecalSystem_Reset(decalsystem);
9767                 return;
9768         }
9769
9770         if (decalsystem->model != model)
9771                 R_DecalSystem_Reset(decalsystem);
9772         decalsystem->model = model;
9773
9774         RSurf_ActiveModelEntity(ent, true, false, false);
9775
9776         Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
9777         Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
9778         VectorNormalize(localnormal);
9779         localsize = worldsize*rsurface.inversematrixscale;
9780         localmins[0] = localorigin[0] - localsize;
9781         localmins[1] = localorigin[1] - localsize;
9782         localmins[2] = localorigin[2] - localsize;
9783         localmaxs[0] = localorigin[0] + localsize;
9784         localmaxs[1] = localorigin[1] + localsize;
9785         localmaxs[2] = localorigin[2] + localsize;
9786
9787         //VectorCopy(localnormal, planes[4]);
9788         //VectorVectors(planes[4], planes[2], planes[0]);
9789         AnglesFromVectors(angles, localnormal, NULL, false);
9790         AngleVectors(angles, planes[0], planes[2], planes[4]);
9791         VectorNegate(planes[0], planes[1]);
9792         VectorNegate(planes[2], planes[3]);
9793         VectorNegate(planes[4], planes[5]);
9794         planes[0][3] = DotProduct(planes[0], localorigin) - localsize;
9795         planes[1][3] = DotProduct(planes[1], localorigin) - localsize;
9796         planes[2][3] = DotProduct(planes[2], localorigin) - localsize;
9797         planes[3][3] = DotProduct(planes[3], localorigin) - localsize;
9798         planes[4][3] = DotProduct(planes[4], localorigin) - localsize;
9799         planes[5][3] = DotProduct(planes[5], localorigin) - localsize;
9800
9801 #if 1
9802 // works
9803 {
9804         matrix4x4_t forwardprojection;
9805         Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize);
9806         Matrix4x4_Invert_Simple(&projection, &forwardprojection);
9807 }
9808 #else
9809 // broken
9810 {
9811         float projectionvector[4][3];
9812         VectorScale(planes[0], ilocalsize, projectionvector[0]);
9813         VectorScale(planes[2], ilocalsize, projectionvector[1]);
9814         VectorScale(planes[4], ilocalsize, projectionvector[2]);
9815         projectionvector[0][0] = planes[0][0] * ilocalsize;
9816         projectionvector[0][1] = planes[1][0] * ilocalsize;
9817         projectionvector[0][2] = planes[2][0] * ilocalsize;
9818         projectionvector[1][0] = planes[0][1] * ilocalsize;
9819         projectionvector[1][1] = planes[1][1] * ilocalsize;
9820         projectionvector[1][2] = planes[2][1] * ilocalsize;
9821         projectionvector[2][0] = planes[0][2] * ilocalsize;
9822         projectionvector[2][1] = planes[1][2] * ilocalsize;
9823         projectionvector[2][2] = planes[2][2] * ilocalsize;
9824         projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]);
9825         projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]);
9826         projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]);
9827         Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]);
9828 }
9829 #endif
9830
9831         dynamic = model->surfmesh.isanimated;
9832         numsurfacelist = model->nummodelsurfaces;
9833         surfacelist = model->sortedmodelsurfaces;
9834         surfaces = model->data_surfaces;
9835
9836         bih = NULL;
9837         bih_triangles_count = -1;
9838         if(!dynamic)
9839         {
9840                 if(model->render_bih.numleafs)
9841                         bih = &model->render_bih;
9842                 else if(model->collision_bih.numleafs)
9843                         bih = &model->collision_bih;
9844         }
9845         if(bih)
9846                 bih_triangles_count = BIH_GetTriangleListForBox(bih, sizeof(bih_triangles) / sizeof(*bih_triangles), bih_triangles, bih_surfaces, localmins, localmaxs);
9847         if(bih_triangles_count == 0)
9848                 return;
9849         if(bih_triangles_count > (int) (sizeof(bih_triangles) / sizeof(*bih_triangles))) // hit too many, likely bad anyway
9850                 return;
9851         if(bih_triangles_count > 0)
9852         {
9853                 for (triangleindex = 0; triangleindex < bih_triangles_count; ++triangleindex)
9854                 {
9855                         surfaceindex = bih_surfaces[triangleindex];
9856                         surface = surfaces + surfaceindex;
9857                         texture = surface->texture;
9858                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9859                                 continue;
9860                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9861                                 continue;
9862                         R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, bih_triangles[triangleindex], surfaceindex);
9863                 }
9864         }
9865         else
9866         {
9867                 for (surfacelistindex = 0;surfacelistindex < numsurfacelist;surfacelistindex++)
9868                 {
9869                         surfaceindex = surfacelist[surfacelistindex];
9870                         surface = surfaces + surfaceindex;
9871                         // check cull box first because it rejects more than any other check
9872                         if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
9873                                 continue;
9874                         // skip transparent surfaces
9875                         texture = surface->texture;
9876                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9877                                 continue;
9878                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9879                                 continue;
9880                         numtriangles = surface->num_triangles;
9881                         for (triangleindex = 0; triangleindex < numtriangles; triangleindex++)
9882                                 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, triangleindex + surface->num_firsttriangle, surfaceindex);
9883                 }
9884         }
9885 }
9886
9887 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
9888 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)
9889 {
9890         int renderentityindex;
9891         float worldmins[3];
9892         float worldmaxs[3];
9893         entity_render_t *ent;
9894
9895         if (!cl_decals_newsystem.integer)
9896                 return;
9897
9898         worldmins[0] = worldorigin[0] - worldsize;
9899         worldmins[1] = worldorigin[1] - worldsize;
9900         worldmins[2] = worldorigin[2] - worldsize;
9901         worldmaxs[0] = worldorigin[0] + worldsize;
9902         worldmaxs[1] = worldorigin[1] + worldsize;
9903         worldmaxs[2] = worldorigin[2] + worldsize;
9904
9905         R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9906
9907         for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
9908         {
9909                 ent = r_refdef.scene.entities[renderentityindex];
9910                 if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
9911                         continue;
9912
9913                 R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9914         }
9915 }
9916
9917 typedef struct r_decalsystem_splatqueue_s
9918 {
9919         vec3_t worldorigin;
9920         vec3_t worldnormal;
9921         float color[4];
9922         float tcrange[4];
9923         float worldsize;
9924         unsigned int decalsequence;
9925 }
9926 r_decalsystem_splatqueue_t;
9927
9928 int r_decalsystem_numqueued = 0;
9929 r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
9930
9931 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)
9932 {
9933         r_decalsystem_splatqueue_t *queue;
9934
9935         if (!cl_decals_newsystem.integer || r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
9936                 return;
9937
9938         queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
9939         VectorCopy(worldorigin, queue->worldorigin);
9940         VectorCopy(worldnormal, queue->worldnormal);
9941         Vector4Set(queue->color, r, g, b, a);
9942         Vector4Set(queue->tcrange, s1, t1, s2, t2);
9943         queue->worldsize = worldsize;
9944         queue->decalsequence = cl.decalsequence++;
9945 }
9946
9947 static void R_DecalSystem_ApplySplatEntitiesQueue(void)
9948 {
9949         int i;
9950         r_decalsystem_splatqueue_t *queue;
9951
9952         for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
9953                 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);
9954         r_decalsystem_numqueued = 0;
9955 }
9956
9957 extern cvar_t cl_decals_max;
9958 static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
9959 {
9960         int i;
9961         decalsystem_t *decalsystem = &ent->decalsystem;
9962         int numdecals;
9963         unsigned int killsequence;
9964         tridecal_t *decal;
9965         float frametime;
9966         float lifetime;
9967
9968         if (!decalsystem->numdecals)
9969                 return;
9970
9971         if (r_showsurfaces.integer)
9972                 return;
9973
9974         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9975         {
9976                 R_DecalSystem_Reset(decalsystem);
9977                 return;
9978         }
9979
9980         killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
9981         lifetime = cl_decals_time.value + cl_decals_fadetime.value;
9982
9983         if (decalsystem->lastupdatetime)
9984                 frametime = (r_refdef.scene.time - decalsystem->lastupdatetime);
9985         else
9986                 frametime = 0;
9987         decalsystem->lastupdatetime = r_refdef.scene.time;
9988         numdecals = decalsystem->numdecals;
9989
9990         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9991         {
9992                 if (decal->color4f[0][3])
9993                 {
9994                         decal->lived += frametime;
9995                         if (killsequence > decal->decalsequence || decal->lived >= lifetime)
9996                         {
9997                                 memset(decal, 0, sizeof(*decal));
9998                                 if (decalsystem->freedecal > i)
9999                                         decalsystem->freedecal = i;
10000                         }
10001                 }
10002         }
10003         decal = decalsystem->decals;
10004         while (numdecals > 0 && !decal[numdecals-1].color4f[0][3])
10005                 numdecals--;
10006
10007         // collapse the array by shuffling the tail decals into the gaps
10008         for (;;)
10009         {
10010                 while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4f[0][3])
10011                         decalsystem->freedecal++;
10012                 if (decalsystem->freedecal == numdecals)
10013                         break;
10014                 decal[decalsystem->freedecal] = decal[--numdecals];
10015         }
10016
10017         decalsystem->numdecals = numdecals;
10018
10019         if (numdecals <= 0)
10020         {
10021                 // if there are no decals left, reset decalsystem
10022                 R_DecalSystem_Reset(decalsystem);
10023         }
10024 }
10025
10026 extern skinframe_t *decalskinframe;
10027 static void R_DrawModelDecals_Entity(entity_render_t *ent)
10028 {
10029         int i;
10030         decalsystem_t *decalsystem = &ent->decalsystem;
10031         int numdecals;
10032         tridecal_t *decal;
10033         float faderate;
10034         float alpha;
10035         float *v3f;
10036         float *c4f;
10037         float *t2f;
10038         const int *e;
10039         const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
10040         int numtris = 0;
10041
10042         numdecals = decalsystem->numdecals;
10043         if (!numdecals)
10044                 return;
10045
10046         if (r_showsurfaces.integer)
10047                 return;
10048
10049         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
10050         {
10051                 R_DecalSystem_Reset(decalsystem);
10052                 return;
10053         }
10054
10055         // if the model is static it doesn't matter what value we give for
10056         // wantnormals and wanttangents, so this logic uses only rules applicable
10057         // to a model, knowing that they are meaningless otherwise
10058         RSurf_ActiveModelEntity(ent, false, false, false);
10059
10060         decalsystem->lastupdatetime = r_refdef.scene.time;
10061
10062         faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
10063
10064         // update vertex positions for animated models
10065         v3f = decalsystem->vertex3f;
10066         c4f = decalsystem->color4f;
10067         t2f = decalsystem->texcoord2f;
10068         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
10069         {
10070                 if (!decal->color4f[0][3])
10071                         continue;
10072
10073                 if (surfacevisible && !surfacevisible[decal->surfaceindex])
10074                         continue;
10075
10076                 // skip backfaces
10077                 if (decal->triangleindex < 0 && DotProduct(r_refdef.view.origin, decal->plane) < decal->plane[3])
10078                         continue;
10079
10080                 // update color values for fading decals
10081                 if (decal->lived >= cl_decals_time.value)
10082                         alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
10083                 else
10084                         alpha = 1.0f;
10085
10086                 c4f[ 0] = decal->color4f[0][0] * alpha;
10087                 c4f[ 1] = decal->color4f[0][1] * alpha;
10088                 c4f[ 2] = decal->color4f[0][2] * alpha;
10089                 c4f[ 3] = 1;
10090                 c4f[ 4] = decal->color4f[1][0] * alpha;
10091                 c4f[ 5] = decal->color4f[1][1] * alpha;
10092                 c4f[ 6] = decal->color4f[1][2] * alpha;
10093                 c4f[ 7] = 1;
10094                 c4f[ 8] = decal->color4f[2][0] * alpha;
10095                 c4f[ 9] = decal->color4f[2][1] * alpha;
10096                 c4f[10] = decal->color4f[2][2] * alpha;
10097                 c4f[11] = 1;
10098
10099                 t2f[0] = decal->texcoord2f[0][0];
10100                 t2f[1] = decal->texcoord2f[0][1];
10101                 t2f[2] = decal->texcoord2f[1][0];
10102                 t2f[3] = decal->texcoord2f[1][1];
10103                 t2f[4] = decal->texcoord2f[2][0];
10104                 t2f[5] = decal->texcoord2f[2][1];
10105
10106                 // update vertex positions for animated models
10107                 if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
10108                 {
10109                         e = rsurface.modelelement3i + 3*decal->triangleindex;
10110                         VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f);
10111                         VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3);
10112                         VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6);
10113                 }
10114                 else
10115                 {
10116                         VectorCopy(decal->vertex3f[0], v3f);
10117                         VectorCopy(decal->vertex3f[1], v3f + 3);
10118                         VectorCopy(decal->vertex3f[2], v3f + 6);
10119                 }
10120
10121                 if (r_refdef.fogenabled)
10122                 {
10123                         alpha = RSurf_FogVertex(v3f);
10124                         VectorScale(c4f, alpha, c4f);
10125                         alpha = RSurf_FogVertex(v3f + 3);
10126                         VectorScale(c4f + 4, alpha, c4f + 4);
10127                         alpha = RSurf_FogVertex(v3f + 6);
10128                         VectorScale(c4f + 8, alpha, c4f + 8);
10129                 }
10130
10131                 v3f += 9;
10132                 c4f += 12;
10133                 t2f += 6;
10134                 numtris++;
10135         }
10136
10137         if (numtris > 0)
10138         {
10139                 r_refdef.stats[r_stat_drawndecals] += numtris;
10140
10141                 // now render the decals all at once
10142                 // (this assumes they all use one particle font texture!)
10143                 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);
10144 //              R_Mesh_ResetTextureState();
10145                 R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
10146                 GL_DepthMask(false);
10147                 GL_DepthRange(0, 1);
10148                 GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
10149                 GL_DepthTest(true);
10150                 GL_CullFace(GL_NONE);
10151                 GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
10152                 R_SetupShader_Generic(decalskinframe->base, NULL, GL_MODULATE, 1, false, false, false);
10153                 R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
10154         }
10155 }
10156
10157 static void R_DrawModelDecals(void)
10158 {
10159         int i, numdecals;
10160
10161         // fade faster when there are too many decals
10162         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
10163         for (i = 0;i < r_refdef.scene.numentities;i++)
10164                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
10165
10166         R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
10167         for (i = 0;i < r_refdef.scene.numentities;i++)
10168                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
10169                         R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
10170
10171         R_DecalSystem_ApplySplatEntitiesQueue();
10172
10173         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
10174         for (i = 0;i < r_refdef.scene.numentities;i++)
10175                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
10176
10177         r_refdef.stats[r_stat_totaldecals] += numdecals;
10178
10179         if (r_showsurfaces.integer)
10180                 return;
10181
10182         R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
10183
10184         for (i = 0;i < r_refdef.scene.numentities;i++)
10185         {
10186                 if (!r_refdef.viewcache.entityvisible[i])
10187                         continue;
10188                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
10189                         R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
10190         }
10191 }
10192
10193 extern cvar_t mod_collision_bih;
10194 static void R_DrawDebugModel(void)
10195 {
10196         entity_render_t *ent = rsurface.entity;
10197         int i, j, flagsmask;
10198         const msurface_t *surface;
10199         dp_model_t *model = ent->model;
10200
10201         if (!sv.active  && !cls.demoplayback && ent != r_refdef.scene.worldentity)
10202                 return;
10203
10204         if (r_showoverdraw.value > 0)
10205         {
10206                 float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
10207                 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
10208                 R_SetupShader_Generic_NoTexture(false, false);
10209                 GL_DepthTest(false);
10210                 GL_DepthMask(false);
10211                 GL_DepthRange(0, 1);
10212                 GL_BlendFunc(GL_ONE, GL_ONE);
10213                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
10214                 {
10215                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
10216                                 continue;
10217                         rsurface.texture = R_GetCurrentTexture(surface->texture);
10218                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
10219                         {
10220                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface);
10221                                 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
10222                                 if (!rsurface.texture->currentlayers->depthmask)
10223                                         GL_Color(c, 0, 0, 1.0f);
10224                                 else if (ent == r_refdef.scene.worldentity)
10225                                         GL_Color(c, c, c, 1.0f);
10226                                 else
10227                                         GL_Color(0, c, 0, 1.0f);
10228                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
10229                                 RSurf_DrawBatch();
10230                         }
10231                 }
10232                 rsurface.texture = NULL;
10233         }
10234
10235         flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
10236
10237 //      R_Mesh_ResetTextureState();
10238         R_SetupShader_Generic_NoTexture(false, false);
10239         GL_DepthRange(0, 1);
10240         GL_DepthTest(!r_showdisabledepthtest.integer);
10241         GL_DepthMask(false);
10242         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
10243
10244         if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs)
10245         {
10246                 int triangleindex;
10247                 int bihleafindex;
10248                 qboolean cullbox = false;
10249                 const q3mbrush_t *brush;
10250                 const bih_t *bih = &model->collision_bih;
10251                 const bih_leaf_t *bihleaf;
10252                 float vertex3f[3][3];
10253                 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
10254                 for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
10255                 {
10256                         if (cullbox && R_CullBox(bihleaf->mins, bihleaf->maxs))
10257                                 continue;
10258                         switch (bihleaf->type)
10259                         {
10260                         case BIH_BRUSH:
10261                                 brush = model->brush.data_brushes + bihleaf->itemindex;
10262                                 if (brush->colbrushf && brush->colbrushf->numtriangles)
10263                                 {
10264                                         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);
10265                                         R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL);
10266                                         R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0);
10267                                 }
10268                                 break;
10269                         case BIH_COLLISIONTRIANGLE:
10270                                 triangleindex = bihleaf->itemindex;
10271                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
10272                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
10273                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
10274                                 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);
10275                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
10276                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
10277                                 break;
10278                         case BIH_RENDERTRIANGLE:
10279                                 triangleindex = bihleaf->itemindex;
10280                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
10281                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
10282                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]);
10283                                 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);
10284                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
10285                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
10286                                 break;
10287                         }
10288                 }
10289         }
10290
10291         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
10292
10293 #ifndef USE_GLES2
10294         if (r_showtris.value > 0 && qglPolygonMode)
10295         {
10296                 if (r_showdisabledepthtest.integer)
10297                 {
10298                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
10299                         GL_DepthMask(false);
10300                 }
10301                 else
10302                 {
10303                         GL_BlendFunc(GL_ONE, GL_ZERO);
10304                         GL_DepthMask(true);
10305                 }
10306                 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR
10307                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
10308                 {
10309                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
10310                                 continue;
10311                         rsurface.texture = R_GetCurrentTexture(surface->texture);
10312                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
10313                         {
10314                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
10315                                 if (!rsurface.texture->currentlayers->depthmask)
10316                                         GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value);
10317                                 else if (ent == r_refdef.scene.worldentity)
10318                                         GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
10319                                 else
10320                                         GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
10321                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
10322                                 RSurf_DrawBatch();
10323                         }
10324                 }
10325                 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);CHECKGLERROR
10326                 rsurface.texture = NULL;
10327         }
10328
10329 # if 0
10330         // FIXME!  implement r_shownormals with just triangles
10331         if (r_shownormals.value != 0 && qglBegin)
10332         {
10333                 int l, k;
10334                 vec3_t v;
10335                 if (r_showdisabledepthtest.integer)
10336                 {
10337                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
10338                         GL_DepthMask(false);
10339                 }
10340                 else
10341                 {
10342                         GL_BlendFunc(GL_ONE, GL_ZERO);
10343                         GL_DepthMask(true);
10344                 }
10345                 for (i = 0, j = model->firstmodelsurface, surface = model->data_surfaces + j;i < model->nummodelsurfaces;i++, j++, surface++)
10346                 {
10347                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
10348                                 continue;
10349                         rsurface.texture = R_GetCurrentTexture(surface->texture);
10350                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
10351                         {
10352                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
10353                                 qglBegin(GL_LINES);
10354                                 if (r_shownormals.value < 0 && rsurface.batchnormal3f)
10355                                 {
10356                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10357                                         {
10358                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10359                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10360                                                 qglVertex3f(v[0], v[1], v[2]);
10361                                                 VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10362                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10363                                                 qglVertex3f(v[0], v[1], v[2]);
10364                                         }
10365                                 }
10366                                 if (r_shownormals.value > 0 && rsurface.batchsvector3f)
10367                                 {
10368                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10369                                         {
10370                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10371                                                 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
10372                                                 qglVertex3f(v[0], v[1], v[2]);
10373                                                 VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
10374                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10375                                                 qglVertex3f(v[0], v[1], v[2]);
10376                                         }
10377                                 }
10378                                 if (r_shownormals.value > 0 && rsurface.batchtvector3f)
10379                                 {
10380                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10381                                         {
10382                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10383                                                 GL_Color(0, r_refdef.view.colorscale, 0, 1);
10384                                                 qglVertex3f(v[0], v[1], v[2]);
10385                                                 VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
10386                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10387                                                 qglVertex3f(v[0], v[1], v[2]);
10388                                         }
10389                                 }
10390                                 if (r_shownormals.value > 0 && rsurface.batchnormal3f)
10391                                 {
10392                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
10393                                         {
10394                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
10395                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
10396                                                 qglVertex3f(v[0], v[1], v[2]);
10397                                                 VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
10398                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
10399                                                 qglVertex3f(v[0], v[1], v[2]);
10400                                         }
10401                                 }
10402                                 qglEnd();
10403                                 CHECKGLERROR
10404                         }
10405                 }
10406                 rsurface.texture = NULL;
10407         }
10408 # endif
10409 #endif
10410 }
10411
10412 int r_maxsurfacelist = 0;
10413 const msurface_t **r_surfacelist = NULL;
10414 void R_DrawModelSurfaces(entity_render_t *ent, qboolean skysurfaces, qboolean writedepth, qboolean depthonly, qboolean debug, qboolean prepass)
10415 {
10416         int i, j, endj, flagsmask;
10417         dp_model_t *model = ent->model;
10418         msurface_t *surfaces;
10419         unsigned char *update;
10420         int numsurfacelist = 0;
10421         if (model == NULL)
10422                 return;
10423
10424         if (r_maxsurfacelist < model->num_surfaces)
10425         {
10426                 r_maxsurfacelist = model->num_surfaces;
10427                 if (r_surfacelist)
10428                         Mem_Free((msurface_t **)r_surfacelist);
10429                 r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
10430         }
10431
10432         if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
10433                 RSurf_ActiveModelEntity(ent, false, false, false);
10434         else if (prepass)
10435                 RSurf_ActiveModelEntity(ent, true, true, true);
10436         else if (depthonly)
10437                 RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
10438         else
10439                 RSurf_ActiveModelEntity(ent, true, true, false);
10440
10441         surfaces = model->data_surfaces;
10442         update = model->brushq1.lightmapupdateflags;
10443
10444         // update light styles
10445         if (!skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0)
10446         {
10447                 model_brush_lightstyleinfo_t *style;
10448                 for (i = 0, style = model->brushq1.data_lightstyleinfo;i < model->brushq1.num_lightstyles;i++, style++)
10449                 {
10450                         if (style->value != r_refdef.scene.lightstylevalue[style->style])
10451                         {
10452                                 int *list = style->surfacelist;
10453                                 style->value = r_refdef.scene.lightstylevalue[style->style];
10454                                 for (j = 0;j < style->numsurfaces;j++)
10455                                         update[list[j]] = true;
10456                         }
10457                 }
10458         }
10459
10460         flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
10461
10462         if (debug)
10463         {
10464                 R_DrawDebugModel();
10465                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10466                 return;
10467         }
10468
10469         rsurface.lightmaptexture = NULL;
10470         rsurface.deluxemaptexture = NULL;
10471         rsurface.uselightmaptexture = false;
10472         rsurface.texture = NULL;
10473         rsurface.rtlight = NULL;
10474         numsurfacelist = 0;
10475         // add visible surfaces to draw list
10476         if (ent == r_refdef.scene.worldentity)
10477         {
10478                 // for the world entity, check surfacevisible
10479                 for (i = 0;i < model->nummodelsurfaces;i++)
10480                 {
10481                         j = model->sortedmodelsurfaces[i];
10482                         if (r_refdef.viewcache.world_surfacevisible[j])
10483                                 r_surfacelist[numsurfacelist++] = surfaces + j;
10484                 }
10485         }
10486         else
10487         {
10488                 // add all surfaces
10489                 for (i = 0; i < model->nummodelsurfaces; i++)
10490                         r_surfacelist[numsurfacelist++] = surfaces + model->sortedmodelsurfaces[i];
10491         }
10492         // don't do anything if there were no surfaces
10493         if (!numsurfacelist)
10494         {
10495                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10496                 return;
10497         }
10498         // update lightmaps if needed
10499         if (update)
10500         {
10501                 int updated = 0;
10502                 for (j = model->firstmodelsurface, endj = model->firstmodelsurface + model->nummodelsurfaces;j < endj;j++)
10503                 {
10504                         if (update[j])
10505                         {
10506                                 updated++;
10507                                 R_BuildLightMap(ent, surfaces + j);
10508                         }
10509                 }
10510         }
10511
10512         R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass);
10513
10514         // add to stats if desired
10515         if (r_speeds.integer && !skysurfaces && !depthonly)
10516         {
10517                 r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist;
10518                 for (j = 0;j < numsurfacelist;j++)
10519                         r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
10520         }
10521
10522         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10523 }
10524
10525 void R_DebugLine(vec3_t start, vec3_t end)
10526 {
10527         dp_model_t *mod = CL_Mesh_UI();
10528         msurface_t *surf;
10529         int e0, e1, e2, e3;
10530         float offsetx, offsety, x1, y1, x2, y2, width = 1.0f;
10531         float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f, alpha1 = 0.25f;
10532         float r2 = 1.0f, g2 = 1.0f, b2 = 0.0f, alpha2 = 0.25f;
10533         vec4_t w[2], s[2];
10534
10535         // transform to screen coords first
10536         Vector4Set(w[0], start[0], start[1], start[2], 1);
10537         Vector4Set(w[1], end[0], end[1], end[2], 1);
10538         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
10539         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
10540         x1 = s[0][0] * vid_conwidth.value / vid.width;
10541         y1 = (vid.height - s[0][1]) * vid_conheight.value / vid.height;
10542         x2 = s[1][0] * vid_conwidth.value / vid.width;
10543         y2 = (vid.height - s[1][1]) * vid_conheight.value / vid.height;
10544         //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
10545
10546         // add the line to the UI mesh for drawing later
10547
10548         // width is measured in real pixels
10549         if (fabs(x2 - x1) > fabs(y2 - y1))
10550         {
10551                 offsetx = 0;
10552                 offsety = 0.5f * width * vid_conheight.value / vid.height;
10553         }
10554         else
10555         {
10556                 offsetx = 0.5f * width * vid_conwidth.value / vid.width;
10557                 offsety = 0;
10558         }
10559         surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, "white", 0, 0, MATERIALFLAG_VERTEXCOLOR), true);
10560         e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10561         e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10562         e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10563         e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10564         Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
10565         Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
10566
10567 }
10568
10569
10570 void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qboolean writedepth, qboolean prepass)
10571 {
10572         int q;
10573         static texture_t texture;
10574         static msurface_t surface;
10575         const msurface_t *surfacelist = &surface;
10576
10577         // fake enough texture and surface state to render this geometry
10578
10579         texture.update_lastrenderframe = -1; // regenerate this texture
10580         texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
10581         texture.basealpha = 1.0f;
10582         texture.currentskinframe = skinframe;
10583         texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
10584         texture.offsetmapping = OFFSETMAPPING_OFF;
10585         texture.offsetscale = 1;
10586         texture.specularscalemod = 1;
10587         texture.specularpowermod = 1;
10588         texture.transparentsort = TRANSPARENTSORT_DISTANCE;
10589         // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
10590         // JUST GREP FOR "specularscalemod = 1".
10591
10592         for (q = 0; q < 3; q++)
10593         {
10594                 texture.render_glowmod[q] = r_refdef.view.colorscale * r_hdr_glowintensity.value;
10595                 texture.render_modellight_lightdir[q] = q == 2;
10596                 texture.render_modellight_ambient[q] = r_refdef.view.colorscale * r_refdef.scene.ambientintensity;
10597                 texture.render_modellight_diffuse[q] = r_refdef.view.colorscale;
10598                 texture.render_modellight_specular[q] = r_refdef.view.colorscale;
10599                 texture.render_lightmap_ambient[q] = r_refdef.view.colorscale * r_refdef.scene.ambientintensity;
10600                 texture.render_lightmap_diffuse[q] = r_refdef.view.colorscale * r_refdef.scene.lightmapintensity;
10601                 texture.render_lightmap_specular[q] = r_refdef.view.colorscale;
10602                 texture.render_rtlight_diffuse[q] = r_refdef.view.colorscale;
10603                 texture.render_rtlight_specular[q] = r_refdef.view.colorscale;
10604         }
10605         texture.currentalpha = 1.0f;
10606
10607         surface.texture = &texture;
10608         surface.num_triangles = numtriangles;
10609         surface.num_firsttriangle = firsttriangle;
10610         surface.num_vertices = numvertices;
10611         surface.num_firstvertex = firstvertex;
10612
10613         // now render it
10614         rsurface.texture = R_GetCurrentTexture(surface.texture);
10615         rsurface.lightmaptexture = NULL;
10616         rsurface.deluxemaptexture = NULL;
10617         rsurface.uselightmaptexture = false;
10618         R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass);
10619 }
10620
10621 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)
10622 {
10623         static msurface_t surface;
10624         const msurface_t *surfacelist = &surface;
10625
10626         // fake enough texture and surface state to render this geometry
10627         surface.texture = texture;
10628         surface.num_triangles = numtriangles;
10629         surface.num_firsttriangle = firsttriangle;
10630         surface.num_vertices = numvertices;
10631         surface.num_firstvertex = firstvertex;
10632
10633         // now render it
10634         rsurface.texture = R_GetCurrentTexture(surface.texture);
10635         rsurface.lightmaptexture = NULL;
10636         rsurface.deluxemaptexture = NULL;
10637         rsurface.uselightmaptexture = false;
10638         R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass);
10639 }