]> git.xonotic.org Git - xonotic/darkplaces.git/blob - gl_rmain.c
Fix GCC 13 warns: ‘new_velocity[0]’ may be used uninitialized
[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 int r_textureframe = 0; ///< used only by R_GetCurrentTexture, incremented per view and per UI render
46
47 static qbool r_loadnormalmap;
48 static qbool r_loadgloss;
49 qbool r_loadfog;
50 static qbool r_loaddds;
51 static qbool r_savedds;
52 static qbool r_gpuskeletal;
53
54 //
55 // screen size info
56 //
57 r_refdef_t r_refdef;
58
59 cvar_t r_motionblur = {CF_CLIENT | CF_ARCHIVE, "r_motionblur", "0", "screen motionblur - value represents intensity, somewhere around 0.5 recommended - NOTE: bad performance on multi-gpu!"};
60 cvar_t r_damageblur = {CF_CLIENT | CF_ARCHIVE, "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 = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_averaging", "0.1", "sliding average reaction time for velocity (higher = slower adaption to change)"};
62 cvar_t r_motionblur_randomize = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_randomize", "0.1", "randomizing coefficient to workaround ghosting"};
63 cvar_t r_motionblur_minblur = {CF_CLIENT | CF_ARCHIVE, "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 = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_maxblur", "0.9", "maxmimum amount of blur"};
65 cvar_t r_motionblur_velocityfactor = {CF_CLIENT | CF_ARCHIVE, "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 = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_velocityfactor_minspeed", "400", "lower value of velocity when it starts to factor into blur equation"};
67 cvar_t r_motionblur_velocityfactor_maxspeed = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_velocityfactor_maxspeed", "800", "upper value of velocity when it reaches the peak factor into blur equation"};
68 cvar_t r_motionblur_mousefactor = {CF_CLIENT | CF_ARCHIVE, "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 = {CF_CLIENT | CF_ARCHIVE, "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 = {CF_CLIENT | CF_ARCHIVE, "r_motionblur_mousefactor_maxspeed", "50", "upper value of mouse acceleration when it reaches the peak factor into blur equation"};
71
72 cvar_t r_depthfirst = {CF_CLIENT | CF_ARCHIVE, "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"};
73 cvar_t r_useinfinitefarclip = {CF_CLIENT | CF_ARCHIVE, "r_useinfinitefarclip", "1", "enables use of a special kind of projection matrix that has an extremely large farclip"};
74 cvar_t r_farclip_base = {CF_CLIENT, "r_farclip_base", "65536", "farclip (furthest visible distance) for rendering when r_useinfinitefarclip is 0"};
75 cvar_t r_farclip_world = {CF_CLIENT, "r_farclip_world", "2", "adds map size to farclip multiplied by this value"};
76 cvar_t r_nearclip = {CF_CLIENT, "r_nearclip", "1", "distance from camera of nearclip plane" };
77 cvar_t r_deformvertexes = {CF_CLIENT, "r_deformvertexes", "1", "allows use of deformvertexes in shader files (can be turned off to check performance impact)"};
78 cvar_t r_transparent = {CF_CLIENT, "r_transparent", "1", "allows use of transparent surfaces (can be turned off to check performance impact)"};
79 cvar_t r_transparent_alphatocoverage = {CF_CLIENT, "r_transparent_alphatocoverage", "1", "enables GL_ALPHA_TO_COVERAGE antialiasing technique on alphablend and alphatest surfaces when using vid_samples 2 or higher"};
80 cvar_t r_transparent_sortsurfacesbynearest = {CF_CLIENT, "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"};
81 cvar_t r_transparent_useplanardistance = {CF_CLIENT, "r_transparent_useplanardistance", "0", "sort transparent meshes by distance from view plane rather than spherical distance to the chosen point"};
82 cvar_t r_showoverdraw = {CF_CLIENT, "r_showoverdraw", "0", "shows overlapping geometry"};
83 cvar_t r_showbboxes = {CF_CLIENT, "r_showbboxes", "0", "shows bounding boxes of server entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
84 cvar_t r_showbboxes_client = {CF_CLIENT, "r_showbboxes_client", "0", "shows bounding boxes of clientside qc entities, value controls opacity scaling (1 = 10%,  10 = 100%)"};
85 cvar_t r_showsurfaces = {CF_CLIENT, "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)"};
86 cvar_t r_showtris = {CF_CLIENT, "r_showtris", "0", "shows triangle outlines, value controls brightness (can be above 1)"};
87 cvar_t r_shownormals = {CF_CLIENT, "r_shownormals", "0", "shows per-vertex surface normals and tangent vectors for bumpmapped lighting"};
88 cvar_t r_showlighting = {CF_CLIENT, "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"};
89 cvar_t r_showcollisionbrushes = {CF_CLIENT, "r_showcollisionbrushes", "0", "draws collision brushes in quake3 maps (mode 1), mode 2 disables rendering of world (trippy!)"};
90 cvar_t r_showcollisionbrushes_polygonfactor = {CF_CLIENT, "r_showcollisionbrushes_polygonfactor", "-1", "expands outward the brush polygons a little bit, used to make collision brushes appear infront of walls"};
91 cvar_t r_showcollisionbrushes_polygonoffset = {CF_CLIENT, "r_showcollisionbrushes_polygonoffset", "0", "nudges brush polygon depth in hardware depth units, used to make collision brushes appear infront of walls"};
92 cvar_t r_showdisabledepthtest = {CF_CLIENT, "r_showdisabledepthtest", "0", "disables depth testing on r_show* cvars, allowing you to see what hidden geometry the graphics card is processing"};
93 cvar_t r_showspriteedges = {CF_CLIENT, "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"};
94 cvar_t r_showparticleedges = {CF_CLIENT, "r_showparticleedges", "0", "renders a debug outline to show the polygon shape of each particle, for debugging rendering bugs with specific view types"};
95 cvar_t r_drawportals = {CF_CLIENT, "r_drawportals", "0", "shows portals (separating polygons) in world interior in quake1 maps"};
96 cvar_t r_drawentities = {CF_CLIENT, "r_drawentities","1", "draw entities (doors, players, projectiles, etc)"};
97 cvar_t r_draw2d = {CF_CLIENT, "r_draw2d","1", "draw 2D stuff (dangerous to turn off)"};
98 cvar_t r_drawworld = {CF_CLIENT, "r_drawworld","1", "draw world (most static stuff)"};
99 cvar_t r_drawviewmodel = {CF_CLIENT, "r_drawviewmodel","1", "draw your weapon model"};
100 cvar_t r_drawexteriormodel = {CF_CLIENT, "r_drawexteriormodel","1", "draw your player model (e.g. in chase cam, reflections)"};
101 cvar_t r_cullentities_trace = {CF_CLIENT, "r_cullentities_trace", "1", "probabistically cull invisible entities"};
102 cvar_t r_cullentities_trace_entityocclusion = {CF_CLIENT, "r_cullentities_trace_entityocclusion", "1", "check for occluding entities such as doors, not just world hull"};
103 cvar_t r_cullentities_trace_samples = {CF_CLIENT, "r_cullentities_trace_samples", "2", "number of samples to test for entity culling (in addition to center sample)"};
104 cvar_t r_cullentities_trace_tempentitysamples = {CF_CLIENT, "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)"};
105 cvar_t r_cullentities_trace_enlarge = {CF_CLIENT, "r_cullentities_trace_enlarge", "0", "box enlargement for entity culling"};
106 cvar_t r_cullentities_trace_expand = {CF_CLIENT, "r_cullentities_trace_expand", "0", "box expanded by this many units for entity culling"};
107 cvar_t r_cullentities_trace_pad = {CF_CLIENT, "r_cullentities_trace_pad", "8", "accept traces that hit within this many units of the box"};
108 cvar_t r_cullentities_trace_delay = {CF_CLIENT, "r_cullentities_trace_delay", "1", "number of seconds until the entity gets actually culled"};
109 cvar_t r_cullentities_trace_eyejitter = {CF_CLIENT, "r_cullentities_trace_eyejitter", "16", "randomly offset rays from the eye by this much to reduce the odds of flickering"};
110 cvar_t r_sortentities = {CF_CLIENT, "r_sortentities", "0", "sort entities before drawing (might be faster)"};
111 cvar_t r_speeds = {CF_CLIENT, "r_speeds","0", "displays rendering statistics and per-subsystem timings"};
112 cvar_t r_fullbright = {CF_CLIENT, "r_fullbright","0", "makes map very bright and renders faster"};
113
114 cvar_t r_fullbright_directed = {CF_CLIENT, "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"};
115 cvar_t r_fullbright_directed_ambient = {CF_CLIENT, "r_fullbright_directed_ambient", "0.5", "ambient light multiplier for directed fullbright"};
116 cvar_t r_fullbright_directed_diffuse = {CF_CLIENT, "r_fullbright_directed_diffuse", "0.75", "diffuse light multiplier for directed fullbright"};
117 cvar_t r_fullbright_directed_pitch = {CF_CLIENT, "r_fullbright_directed_pitch", "20", "constant pitch direction ('height') of the fake light source to use for fullbright"};
118 cvar_t r_fullbright_directed_pitch_relative = {CF_CLIENT, "r_fullbright_directed_pitch_relative", "0", "whether r_fullbright_directed_pitch is interpreted as absolute (0) or relative (1) pitch"};
119
120 cvar_t r_wateralpha = {CF_CLIENT | CF_ARCHIVE, "r_wateralpha","1", "opacity of water polygons"};
121 cvar_t r_dynamic = {CF_CLIENT | CF_ARCHIVE, "r_dynamic","1", "enables dynamic lights (rocket glow and such)"};
122 cvar_t r_fullbrights = {CF_CLIENT | CF_ARCHIVE, "r_fullbrights", "1", "enables glowing pixels in quake textures (changes need r_restart to take effect)"};
123 cvar_t r_shadows = {CF_CLIENT | CF_ARCHIVE, "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."};
124 cvar_t r_shadows_darken = {CF_CLIENT | CF_ARCHIVE, "r_shadows_darken", "0.5", "how much shadowed areas will be darkened"};
125 cvar_t r_shadows_throwdistance = {CF_CLIENT | CF_ARCHIVE, "r_shadows_throwdistance", "500", "how far to cast shadows from models"};
126 cvar_t r_shadows_throwdirection = {CF_CLIENT | CF_ARCHIVE, "r_shadows_throwdirection", "0 0 -1", "override throwing direction for r_shadows 2"};
127 cvar_t r_shadows_drawafterrtlighting = {CF_CLIENT | CF_ARCHIVE, "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."};
128 cvar_t r_shadows_castfrombmodels = {CF_CLIENT | CF_ARCHIVE, "r_shadows_castfrombmodels", "0", "do cast shadows from bmodels"};
129 cvar_t r_shadows_focus = {CF_CLIENT | CF_ARCHIVE, "r_shadows_focus", "0 0 0", "offset the shadowed area focus"};
130 cvar_t r_shadows_shadowmapscale = {CF_CLIENT | CF_ARCHIVE, "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."};
131 cvar_t r_shadows_shadowmapbias = {CF_CLIENT | CF_ARCHIVE, "r_shadows_shadowmapbias", "-1", "sets shadowmap bias for fake shadows. -1 sets the value of r_shadow_shadowmapping_bias. Needs shadowmapping ON."};
132 cvar_t r_q1bsp_skymasking = {CF_CLIENT, "r_q1bsp_skymasking", "1", "allows sky polygons in quake1 maps to obscure other geometry"};
133 cvar_t r_polygonoffset_submodel_factor = {CF_CLIENT, "r_polygonoffset_submodel_factor", "0", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
134 cvar_t r_polygonoffset_submodel_offset = {CF_CLIENT, "r_polygonoffset_submodel_offset", "14", "biases depth values of world submodels such as doors, to prevent z-fighting artifacts in Quake maps"};
135 cvar_t r_polygonoffset_decals_factor = {CF_CLIENT, "r_polygonoffset_decals_factor", "0", "biases depth values of decals to prevent z-fighting artifacts"};
136 cvar_t r_polygonoffset_decals_offset = {CF_CLIENT, "r_polygonoffset_decals_offset", "-14", "biases depth values of decals to prevent z-fighting artifacts"};
137 cvar_t r_fog_exp2 = {CF_CLIENT, "r_fog_exp2", "0", "uses GL_EXP2 fog (as in Nehahra) rather than realistic GL_EXP fog"};
138 cvar_t r_fog_clear = {CF_CLIENT, "r_fog_clear", "1", "clears renderbuffer with fog color before render starts"};
139 cvar_t r_drawfog = {CF_CLIENT | CF_ARCHIVE, "r_drawfog", "1", "allows one to disable fog rendering"};
140 cvar_t r_transparentdepthmasking = {CF_CLIENT | CF_ARCHIVE, "r_transparentdepthmasking", "0", "enables depth writes on transparent meshes whose materially is normally opaque, this prevents seeing the inside of a transparent mesh"};
141 cvar_t r_transparent_sortmindist = {CF_CLIENT | CF_ARCHIVE, "r_transparent_sortmindist", "0", "lower distance limit for transparent sorting"};
142 cvar_t r_transparent_sortmaxdist = {CF_CLIENT | CF_ARCHIVE, "r_transparent_sortmaxdist", "32768", "upper distance limit for transparent sorting"};
143 cvar_t r_transparent_sortarraysize = {CF_CLIENT | CF_ARCHIVE, "r_transparent_sortarraysize", "4096", "number of distance-sorting layers"};
144 cvar_t r_celshading = {CF_CLIENT | CF_ARCHIVE, "r_celshading", "0", "cartoon-style light shading (OpenGL 2.x only)"}; // FIXME remove OpenGL 2.x only once implemented for DX9
145 cvar_t r_celoutlines = {CF_CLIENT | CF_ARCHIVE, "r_celoutlines", "0", "cartoon-style outlines (requires r_shadow_deferred)"};
146
147 cvar_t gl_fogenable = {CF_CLIENT, "gl_fogenable", "0", "nehahra fog enable (for Nehahra compatibility only)"};
148 cvar_t gl_fogdensity = {CF_CLIENT, "gl_fogdensity", "0.25", "nehahra fog density (recommend values below 0.1) (for Nehahra compatibility only)"};
149 cvar_t gl_fogred = {CF_CLIENT, "gl_fogred","0.3", "nehahra fog color red value (for Nehahra compatibility only)"};
150 cvar_t gl_foggreen = {CF_CLIENT, "gl_foggreen","0.3", "nehahra fog color green value (for Nehahra compatibility only)"};
151 cvar_t gl_fogblue = {CF_CLIENT, "gl_fogblue","0.3", "nehahra fog color blue value (for Nehahra compatibility only)"};
152 cvar_t gl_fogstart = {CF_CLIENT, "gl_fogstart", "0", "nehahra fog start distance (for Nehahra compatibility only)"};
153 cvar_t gl_fogend = {CF_CLIENT, "gl_fogend","0", "nehahra fog end distance (for Nehahra compatibility only)"};
154 cvar_t gl_skyclip = {CF_CLIENT, "gl_skyclip", "4608", "nehahra farclip distance - the real fog end (for Nehahra compatibility only)"};
155
156 cvar_t r_texture_dds_load = {CF_CLIENT | CF_ARCHIVE, "r_texture_dds_load", "0", "load compressed dds/filename.dds texture instead of filename.tga, if the file exists (requires driver support)"};
157 cvar_t r_texture_dds_save = {CF_CLIENT | CF_ARCHIVE, "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"};
158
159 cvar_t r_textureunits = {CF_CLIENT, "r_textureunits", "32", "number of texture units to use in GL 1.1 and GL 1.3 rendering paths"};
160 static cvar_t gl_combine = {CF_CLIENT | CF_READONLY, "gl_combine", "1", "indicates whether the OpenGL 1.3 rendering path is active"};
161 static cvar_t r_glsl = {CF_CLIENT | CF_READONLY, "r_glsl", "1", "indicates whether the OpenGL 2.0 rendering path is active"};
162
163 cvar_t r_usedepthtextures = {CF_CLIENT | CF_ARCHIVE, "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"};
164 cvar_t r_viewfbo = {CF_CLIENT | CF_ARCHIVE, "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"};
165 cvar_t r_rendertarget_debug = {CF_CLIENT, "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)"};
166 cvar_t r_viewscale = {CF_CLIENT | CF_ARCHIVE, "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"};
167 cvar_t r_viewscale_fpsscaling = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling", "0", "change resolution based on framerate"};
168 cvar_t r_viewscale_fpsscaling_min = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_min", "0.0625", "worst acceptable quality"};
169 cvar_t r_viewscale_fpsscaling_multiply = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_multiply", "5", "adjust quality up or down by the frametime difference from 1.0/target, multiplied by this factor"};
170 cvar_t r_viewscale_fpsscaling_stepsize = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_stepsize", "0.01", "smallest adjustment to hit the target framerate (this value prevents minute oscillations)"};
171 cvar_t r_viewscale_fpsscaling_stepmax = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_stepmax", "1.00", "largest adjustment to hit the target framerate (this value prevents wild overshooting of the estimate)"};
172 cvar_t r_viewscale_fpsscaling_target = {CF_CLIENT | CF_ARCHIVE, "r_viewscale_fpsscaling_target", "70", "desired framerate"};
173
174 cvar_t r_glsl_skeletal = {CF_CLIENT | CF_ARCHIVE, "r_glsl_skeletal", "1", "render skeletal models faster using a gpu-skinning technique"};
175 cvar_t r_glsl_deluxemapping = {CF_CLIENT | CF_ARCHIVE, "r_glsl_deluxemapping", "1", "use per pixel lighting on deluxemap-compiled q3bsp maps (or a value of 2 forces deluxemap shading even without deluxemaps)"};
176 cvar_t r_glsl_offsetmapping = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping", "0", "offset mapping effect (also known as parallax mapping or virtual displacement mapping)"};
177 cvar_t r_glsl_offsetmapping_steps = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_steps", "2", "offset mapping steps (note: too high values may be not supported by your GPU)"};
178 cvar_t r_glsl_offsetmapping_reliefmapping = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_reliefmapping", "0", "relief mapping effect (higher quality)"};
179 cvar_t r_glsl_offsetmapping_reliefmapping_steps = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_reliefmapping_steps", "10", "relief mapping steps (note: too high values may be not supported by your GPU)"};
180 cvar_t r_glsl_offsetmapping_reliefmapping_refinesteps = {CF_CLIENT | CF_ARCHIVE, "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)"};
181 cvar_t r_glsl_offsetmapping_scale = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_scale", "0.04", "how deep the offset mapping effect is"};
182 cvar_t r_glsl_offsetmapping_lod = {CF_CLIENT | CF_ARCHIVE, "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"};
183 cvar_t r_glsl_offsetmapping_lod_distance = {CF_CLIENT | CF_ARCHIVE, "r_glsl_offsetmapping_lod_distance", "32", "first LOD level distance, second level (-50% steps) is 2x of this, third (33%) - 3x etc."};
184 cvar_t r_glsl_postprocess = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess", "0", "use a GLSL postprocessing shader"};
185 cvar_t r_glsl_postprocess_uservec1 = {CF_CLIENT | CF_ARCHIVE, "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)"};
186 cvar_t r_glsl_postprocess_uservec2 = {CF_CLIENT | CF_ARCHIVE, "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)"};
187 cvar_t r_glsl_postprocess_uservec3 = {CF_CLIENT | CF_ARCHIVE, "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)"};
188 cvar_t r_glsl_postprocess_uservec4 = {CF_CLIENT | CF_ARCHIVE, "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)"};
189 cvar_t r_glsl_postprocess_uservec1_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec1_enable", "1", "enables postprocessing uservec1 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
190 cvar_t r_glsl_postprocess_uservec2_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec2_enable", "1", "enables postprocessing uservec2 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
191 cvar_t r_glsl_postprocess_uservec3_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec3_enable", "1", "enables postprocessing uservec3 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
192 cvar_t r_glsl_postprocess_uservec4_enable = {CF_CLIENT | CF_ARCHIVE, "r_glsl_postprocess_uservec4_enable", "1", "enables postprocessing uservec4 usage, creates USERVEC1 define (only useful if default.glsl has been customized)"};
193 cvar_t r_colorfringe = {CF_CLIENT | CF_ARCHIVE, "r_colorfringe", "0", "Chromatic aberration. Values higher than 0.025 will noticeably distort the image"};
194 cvar_t r_fxaa = {CF_CLIENT | CF_ARCHIVE, "r_fxaa", "0", "fast approximate anti aliasing"};
195
196 cvar_t r_water = {CF_CLIENT | CF_ARCHIVE, "r_water", "0", "whether to use reflections and refraction on water surfaces (note: r_wateralpha must be set below 1)"};
197 cvar_t r_water_cameraentitiesonly = {CF_CLIENT | CF_ARCHIVE, "r_water_cameraentitiesonly", "0", "whether to only show QC-defined reflections/refractions (typically used for camera- or portal-like effects)"};
198 cvar_t r_water_clippingplanebias = {CF_CLIENT | CF_ARCHIVE, "r_water_clippingplanebias", "1", "a rather technical setting which avoids black pixels around water edges"};
199 cvar_t r_water_resolutionmultiplier = {CF_CLIENT | CF_ARCHIVE, "r_water_resolutionmultiplier", "0.5", "multiplier for screen resolution when rendering refracted/reflected scenes, 1 is full quality, lower values are faster"};
200 cvar_t r_water_refractdistort = {CF_CLIENT | CF_ARCHIVE, "r_water_refractdistort", "0.01", "how much water refractions shimmer"};
201 cvar_t r_water_reflectdistort = {CF_CLIENT | CF_ARCHIVE, "r_water_reflectdistort", "0.01", "how much water reflections shimmer"};
202 cvar_t r_water_scissormode = {CF_CLIENT, "r_water_scissormode", "3", "scissor (1) or cull (2) or both (3) water renders"};
203 cvar_t r_water_lowquality = {CF_CLIENT, "r_water_lowquality", "0", "special option to accelerate water rendering: 1 disables all dynamic lights, 2 disables particles too"};
204 cvar_t r_water_hideplayer = {CF_CLIENT | CF_ARCHIVE, "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"};
205
206 cvar_t r_lerpsprites = {CF_CLIENT | CF_ARCHIVE, "r_lerpsprites", "0", "enables animation smoothing on sprites"};
207 cvar_t r_lerpmodels = {CF_CLIENT | CF_ARCHIVE, "r_lerpmodels", "1", "enables animation smoothing on models"};
208 cvar_t r_nolerp_list = {CF_CLIENT | CF_ARCHIVE, "r_nolerp_list", "progs/v_nail.mdl,progs/v_nail2.mdl,progs/flame.mdl,progs/flame2.mdl,progs/braztall.mdl,progs/brazshrt.mdl,progs/longtrch.mdl,progs/flame_pyre.mdl,progs/v_saw.mdl,progs/v_xfist.mdl,progs/h2stuff/newfire.mdl", "comma separated list of models that will not have their animations smoothed"};
209 cvar_t r_lerplightstyles = {CF_CLIENT | CF_ARCHIVE, "r_lerplightstyles", "0", "enable animation smoothing on flickering lights"};
210 cvar_t r_waterscroll = {CF_CLIENT | CF_ARCHIVE, "r_waterscroll", "1", "makes water scroll around, value controls how much"};
211
212 cvar_t r_bloom = {CF_CLIENT | CF_ARCHIVE, "r_bloom", "0", "enables bloom effect (makes bright pixels affect neighboring pixels)"};
213 cvar_t r_bloom_colorscale = {CF_CLIENT | CF_ARCHIVE, "r_bloom_colorscale", "1", "how bright the glow is"};
214
215 cvar_t r_bloom_brighten = {CF_CLIENT | CF_ARCHIVE, "r_bloom_brighten", "1", "how bright the glow is, after subtract/power"};
216 cvar_t r_bloom_blur = {CF_CLIENT | CF_ARCHIVE, "r_bloom_blur", "4", "how large the glow is"};
217 cvar_t r_bloom_resolution = {CF_CLIENT | CF_ARCHIVE, "r_bloom_resolution", "320", "what resolution to perform the bloom effect at (independent of screen resolution)"};
218 cvar_t r_bloom_colorexponent = {CF_CLIENT | CF_ARCHIVE, "r_bloom_colorexponent", "1", "how exaggerated the glow is"};
219 cvar_t r_bloom_colorsubtract = {CF_CLIENT | CF_ARCHIVE, "r_bloom_colorsubtract", "0.1", "reduces bloom colors by a certain amount"};
220 cvar_t r_bloom_scenebrightness = {CF_CLIENT | CF_ARCHIVE, "r_bloom_scenebrightness", "1", "global rendering brightness when bloom is enabled"};
221
222 cvar_t r_hdr_scenebrightness = {CF_CLIENT | CF_ARCHIVE, "r_hdr_scenebrightness", "1", "global rendering brightness"};
223 cvar_t r_hdr_glowintensity = {CF_CLIENT | CF_ARCHIVE, "r_hdr_glowintensity", "1", "how bright light emitting textures should appear"};
224 cvar_t r_hdr_irisadaptation = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation", "0", "adjust scene brightness according to light intensity at player location"};
225 cvar_t r_hdr_irisadaptation_multiplier = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_multiplier", "2", "brightness at which value will be 1.0"};
226 cvar_t r_hdr_irisadaptation_minvalue = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_minvalue", "0.5", "minimum value that can result from multiplier / brightness"};
227 cvar_t r_hdr_irisadaptation_maxvalue = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_maxvalue", "4", "maximum value that can result from multiplier / brightness"};
228 cvar_t r_hdr_irisadaptation_value = {CF_CLIENT, "r_hdr_irisadaptation_value", "1", "current value as scenebrightness multiplier, changes continuously when irisadaptation is active"};
229 cvar_t r_hdr_irisadaptation_fade_up = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_fade_up", "0.1", "fade rate at which value adjusts to darkness"};
230 cvar_t r_hdr_irisadaptation_fade_down = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_fade_down", "0.5", "fade rate at which value adjusts to brightness"};
231 cvar_t r_hdr_irisadaptation_radius = {CF_CLIENT | CF_ARCHIVE, "r_hdr_irisadaptation_radius", "15", "lighting within this many units of the eye is averaged"};
232
233 cvar_t r_smoothnormals_areaweighting = {CF_CLIENT, "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"};
234
235 cvar_t developer_texturelogging = {CF_CLIENT, "developer_texturelogging", "0", "produces a textures.log file containing names of skins and map textures the engine tried to load"};
236
237 cvar_t gl_lightmaps = {CF_CLIENT, "gl_lightmaps", "0", "draws only lightmaps, no texture (for level designers), a value of 2 keeps normalmap shading"};
238
239 cvar_t r_test = {CF_CLIENT, "r_test", "0", "internal development use only, leave it alone (usually does nothing anyway)"};
240
241 cvar_t r_batch_multidraw = {CF_CLIENT | CF_ARCHIVE, "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)"};
242 cvar_t r_batch_multidraw_mintriangles = {CF_CLIENT | CF_ARCHIVE, "r_batch_multidraw_mintriangles", "0", "minimum number of triangles to activate multidraw path (copying small groups of triangles may be faster)"};
243 cvar_t r_batch_debugdynamicvertexpath = {CF_CLIENT | CF_ARCHIVE, "r_batch_debugdynamicvertexpath", "0", "force the dynamic batching code path for debugging purposes"};
244 cvar_t r_batch_dynamicbuffer = {CF_CLIENT | CF_ARCHIVE, "r_batch_dynamicbuffer", "0", "use vertex/index buffers for drawing dynamic and copytriangles batches"};
245
246 cvar_t r_glsl_saturation = {CF_CLIENT | CF_ARCHIVE, "r_glsl_saturation", "1", "saturation multiplier (only working in glsl!)"};
247 cvar_t r_glsl_saturation_redcompensate = {CF_CLIENT | CF_ARCHIVE, "r_glsl_saturation_redcompensate", "0", "a 'vampire sight' addition to desaturation effect, does compensation for red color, r_glsl_restart is required"};
248
249 cvar_t r_glsl_vertextextureblend_usebothalphas = {CF_CLIENT | CF_ARCHIVE, "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."};
250
251 // FIXME: This cvar would grow to a ridiculous size after several launches and clean exits when used during surface sorting.
252 cvar_t r_framedatasize = {CF_CLIENT | CF_ARCHIVE, "r_framedatasize", "0.5", "size of renderer data cache used during one frame (for skeletal animation caching, light processing, etc)"};
253 cvar_t r_buffermegs[R_BUFFERDATA_COUNT] =
254 {
255         {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_vertex", "4", "vertex buffer size for one frame"},
256         {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_index16", "1", "index buffer size for one frame (16bit indices)"},
257         {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_index32", "1", "index buffer size for one frame (32bit indices)"},
258         {CF_CLIENT | CF_ARCHIVE, "r_buffermegs_uniform", "0.25", "uniform buffer size for one frame"},
259 };
260
261 cvar_t r_q1bsp_lightmap_updates_enabled = {CF_CLIENT | CF_ARCHIVE, "r_q1bsp_lightmap_updates_enabled", "1", "allow lightmaps to be updated on Q1BSP maps (don't turn this off except for debugging)"};
262 cvar_t r_q1bsp_lightmap_updates_combine = {CF_CLIENT | CF_ARCHIVE, "r_q1bsp_lightmap_updates_combine", "2", "combine lightmap texture updates to make fewer glTexSubImage2D calls, modes: 0 = immediately upload lightmaps (may be thousands of small 3x3 updates), 1 = combine to one call, 2 = combine to one full texture update (glTexImage2D) which tells the driver it does not need to lock the resource (faster on most drivers)"};
263 cvar_t r_q1bsp_lightmap_updates_hidden_surfaces = {CF_CLIENT | CF_ARCHIVE, "r_q1bsp_lightmap_updates_hidden_surfaces", "0", "update lightmaps on surfaces that are not visible, so that updates only occur on frames where lightstyles changed value (animation or light switches), only makes sense with combine = 2"};
264
265 extern cvar_t v_glslgamma_2d;
266
267 extern qbool v_flipped_state;
268
269 r_framebufferstate_t r_fb;
270
271 /// shadow volume bsp struct with automatically growing nodes buffer
272 svbsp_t r_svbsp;
273
274 int r_uniformbufferalignment = 32; // dynamically updated to match GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
275
276 rtexture_t *r_texture_blanknormalmap;
277 rtexture_t *r_texture_white;
278 rtexture_t *r_texture_grey128;
279 rtexture_t *r_texture_black;
280 rtexture_t *r_texture_notexture;
281 rtexture_t *r_texture_whitecube;
282 rtexture_t *r_texture_normalizationcube;
283 rtexture_t *r_texture_fogattenuation;
284 rtexture_t *r_texture_fogheighttexture;
285 rtexture_t *r_texture_gammaramps;
286 unsigned int r_texture_gammaramps_serial;
287 //rtexture_t *r_texture_fogintensity;
288 rtexture_t *r_texture_reflectcube;
289
290 // TODO: hash lookups?
291 typedef struct cubemapinfo_s
292 {
293         char basename[64];
294         rtexture_t *texture;
295 }
296 cubemapinfo_t;
297
298 int r_texture_numcubemaps;
299 cubemapinfo_t *r_texture_cubemaps[MAX_CUBEMAPS];
300
301 unsigned int r_queries[MAX_OCCLUSION_QUERIES];
302 unsigned int r_numqueries;
303 unsigned int r_maxqueries;
304
305 typedef struct r_qwskincache_s
306 {
307         char name[MAX_QPATH];
308         skinframe_t *skinframe;
309 }
310 r_qwskincache_t;
311
312 static r_qwskincache_t *r_qwskincache;
313 static int r_qwskincache_size;
314
315 /// vertex coordinates for a quad that covers the screen exactly
316 extern const float r_screenvertex3f[12];
317 const float r_screenvertex3f[12] =
318 {
319         0, 0, 0,
320         1, 0, 0,
321         1, 1, 0,
322         0, 1, 0
323 };
324
325 void R_ModulateColors(float *in, float *out, int verts, float r, float g, float b)
326 {
327         int i;
328         for (i = 0;i < verts;i++)
329         {
330                 out[0] = in[0] * r;
331                 out[1] = in[1] * g;
332                 out[2] = in[2] * b;
333                 out[3] = in[3];
334                 in += 4;
335                 out += 4;
336         }
337 }
338
339 void R_FillColors(float *out, int verts, float r, float g, float b, float a)
340 {
341         int i;
342         for (i = 0;i < verts;i++)
343         {
344                 out[0] = r;
345                 out[1] = g;
346                 out[2] = b;
347                 out[3] = a;
348                 out += 4;
349         }
350 }
351
352 // FIXME: move this to client?
353 void FOG_clear(void)
354 {
355         if (gamemode == GAME_NEHAHRA)
356         {
357                 Cvar_Set(&cvars_all, "gl_fogenable", "0");
358                 Cvar_Set(&cvars_all, "gl_fogdensity", "0.2");
359                 Cvar_Set(&cvars_all, "gl_fogred", "0.3");
360                 Cvar_Set(&cvars_all, "gl_foggreen", "0.3");
361                 Cvar_Set(&cvars_all, "gl_fogblue", "0.3");
362         }
363         r_refdef.fog_density = 0;
364         r_refdef.fog_red = 0;
365         r_refdef.fog_green = 0;
366         r_refdef.fog_blue = 0;
367         r_refdef.fog_alpha = 1;
368         r_refdef.fog_start = 0;
369         r_refdef.fog_end = 16384;
370         r_refdef.fog_height = 1<<30;
371         r_refdef.fog_fadedepth = 128;
372         memset(r_refdef.fog_height_texturename, 0, sizeof(r_refdef.fog_height_texturename));
373 }
374
375 static void R_BuildBlankTextures(void)
376 {
377         unsigned char data[4];
378         data[2] = 128; // normal X
379         data[1] = 128; // normal Y
380         data[0] = 255; // normal Z
381         data[3] = 255; // height
382         r_texture_blanknormalmap = R_LoadTexture2D(r_main_texturepool, "blankbump", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
383         data[0] = 255;
384         data[1] = 255;
385         data[2] = 255;
386         data[3] = 255;
387         r_texture_white = R_LoadTexture2D(r_main_texturepool, "blankwhite", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
388         data[0] = 128;
389         data[1] = 128;
390         data[2] = 128;
391         data[3] = 255;
392         r_texture_grey128 = R_LoadTexture2D(r_main_texturepool, "blankgrey128", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
393         data[0] = 0;
394         data[1] = 0;
395         data[2] = 0;
396         data[3] = 255;
397         r_texture_black = R_LoadTexture2D(r_main_texturepool, "blankblack", 1, 1, data, TEXTYPE_BGRA, TEXF_PERSISTENT, -1, NULL);
398 }
399
400 static void R_BuildNoTexture(void)
401 {
402         r_texture_notexture = R_LoadTexture2D(r_main_texturepool, "notexture", 16, 16, Image_GenerateNoTexture(), TEXTYPE_BGRA, TEXF_MIPMAP | TEXF_PERSISTENT, -1, NULL);
403 }
404
405 static void R_BuildWhiteCube(void)
406 {
407         unsigned char data[6*1*1*4];
408         memset(data, 255, sizeof(data));
409         r_texture_whitecube = R_LoadTextureCubeMap(r_main_texturepool, "whitecube", 1, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
410 }
411
412 static void R_BuildNormalizationCube(void)
413 {
414         int x, y, side;
415         vec3_t v;
416         vec_t s, t, intensity;
417 #define NORMSIZE 64
418         unsigned char *data;
419         data = (unsigned char *)Mem_Alloc(tempmempool, 6*NORMSIZE*NORMSIZE*4);
420         for (side = 0;side < 6;side++)
421         {
422                 for (y = 0;y < NORMSIZE;y++)
423                 {
424                         for (x = 0;x < NORMSIZE;x++)
425                         {
426                                 s = (x + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
427                                 t = (y + 0.5f) * (2.0f / NORMSIZE) - 1.0f;
428                                 switch(side)
429                                 {
430                                 default:
431                                 case 0:
432                                         v[0] = 1;
433                                         v[1] = -t;
434                                         v[2] = -s;
435                                         break;
436                                 case 1:
437                                         v[0] = -1;
438                                         v[1] = -t;
439                                         v[2] = s;
440                                         break;
441                                 case 2:
442                                         v[0] = s;
443                                         v[1] = 1;
444                                         v[2] = t;
445                                         break;
446                                 case 3:
447                                         v[0] = s;
448                                         v[1] = -1;
449                                         v[2] = -t;
450                                         break;
451                                 case 4:
452                                         v[0] = s;
453                                         v[1] = -t;
454                                         v[2] = 1;
455                                         break;
456                                 case 5:
457                                         v[0] = -s;
458                                         v[1] = -t;
459                                         v[2] = -1;
460                                         break;
461                                 }
462                                 intensity = 127.0f / sqrt(DotProduct(v, v));
463                                 data[((side*64+y)*64+x)*4+2] = (unsigned char)(128.0f + intensity * v[0]);
464                                 data[((side*64+y)*64+x)*4+1] = (unsigned char)(128.0f + intensity * v[1]);
465                                 data[((side*64+y)*64+x)*4+0] = (unsigned char)(128.0f + intensity * v[2]);
466                                 data[((side*64+y)*64+x)*4+3] = 255;
467                         }
468                 }
469         }
470         r_texture_normalizationcube = R_LoadTextureCubeMap(r_main_texturepool, "normalcube", NORMSIZE, data, TEXTYPE_BGRA, TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
471         Mem_Free(data);
472 }
473
474 static void R_BuildFogTexture(void)
475 {
476         int x, b;
477 #define FOGWIDTH 256
478         unsigned char data1[FOGWIDTH][4];
479         //unsigned char data2[FOGWIDTH][4];
480         double d, r, alpha;
481
482         r_refdef.fogmasktable_start = r_refdef.fog_start;
483         r_refdef.fogmasktable_alpha = r_refdef.fog_alpha;
484         r_refdef.fogmasktable_range = r_refdef.fogrange;
485         r_refdef.fogmasktable_density = r_refdef.fog_density;
486
487         r = r_refdef.fogmasktable_range / FOGMASKTABLEWIDTH;
488         for (x = 0;x < FOGMASKTABLEWIDTH;x++)
489         {
490                 d = (x * r - r_refdef.fogmasktable_start);
491                 if(developer_extra.integer)
492                         Con_DPrintf("%f ", d);
493                 d = max(0, d);
494                 if (r_fog_exp2.integer)
495                         alpha = exp(-r_refdef.fogmasktable_density * r_refdef.fogmasktable_density * 0.0001 * d * d);
496                 else
497                         alpha = exp(-r_refdef.fogmasktable_density * 0.004 * d);
498                 if(developer_extra.integer)
499                         Con_DPrintf(" : %f ", alpha);
500                 alpha = 1 - (1 - alpha) * r_refdef.fogmasktable_alpha;
501                 if(developer_extra.integer)
502                         Con_DPrintf(" = %f\n", alpha);
503                 r_refdef.fogmasktable[x] = bound(0, alpha, 1);
504         }
505
506         for (x = 0;x < FOGWIDTH;x++)
507         {
508                 b = (int)(r_refdef.fogmasktable[x * (FOGMASKTABLEWIDTH - 1) / (FOGWIDTH - 1)] * 255);
509                 data1[x][0] = b;
510                 data1[x][1] = b;
511                 data1[x][2] = b;
512                 data1[x][3] = 255;
513                 //data2[x][0] = 255 - b;
514                 //data2[x][1] = 255 - b;
515                 //data2[x][2] = 255 - b;
516                 //data2[x][3] = 255;
517         }
518         if (r_texture_fogattenuation)
519         {
520                 R_UpdateTexture(r_texture_fogattenuation, &data1[0][0], 0, 0, 0, FOGWIDTH, 1, 1, 0);
521                 //R_UpdateTexture(r_texture_fogattenuation, &data2[0][0], 0, 0, 0, FOGWIDTH, 1, 1, 0);
522         }
523         else
524         {
525                 r_texture_fogattenuation = R_LoadTexture2D(r_main_texturepool, "fogattenuation", FOGWIDTH, 1, &data1[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
526                 //r_texture_fogintensity = R_LoadTexture2D(r_main_texturepool, "fogintensity", FOGWIDTH, 1, &data2[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP, NULL);
527         }
528 }
529
530 static void R_BuildFogHeightTexture(void)
531 {
532         unsigned char *inpixels;
533         int size;
534         int x;
535         int y;
536         int j;
537         float c[4];
538         float f;
539         inpixels = NULL;
540         strlcpy(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename, sizeof(r_refdef.fogheighttexturename));
541         if (r_refdef.fogheighttexturename[0])
542                 inpixels = loadimagepixelsbgra(r_refdef.fogheighttexturename, true, false, false, NULL);
543         if (!inpixels)
544         {
545                 r_refdef.fog_height_tablesize = 0;
546                 if (r_texture_fogheighttexture)
547                         R_FreeTexture(r_texture_fogheighttexture);
548                 r_texture_fogheighttexture = NULL;
549                 if (r_refdef.fog_height_table2d)
550                         Mem_Free(r_refdef.fog_height_table2d);
551                 r_refdef.fog_height_table2d = NULL;
552                 if (r_refdef.fog_height_table1d)
553                         Mem_Free(r_refdef.fog_height_table1d);
554                 r_refdef.fog_height_table1d = NULL;
555                 return;
556         }
557         size = image_width;
558         r_refdef.fog_height_tablesize = size;
559         r_refdef.fog_height_table1d = (unsigned char *)Mem_Alloc(r_main_mempool, size * 4);
560         r_refdef.fog_height_table2d = (unsigned char *)Mem_Alloc(r_main_mempool, size * size * 4);
561         memcpy(r_refdef.fog_height_table1d, inpixels, size * 4);
562         Mem_Free(inpixels);
563         // LadyHavoc: now the magic - what is that table2d for?  it is a cooked
564         // average fog color table accounting for every fog layer between a point
565         // and the camera.  (Note: attenuation is handled separately!)
566         for (y = 0;y < size;y++)
567         {
568                 for (x = 0;x < size;x++)
569                 {
570                         Vector4Clear(c);
571                         f = 0;
572                         if (x < y)
573                         {
574                                 for (j = x;j <= y;j++)
575                                 {
576                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
577                                         f++;
578                                 }
579                         }
580                         else
581                         {
582                                 for (j = x;j >= y;j--)
583                                 {
584                                         Vector4Add(c, r_refdef.fog_height_table1d + j*4, c);
585                                         f++;
586                                 }
587                         }
588                         f = 1.0f / f;
589                         r_refdef.fog_height_table2d[(y*size+x)*4+0] = (unsigned char)(c[0] * f);
590                         r_refdef.fog_height_table2d[(y*size+x)*4+1] = (unsigned char)(c[1] * f);
591                         r_refdef.fog_height_table2d[(y*size+x)*4+2] = (unsigned char)(c[2] * f);
592                         r_refdef.fog_height_table2d[(y*size+x)*4+3] = (unsigned char)(c[3] * f);
593                 }
594         }
595         r_texture_fogheighttexture = R_LoadTexture2D(r_main_texturepool, "fogheighttable", size, size, r_refdef.fog_height_table2d, TEXTYPE_BGRA, TEXF_ALPHA | TEXF_CLAMP, -1, NULL);
596 }
597
598 //=======================================================================================================================================================
599
600 static const char *builtinshaderstrings[] =
601 {
602 #include "shader_glsl.h"
603 0
604 };
605
606 //=======================================================================================================================================================
607
608 typedef struct shaderpermutationinfo_s
609 {
610         const char *pretext;
611         const char *name;
612 }
613 shaderpermutationinfo_t;
614
615 typedef struct shadermodeinfo_s
616 {
617         const char *sourcebasename;
618         const char *extension;
619         const char **builtinshaderstrings;
620         const char *pretext;
621         const char *name;
622         char *filename;
623         char *builtinstring;
624         int builtincrc;
625 }
626 shadermodeinfo_t;
627
628 // NOTE: MUST MATCH ORDER OF SHADERPERMUTATION_* DEFINES!
629 shaderpermutationinfo_t shaderpermutationinfo[SHADERPERMUTATION_COUNT] =
630 {
631         {"#define USEDIFFUSE\n", " diffuse"},
632         {"#define USEVERTEXTEXTUREBLEND\n", " vertextextureblend"},
633         {"#define USEVIEWTINT\n", " viewtint"},
634         {"#define USECOLORMAPPING\n", " colormapping"},
635         {"#define USESATURATION\n", " saturation"},
636         {"#define USEFOGINSIDE\n", " foginside"},
637         {"#define USEFOGOUTSIDE\n", " fogoutside"},
638         {"#define USEFOGHEIGHTTEXTURE\n", " fogheighttexture"},
639         {"#define USEFOGALPHAHACK\n", " fogalphahack"},
640         {"#define USEGAMMARAMPS\n", " gammaramps"},
641         {"#define USECUBEFILTER\n", " cubefilter"},
642         {"#define USEGLOW\n", " glow"},
643         {"#define USEBLOOM\n", " bloom"},
644         {"#define USESPECULAR\n", " specular"},
645         {"#define USEPOSTPROCESSING\n", " postprocessing"},
646         {"#define USEREFLECTION\n", " reflection"},
647         {"#define USEOFFSETMAPPING\n", " offsetmapping"},
648         {"#define USEOFFSETMAPPING_RELIEFMAPPING\n", " reliefmapping"},
649         {"#define USESHADOWMAP2D\n", " shadowmap2d"},
650         {"#define USESHADOWMAPVSDCT\n", " shadowmapvsdct"}, // TODO make this a static parm
651         {"#define USESHADOWMAPORTHO\n", " shadowmaportho"},
652         {"#define USEDEFERREDLIGHTMAP\n", " deferredlightmap"},
653         {"#define USEALPHAKILL\n", " alphakill"},
654         {"#define USEREFLECTCUBE\n", " reflectcube"},
655         {"#define USENORMALMAPSCROLLBLEND\n", " normalmapscrollblend"},
656         {"#define USEBOUNCEGRID\n", " bouncegrid"},
657         {"#define USEBOUNCEGRIDDIRECTIONAL\n", " bouncegriddirectional"}, // TODO make this a static parm
658         {"#define USETRIPPY\n", " trippy"},
659         {"#define USEDEPTHRGB\n", " depthrgb"},
660         {"#define USEALPHAGENVERTEX\n", " alphagenvertex"},
661         {"#define USESKELETAL\n", " skeletal"},
662         {"#define USEOCCLUDE\n", " occlude"}
663 };
664
665 // NOTE: MUST MATCH ORDER OF SHADERMODE_* ENUMS!
666 shadermodeinfo_t shadermodeinfo[SHADERLANGUAGE_COUNT][SHADERMODE_COUNT] =
667 {
668         // SHADERLANGUAGE_GLSL
669         {
670                 {"combined", "glsl", builtinshaderstrings, "#define MODE_GENERIC\n", " generic"},
671                 {"combined", "glsl", builtinshaderstrings, "#define MODE_POSTPROCESS\n", " postprocess"},
672                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEPTH_OR_SHADOW\n", " depth/shadow"},
673                 {"combined", "glsl", builtinshaderstrings, "#define MODE_FLATCOLOR\n", " flatcolor"},
674                 {"combined", "glsl", builtinshaderstrings, "#define MODE_VERTEXCOLOR\n", " vertexcolor"},
675                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTMAP\n", " lightmap"},
676                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_MODELSPACE\n", " lightdirectionmap_modelspace"},
677                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_TANGENTSPACE\n", " lightdirectionmap_tangentspace"},
678                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP\n", " lightdirectionmap_forced_lightmap"},
679                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR\n", " lightdirectionmap_forced_vertexcolor"},
680                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTGRID\n", " lightgrid"},
681                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTDIRECTION\n", " lightdirection"},
682                 {"combined", "glsl", builtinshaderstrings, "#define MODE_LIGHTSOURCE\n", " lightsource"},
683                 {"combined", "glsl", builtinshaderstrings, "#define MODE_REFRACTION\n", " refraction"},
684                 {"combined", "glsl", builtinshaderstrings, "#define MODE_WATER\n", " water"},
685                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDGEOMETRY\n", " deferredgeometry"},
686                 {"combined", "glsl", builtinshaderstrings, "#define MODE_DEFERREDLIGHTSOURCE\n", " deferredlightsource"},
687         },
688 };
689
690 struct r_glsl_permutation_s;
691 typedef struct r_glsl_permutation_s
692 {
693         /// hash lookup data
694         struct r_glsl_permutation_s *hashnext;
695         unsigned int mode;
696         uint64_t permutation;
697
698         /// indicates if we have tried compiling this permutation already
699         qbool compiled;
700         /// 0 if compilation failed
701         int program;
702         // texture units assigned to each detected uniform
703         int tex_Texture_First;
704         int tex_Texture_Second;
705         int tex_Texture_GammaRamps;
706         int tex_Texture_Normal;
707         int tex_Texture_Color;
708         int tex_Texture_Gloss;
709         int tex_Texture_Glow;
710         int tex_Texture_SecondaryNormal;
711         int tex_Texture_SecondaryColor;
712         int tex_Texture_SecondaryGloss;
713         int tex_Texture_SecondaryGlow;
714         int tex_Texture_Pants;
715         int tex_Texture_Shirt;
716         int tex_Texture_FogHeightTexture;
717         int tex_Texture_FogMask;
718         int tex_Texture_LightGrid;
719         int tex_Texture_Lightmap;
720         int tex_Texture_Deluxemap;
721         int tex_Texture_Attenuation;
722         int tex_Texture_Cube;
723         int tex_Texture_Refraction;
724         int tex_Texture_Reflection;
725         int tex_Texture_ShadowMap2D;
726         int tex_Texture_CubeProjection;
727         int tex_Texture_ScreenNormalMap;
728         int tex_Texture_ScreenDiffuse;
729         int tex_Texture_ScreenSpecular;
730         int tex_Texture_ReflectMask;
731         int tex_Texture_ReflectCube;
732         int tex_Texture_BounceGrid;
733         /// locations of detected uniforms in program object, or -1 if not found
734         int loc_Texture_First;
735         int loc_Texture_Second;
736         int loc_Texture_GammaRamps;
737         int loc_Texture_Normal;
738         int loc_Texture_Color;
739         int loc_Texture_Gloss;
740         int loc_Texture_Glow;
741         int loc_Texture_SecondaryNormal;
742         int loc_Texture_SecondaryColor;
743         int loc_Texture_SecondaryGloss;
744         int loc_Texture_SecondaryGlow;
745         int loc_Texture_Pants;
746         int loc_Texture_Shirt;
747         int loc_Texture_FogHeightTexture;
748         int loc_Texture_FogMask;
749         int loc_Texture_LightGrid;
750         int loc_Texture_Lightmap;
751         int loc_Texture_Deluxemap;
752         int loc_Texture_Attenuation;
753         int loc_Texture_Cube;
754         int loc_Texture_Refraction;
755         int loc_Texture_Reflection;
756         int loc_Texture_ShadowMap2D;
757         int loc_Texture_CubeProjection;
758         int loc_Texture_ScreenNormalMap;
759         int loc_Texture_ScreenDiffuse;
760         int loc_Texture_ScreenSpecular;
761         int loc_Texture_ReflectMask;
762         int loc_Texture_ReflectCube;
763         int loc_Texture_BounceGrid;
764         int loc_Alpha;
765         int loc_BloomBlur_Parameters;
766         int loc_ClientTime;
767         int loc_Color_Ambient;
768         int loc_Color_Diffuse;
769         int loc_Color_Specular;
770         int loc_Color_Glow;
771         int loc_Color_Pants;
772         int loc_Color_Shirt;
773         int loc_DeferredColor_Ambient;
774         int loc_DeferredColor_Diffuse;
775         int loc_DeferredColor_Specular;
776         int loc_DeferredMod_Diffuse;
777         int loc_DeferredMod_Specular;
778         int loc_DistortScaleRefractReflect;
779         int loc_EyePosition;
780         int loc_FogColor;
781         int loc_FogHeightFade;
782         int loc_FogPlane;
783         int loc_FogPlaneViewDist;
784         int loc_FogRangeRecip;
785         int loc_LightColor;
786         int loc_LightDir;
787         int loc_LightGridMatrix;
788         int loc_LightGridNormalMatrix;
789         int loc_LightPosition;
790         int loc_OffsetMapping_ScaleSteps;
791         int loc_OffsetMapping_LodDistance;
792         int loc_OffsetMapping_Bias;
793         int loc_PixelSize;
794         int loc_ReflectColor;
795         int loc_ReflectFactor;
796         int loc_ReflectOffset;
797         int loc_RefractColor;
798         int loc_Saturation;
799         int loc_ScreenCenterRefractReflect;
800         int loc_ScreenScaleRefractReflect;
801         int loc_ScreenToDepth;
802         int loc_ShadowMap_Parameters;
803         int loc_ShadowMap_TextureScale;
804         int loc_SpecularPower;
805         int loc_Skeletal_Transform12;
806         int loc_UserVec1;
807         int loc_UserVec2;
808         int loc_UserVec3;
809         int loc_UserVec4;
810         int loc_ColorFringe;
811         int loc_ViewTintColor;
812         int loc_ViewToLight;
813         int loc_ModelToLight;
814         int loc_TexMatrix;
815         int loc_BackgroundTexMatrix;
816         int loc_ModelViewProjectionMatrix;
817         int loc_ModelViewMatrix;
818         int loc_PixelToScreenTexCoord;
819         int loc_ModelToReflectCube;
820         int loc_ShadowMapMatrix;
821         int loc_BloomColorSubtract;
822         int loc_NormalmapScrollBlend;
823         int loc_BounceGridMatrix;
824         int loc_BounceGridIntensity;
825         /// uniform block bindings
826         int ubibind_Skeletal_Transform12_UniformBlock;
827         /// uniform block indices
828         int ubiloc_Skeletal_Transform12_UniformBlock;
829 }
830 r_glsl_permutation_t;
831
832 #define SHADERPERMUTATION_HASHSIZE 256
833
834
835 // non-degradable "lightweight" shader parameters to keep the permutations simpler
836 // these can NOT degrade! only use for simple stuff
837 enum
838 {
839         SHADERSTATICPARM_SATURATION_REDCOMPENSATE = 0, ///< red compensation filter for saturation
840         SHADERSTATICPARM_EXACTSPECULARMATH = 1, ///< (lightsource or deluxemapping) use exact reflection map for specular effects, as opposed to the usual OpenGL approximation
841         SHADERSTATICPARM_POSTPROCESS_USERVEC1 = 2, ///< postprocess uservec1 is enabled
842         SHADERSTATICPARM_POSTPROCESS_USERVEC2 = 3, ///< postprocess uservec2 is enabled
843         SHADERSTATICPARM_POSTPROCESS_USERVEC3 = 4, ///< postprocess uservec3 is enabled
844         SHADERSTATICPARM_POSTPROCESS_USERVEC4 = 5,  ///< postprocess uservec4 is enabled
845         SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS = 6, // use both alpha layers while blending materials, allows more advanced microblending
846         SHADERSTATICPARM_OFFSETMAPPING_USELOD = 7,  ///< LOD for offsetmapping
847         SHADERSTATICPARM_SHADOWMAPPCF_1 = 8, ///< PCF 1
848         SHADERSTATICPARM_SHADOWMAPPCF_2 = 9, ///< PCF 2
849         SHADERSTATICPARM_SHADOWSAMPLER = 10, ///< sampler
850         SHADERSTATICPARM_CELSHADING = 11, ///< celshading (alternative diffuse and specular math)
851         SHADERSTATICPARM_CELOUTLINES = 12, ///< celoutline (depth buffer analysis to produce outlines)
852         SHADERSTATICPARM_FXAA = 13, ///< fast approximate anti aliasing
853         SHADERSTATICPARM_COLORFRINGE = 14 ///< colorfringe (chromatic aberration)
854 };
855 #define SHADERSTATICPARMS_COUNT 15
856
857 static const char *shaderstaticparmstrings_list[SHADERSTATICPARMS_COUNT];
858 static int shaderstaticparms_count = 0;
859
860 static unsigned int r_compileshader_staticparms[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5] = {0};
861 #define R_COMPILESHADER_STATICPARM_ENABLE(p) r_compileshader_staticparms[(p) >> 5] |= (1 << ((p) & 0x1F))
862
863 extern qbool r_shadow_shadowmapsampler;
864 extern int r_shadow_shadowmappcf;
865 qbool R_CompileShader_CheckStaticParms(void)
866 {
867         static int r_compileshader_staticparms_save[(SHADERSTATICPARMS_COUNT + 0x1F) >> 5];
868         memcpy(r_compileshader_staticparms_save, r_compileshader_staticparms, sizeof(r_compileshader_staticparms));
869         memset(r_compileshader_staticparms, 0, sizeof(r_compileshader_staticparms));
870
871         // detect all
872         if (r_glsl_saturation_redcompensate.integer)
873                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SATURATION_REDCOMPENSATE);
874         if (r_glsl_vertextextureblend_usebothalphas.integer)
875                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS);
876         if (r_shadow_glossexact.integer)
877                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_EXACTSPECULARMATH);
878         if (r_glsl_postprocess.integer)
879         {
880                 if (r_glsl_postprocess_uservec1_enable.integer)
881                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC1);
882                 if (r_glsl_postprocess_uservec2_enable.integer)
883                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC2);
884                 if (r_glsl_postprocess_uservec3_enable.integer)
885                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC3);
886                 if (r_glsl_postprocess_uservec4_enable.integer)
887                         R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_POSTPROCESS_USERVEC4);
888         }
889         if (r_fxaa.integer)
890                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_FXAA);
891         if (r_glsl_offsetmapping_lod.integer && r_glsl_offsetmapping_lod_distance.integer > 0)
892                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_OFFSETMAPPING_USELOD);
893
894         if (r_shadow_shadowmapsampler)
895                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWSAMPLER);
896         if (r_shadow_shadowmappcf > 1)
897                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_2);
898         else if (r_shadow_shadowmappcf)
899                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_SHADOWMAPPCF_1);
900         if (r_celshading.integer)
901                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELSHADING);
902         if (r_celoutlines.integer)
903                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_CELOUTLINES);
904         if (r_colorfringe.value)
905                 R_COMPILESHADER_STATICPARM_ENABLE(SHADERSTATICPARM_COLORFRINGE);
906
907         return memcmp(r_compileshader_staticparms, r_compileshader_staticparms_save, sizeof(r_compileshader_staticparms)) != 0;
908 }
909
910 #define R_COMPILESHADER_STATICPARM_EMIT(p, n) \
911         if(r_compileshader_staticparms[(p) >> 5] & (1 << ((p) & 0x1F))) \
912                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "#define " n "\n"; \
913         else \
914                 shaderstaticparmstrings_list[shaderstaticparms_count++] = "\n"
915 static void R_CompileShader_AddStaticParms(unsigned int mode, uint64_t permutation)
916 {
917         shaderstaticparms_count = 0;
918
919         // emit all
920         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SATURATION_REDCOMPENSATE, "SATURATION_REDCOMPENSATE");
921         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_EXACTSPECULARMATH, "USEEXACTSPECULARMATH");
922         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC1, "USERVEC1");
923         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC2, "USERVEC2");
924         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC3, "USERVEC3");
925         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_POSTPROCESS_USERVEC4, "USERVEC4");
926         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_VERTEXTEXTUREBLEND_USEBOTHALPHAS, "USEBOTHALPHAS");
927         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_OFFSETMAPPING_USELOD, "USEOFFSETMAPPING_LOD");
928         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_1, "USESHADOWMAPPCF 1");
929         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWMAPPCF_2, "USESHADOWMAPPCF 2");
930         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_SHADOWSAMPLER, "USESHADOWSAMPLER");
931         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELSHADING, "USECELSHADING");
932         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_CELOUTLINES, "USECELOUTLINES");
933         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_FXAA, "USEFXAA");
934         R_COMPILESHADER_STATICPARM_EMIT(SHADERSTATICPARM_COLORFRINGE, "USECOLORFRINGE");
935 }
936
937 /// information about each possible shader permutation
938 r_glsl_permutation_t *r_glsl_permutationhash[SHADERMODE_COUNT][SHADERPERMUTATION_HASHSIZE];
939 /// currently selected permutation
940 r_glsl_permutation_t *r_glsl_permutation;
941 /// storage for permutations linked in the hash table
942 memexpandablearray_t r_glsl_permutationarray;
943
944 static r_glsl_permutation_t *R_GLSL_FindPermutation(unsigned int mode, uint64_t permutation)
945 {
946         //unsigned int hashdepth = 0;
947         unsigned int hashindex = (permutation * 0x1021) & (SHADERPERMUTATION_HASHSIZE - 1);
948         r_glsl_permutation_t *p;
949         for (p = r_glsl_permutationhash[mode][hashindex];p;p = p->hashnext)
950         {
951                 if (p->mode == mode && p->permutation == permutation)
952                 {
953                         //if (hashdepth > 10)
954                         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
955                         return p;
956                 }
957                 //hashdepth++;
958         }
959         p = (r_glsl_permutation_t*)Mem_ExpandableArray_AllocRecord(&r_glsl_permutationarray);
960         p->mode = mode;
961         p->permutation = permutation;
962         p->hashnext = r_glsl_permutationhash[mode][hashindex];
963         r_glsl_permutationhash[mode][hashindex] = p;
964         //if (hashdepth > 10)
965         //      Con_Printf("R_GLSL_FindPermutation: Warning: %i:%i has hashdepth %i\n", mode, permutation, hashdepth);
966         return p;
967 }
968
969 static char *R_ShaderStrCat(const char **strings)
970 {
971         char *string, *s;
972         const char **p = strings;
973         const char *t;
974         size_t len = 0;
975         for (p = strings;(t = *p);p++)
976                 len += strlen(t);
977         len++;
978         s = string = (char *)Mem_Alloc(r_main_mempool, len);
979         len = 0;
980         for (p = strings;(t = *p);p++)
981         {
982                 len = strlen(t);
983                 memcpy(s, t, len);
984                 s += len;
985         }
986         *s = 0;
987         return string;
988 }
989
990 static char *R_ShaderStrCat(const char **strings);
991 static void R_InitShaderModeInfo(void)
992 {
993         int i, language;
994         shadermodeinfo_t *modeinfo;
995         // 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)
996         for (language = 0; language < SHADERLANGUAGE_COUNT; language++)
997         {
998                 for (i = 0; i < SHADERMODE_COUNT; i++)
999                 {
1000                         char filename[MAX_QPATH];
1001                         modeinfo = &shadermodeinfo[language][i];
1002                         modeinfo->builtinstring = R_ShaderStrCat(modeinfo->builtinshaderstrings);
1003                         modeinfo->builtincrc = CRC_Block((const unsigned char *)modeinfo->builtinstring, strlen(modeinfo->builtinstring));
1004                         dpsnprintf(filename, sizeof(filename), "%s/%s_crc%i.%s", modeinfo->extension, modeinfo->sourcebasename, modeinfo->builtincrc, modeinfo->extension);
1005                         modeinfo->filename = Mem_strdup(r_main_mempool, filename);
1006                 }
1007         }
1008 }
1009
1010 static char *ShaderModeInfo_GetShaderText(shadermodeinfo_t *modeinfo, qbool printfromdisknotice, qbool builtinonly)
1011 {
1012         char *shaderstring;
1013         // if the mode has no filename we have to return the builtin string
1014         if (builtinonly || !modeinfo->filename)
1015                 return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1016         // note that FS_LoadFile appends a 0 byte to make it a valid string
1017         shaderstring = (char *)FS_LoadFile(modeinfo->filename, r_main_mempool, false, NULL);
1018         if (shaderstring)
1019         {
1020                 if (printfromdisknotice)
1021                         Con_DPrintf("Loading shaders from file %s...\n", modeinfo->filename);
1022                 return shaderstring;
1023         }
1024         // fall back to builtinstring
1025         return Mem_strdup(r_main_mempool, modeinfo->builtinstring);
1026 }
1027
1028 static void R_GLSL_CompilePermutation(r_glsl_permutation_t *p, unsigned int mode, uint64_t permutation)
1029 {
1030         int i;
1031         int ubibind;
1032         int sampler;
1033         shadermodeinfo_t *modeinfo = &shadermodeinfo[SHADERLANGUAGE_GLSL][mode];
1034         char *sourcestring;
1035         char permutationname[256];
1036         int vertstrings_count = 0;
1037         int geomstrings_count = 0;
1038         int fragstrings_count = 0;
1039         const char *vertstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1040         const char *geomstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1041         const char *fragstrings_list[32+5+SHADERSTATICPARMS_COUNT+1];
1042
1043         if (p->compiled)
1044                 return;
1045         p->compiled = true;
1046         p->program = 0;
1047
1048         permutationname[0] = 0;
1049         sourcestring = ShaderModeInfo_GetShaderText(modeinfo, true, false);
1050
1051         strlcat(permutationname, modeinfo->filename, sizeof(permutationname));
1052
1053         // we need 140 for r_glsl_skeletal (GL_ARB_uniform_buffer_object)
1054         if(vid.support.glshaderversion >= 140)
1055         {
1056                 vertstrings_list[vertstrings_count++] = "#version 140\n";
1057                 geomstrings_list[geomstrings_count++] = "#version 140\n";
1058                 fragstrings_list[fragstrings_count++] = "#version 140\n";
1059                 vertstrings_list[vertstrings_count++] = "#define GLSL140\n";
1060                 geomstrings_list[geomstrings_count++] = "#define GLSL140\n";
1061                 fragstrings_list[fragstrings_count++] = "#define GLSL140\n";
1062         }
1063         // if we can do #version 130, we should (this improves quality of offset/reliefmapping thanks to textureGrad)
1064         else if(vid.support.glshaderversion >= 130)
1065         {
1066                 vertstrings_list[vertstrings_count++] = "#version 130\n";
1067                 geomstrings_list[geomstrings_count++] = "#version 130\n";
1068                 fragstrings_list[fragstrings_count++] = "#version 130\n";
1069                 vertstrings_list[vertstrings_count++] = "#define GLSL130\n";
1070                 geomstrings_list[geomstrings_count++] = "#define GLSL130\n";
1071                 fragstrings_list[fragstrings_count++] = "#define GLSL130\n";
1072         }
1073         // if we can do #version 120, we should (this adds the invariant keyword)
1074         else if(vid.support.glshaderversion >= 120)
1075         {
1076                 vertstrings_list[vertstrings_count++] = "#version 120\n";
1077                 geomstrings_list[geomstrings_count++] = "#version 120\n";
1078                 fragstrings_list[fragstrings_count++] = "#version 120\n";
1079                 vertstrings_list[vertstrings_count++] = "#define GLSL120\n";
1080                 geomstrings_list[geomstrings_count++] = "#define GLSL120\n";
1081                 fragstrings_list[fragstrings_count++] = "#define GLSL120\n";
1082         }
1083         // GLES also adds several things from GLSL120
1084         switch(vid.renderpath)
1085         {
1086         case RENDERPATH_GLES2:
1087                 vertstrings_list[vertstrings_count++] = "#define GLES\n";
1088                 geomstrings_list[geomstrings_count++] = "#define GLES\n";
1089                 fragstrings_list[fragstrings_count++] = "#define GLES\n";
1090                 break;
1091         default:
1092                 break;
1093         }
1094
1095         // the first pretext is which type of shader to compile as
1096         // (later these will all be bound together as a program object)
1097         vertstrings_list[vertstrings_count++] = "#define VERTEX_SHADER\n";
1098         geomstrings_list[geomstrings_count++] = "#define GEOMETRY_SHADER\n";
1099         fragstrings_list[fragstrings_count++] = "#define FRAGMENT_SHADER\n";
1100
1101         // the second pretext is the mode (for example a light source)
1102         vertstrings_list[vertstrings_count++] = modeinfo->pretext;
1103         geomstrings_list[geomstrings_count++] = modeinfo->pretext;
1104         fragstrings_list[fragstrings_count++] = modeinfo->pretext;
1105         strlcat(permutationname, modeinfo->name, sizeof(permutationname));
1106
1107         // now add all the permutation pretexts
1108         for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1109         {
1110                 if (permutation & (1ll<<i))
1111                 {
1112                         vertstrings_list[vertstrings_count++] = shaderpermutationinfo[i].pretext;
1113                         geomstrings_list[geomstrings_count++] = shaderpermutationinfo[i].pretext;
1114                         fragstrings_list[fragstrings_count++] = shaderpermutationinfo[i].pretext;
1115                         strlcat(permutationname, shaderpermutationinfo[i].name, sizeof(permutationname));
1116                 }
1117                 else
1118                 {
1119                         // keep line numbers correct
1120                         vertstrings_list[vertstrings_count++] = "\n";
1121                         geomstrings_list[geomstrings_count++] = "\n";
1122                         fragstrings_list[fragstrings_count++] = "\n";
1123                 }
1124         }
1125
1126         // add static parms
1127         R_CompileShader_AddStaticParms(mode, permutation);
1128         memcpy((char *)(vertstrings_list + vertstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1129         vertstrings_count += shaderstaticparms_count;
1130         memcpy((char *)(geomstrings_list + geomstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1131         geomstrings_count += shaderstaticparms_count;
1132         memcpy((char *)(fragstrings_list + fragstrings_count), shaderstaticparmstrings_list, sizeof(*vertstrings_list) * shaderstaticparms_count);
1133         fragstrings_count += shaderstaticparms_count;
1134
1135         // now append the shader text itself
1136         vertstrings_list[vertstrings_count++] = sourcestring;
1137         geomstrings_list[geomstrings_count++] = sourcestring;
1138         fragstrings_list[fragstrings_count++] = sourcestring;
1139
1140         // we don't currently use geometry shaders for anything, so just empty the list
1141         geomstrings_count = 0;
1142
1143         // compile the shader program
1144         if (vertstrings_count + geomstrings_count + fragstrings_count)
1145                 p->program = GL_Backend_CompileProgram(vertstrings_count, vertstrings_list, geomstrings_count, geomstrings_list, fragstrings_count, fragstrings_list);
1146         if (p->program)
1147         {
1148                 CHECKGLERROR
1149                 qglUseProgram(p->program);CHECKGLERROR
1150                 // look up all the uniform variable names we care about, so we don't
1151                 // have to look them up every time we set them
1152
1153 #if 0
1154                 // debugging aid
1155                 {
1156                         GLint activeuniformindex = 0;
1157                         GLint numactiveuniforms = 0;
1158                         char uniformname[128];
1159                         GLsizei uniformnamelength = 0;
1160                         GLint uniformsize = 0;
1161                         GLenum uniformtype = 0;
1162                         memset(uniformname, 0, sizeof(uniformname));
1163                         qglGetProgramiv(p->program, GL_ACTIVE_UNIFORMS, &numactiveuniforms);
1164                         Con_Printf("Shader has %i uniforms\n", numactiveuniforms);
1165                         for (activeuniformindex = 0;activeuniformindex < numactiveuniforms;activeuniformindex++)
1166                         {
1167                                 qglGetActiveUniform(p->program, activeuniformindex, sizeof(uniformname) - 1, &uniformnamelength, &uniformsize, &uniformtype, uniformname);
1168                                 Con_Printf("Uniform %i name \"%s\" size %i type %i\n", (int)activeuniformindex, uniformname, (int)uniformsize, (int)uniformtype);
1169                         }
1170                 }
1171 #endif
1172
1173                 p->loc_Texture_First              = qglGetUniformLocation(p->program, "Texture_First");
1174                 p->loc_Texture_Second             = qglGetUniformLocation(p->program, "Texture_Second");
1175                 p->loc_Texture_GammaRamps         = qglGetUniformLocation(p->program, "Texture_GammaRamps");
1176                 p->loc_Texture_Normal             = qglGetUniformLocation(p->program, "Texture_Normal");
1177                 p->loc_Texture_Color              = qglGetUniformLocation(p->program, "Texture_Color");
1178                 p->loc_Texture_Gloss              = qglGetUniformLocation(p->program, "Texture_Gloss");
1179                 p->loc_Texture_Glow               = qglGetUniformLocation(p->program, "Texture_Glow");
1180                 p->loc_Texture_SecondaryNormal    = qglGetUniformLocation(p->program, "Texture_SecondaryNormal");
1181                 p->loc_Texture_SecondaryColor     = qglGetUniformLocation(p->program, "Texture_SecondaryColor");
1182                 p->loc_Texture_SecondaryGloss     = qglGetUniformLocation(p->program, "Texture_SecondaryGloss");
1183                 p->loc_Texture_SecondaryGlow      = qglGetUniformLocation(p->program, "Texture_SecondaryGlow");
1184                 p->loc_Texture_Pants              = qglGetUniformLocation(p->program, "Texture_Pants");
1185                 p->loc_Texture_Shirt              = qglGetUniformLocation(p->program, "Texture_Shirt");
1186                 p->loc_Texture_FogHeightTexture   = qglGetUniformLocation(p->program, "Texture_FogHeightTexture");
1187                 p->loc_Texture_FogMask            = qglGetUniformLocation(p->program, "Texture_FogMask");
1188                 p->loc_Texture_LightGrid          = qglGetUniformLocation(p->program, "Texture_LightGrid");
1189                 p->loc_Texture_Lightmap           = qglGetUniformLocation(p->program, "Texture_Lightmap");
1190                 p->loc_Texture_Deluxemap          = qglGetUniformLocation(p->program, "Texture_Deluxemap");
1191                 p->loc_Texture_Attenuation        = qglGetUniformLocation(p->program, "Texture_Attenuation");
1192                 p->loc_Texture_Cube               = qglGetUniformLocation(p->program, "Texture_Cube");
1193                 p->loc_Texture_Refraction         = qglGetUniformLocation(p->program, "Texture_Refraction");
1194                 p->loc_Texture_Reflection         = qglGetUniformLocation(p->program, "Texture_Reflection");
1195                 p->loc_Texture_ShadowMap2D        = qglGetUniformLocation(p->program, "Texture_ShadowMap2D");
1196                 p->loc_Texture_CubeProjection     = qglGetUniformLocation(p->program, "Texture_CubeProjection");
1197                 p->loc_Texture_ScreenNormalMap    = qglGetUniformLocation(p->program, "Texture_ScreenNormalMap");
1198                 p->loc_Texture_ScreenDiffuse      = qglGetUniformLocation(p->program, "Texture_ScreenDiffuse");
1199                 p->loc_Texture_ScreenSpecular     = qglGetUniformLocation(p->program, "Texture_ScreenSpecular");
1200                 p->loc_Texture_ReflectMask        = qglGetUniformLocation(p->program, "Texture_ReflectMask");
1201                 p->loc_Texture_ReflectCube        = qglGetUniformLocation(p->program, "Texture_ReflectCube");
1202                 p->loc_Texture_BounceGrid         = qglGetUniformLocation(p->program, "Texture_BounceGrid");
1203                 p->loc_Alpha                      = qglGetUniformLocation(p->program, "Alpha");
1204                 p->loc_BloomBlur_Parameters       = qglGetUniformLocation(p->program, "BloomBlur_Parameters");
1205                 p->loc_ClientTime                 = qglGetUniformLocation(p->program, "ClientTime");
1206                 p->loc_Color_Ambient              = qglGetUniformLocation(p->program, "Color_Ambient");
1207                 p->loc_Color_Diffuse              = qglGetUniformLocation(p->program, "Color_Diffuse");
1208                 p->loc_Color_Specular             = qglGetUniformLocation(p->program, "Color_Specular");
1209                 p->loc_Color_Glow                 = qglGetUniformLocation(p->program, "Color_Glow");
1210                 p->loc_Color_Pants                = qglGetUniformLocation(p->program, "Color_Pants");
1211                 p->loc_Color_Shirt                = qglGetUniformLocation(p->program, "Color_Shirt");
1212                 p->loc_DeferredColor_Ambient      = qglGetUniformLocation(p->program, "DeferredColor_Ambient");
1213                 p->loc_DeferredColor_Diffuse      = qglGetUniformLocation(p->program, "DeferredColor_Diffuse");
1214                 p->loc_DeferredColor_Specular     = qglGetUniformLocation(p->program, "DeferredColor_Specular");
1215                 p->loc_DeferredMod_Diffuse        = qglGetUniformLocation(p->program, "DeferredMod_Diffuse");
1216                 p->loc_DeferredMod_Specular       = qglGetUniformLocation(p->program, "DeferredMod_Specular");
1217                 p->loc_DistortScaleRefractReflect = qglGetUniformLocation(p->program, "DistortScaleRefractReflect");
1218                 p->loc_EyePosition                = qglGetUniformLocation(p->program, "EyePosition");
1219                 p->loc_FogColor                   = qglGetUniformLocation(p->program, "FogColor");
1220                 p->loc_FogHeightFade              = qglGetUniformLocation(p->program, "FogHeightFade");
1221                 p->loc_FogPlane                   = qglGetUniformLocation(p->program, "FogPlane");
1222                 p->loc_FogPlaneViewDist           = qglGetUniformLocation(p->program, "FogPlaneViewDist");
1223                 p->loc_FogRangeRecip              = qglGetUniformLocation(p->program, "FogRangeRecip");
1224                 p->loc_LightColor                 = qglGetUniformLocation(p->program, "LightColor");
1225                 p->loc_LightGridMatrix            = qglGetUniformLocation(p->program, "LightGridMatrix");
1226                 p->loc_LightGridNormalMatrix      = qglGetUniformLocation(p->program, "LightGridNormalMatrix");
1227                 p->loc_LightDir                   = qglGetUniformLocation(p->program, "LightDir");
1228                 p->loc_LightPosition              = qglGetUniformLocation(p->program, "LightPosition");
1229                 p->loc_OffsetMapping_ScaleSteps   = qglGetUniformLocation(p->program, "OffsetMapping_ScaleSteps");
1230                 p->loc_OffsetMapping_LodDistance  = qglGetUniformLocation(p->program, "OffsetMapping_LodDistance");
1231                 p->loc_OffsetMapping_Bias         = qglGetUniformLocation(p->program, "OffsetMapping_Bias");
1232                 p->loc_PixelSize                  = qglGetUniformLocation(p->program, "PixelSize");
1233                 p->loc_ReflectColor               = qglGetUniformLocation(p->program, "ReflectColor");
1234                 p->loc_ReflectFactor              = qglGetUniformLocation(p->program, "ReflectFactor");
1235                 p->loc_ReflectOffset              = qglGetUniformLocation(p->program, "ReflectOffset");
1236                 p->loc_RefractColor               = qglGetUniformLocation(p->program, "RefractColor");
1237                 p->loc_Saturation                 = qglGetUniformLocation(p->program, "Saturation");
1238                 p->loc_ScreenCenterRefractReflect = qglGetUniformLocation(p->program, "ScreenCenterRefractReflect");
1239                 p->loc_ScreenScaleRefractReflect  = qglGetUniformLocation(p->program, "ScreenScaleRefractReflect");
1240                 p->loc_ScreenToDepth              = qglGetUniformLocation(p->program, "ScreenToDepth");
1241                 p->loc_ShadowMap_Parameters       = qglGetUniformLocation(p->program, "ShadowMap_Parameters");
1242                 p->loc_ShadowMap_TextureScale     = qglGetUniformLocation(p->program, "ShadowMap_TextureScale");
1243                 p->loc_SpecularPower              = qglGetUniformLocation(p->program, "SpecularPower");
1244                 p->loc_UserVec1                   = qglGetUniformLocation(p->program, "UserVec1");
1245                 p->loc_UserVec2                   = qglGetUniformLocation(p->program, "UserVec2");
1246                 p->loc_UserVec3                   = qglGetUniformLocation(p->program, "UserVec3");
1247                 p->loc_UserVec4                   = qglGetUniformLocation(p->program, "UserVec4");
1248                 p->loc_ColorFringe                = qglGetUniformLocation(p->program, "ColorFringe");
1249                 p->loc_ViewTintColor              = qglGetUniformLocation(p->program, "ViewTintColor");
1250                 p->loc_ViewToLight                = qglGetUniformLocation(p->program, "ViewToLight");
1251                 p->loc_ModelToLight               = qglGetUniformLocation(p->program, "ModelToLight");
1252                 p->loc_TexMatrix                  = qglGetUniformLocation(p->program, "TexMatrix");
1253                 p->loc_BackgroundTexMatrix        = qglGetUniformLocation(p->program, "BackgroundTexMatrix");
1254                 p->loc_ModelViewMatrix            = qglGetUniformLocation(p->program, "ModelViewMatrix");
1255                 p->loc_ModelViewProjectionMatrix  = qglGetUniformLocation(p->program, "ModelViewProjectionMatrix");
1256                 p->loc_PixelToScreenTexCoord      = qglGetUniformLocation(p->program, "PixelToScreenTexCoord");
1257                 p->loc_ModelToReflectCube         = qglGetUniformLocation(p->program, "ModelToReflectCube");
1258                 p->loc_ShadowMapMatrix            = qglGetUniformLocation(p->program, "ShadowMapMatrix");
1259                 p->loc_BloomColorSubtract         = qglGetUniformLocation(p->program, "BloomColorSubtract");
1260                 p->loc_NormalmapScrollBlend       = qglGetUniformLocation(p->program, "NormalmapScrollBlend");
1261                 p->loc_BounceGridMatrix           = qglGetUniformLocation(p->program, "BounceGridMatrix");
1262                 p->loc_BounceGridIntensity        = qglGetUniformLocation(p->program, "BounceGridIntensity");
1263                 // initialize the samplers to refer to the texture units we use
1264                 p->tex_Texture_First = -1;
1265                 p->tex_Texture_Second = -1;
1266                 p->tex_Texture_GammaRamps = -1;
1267                 p->tex_Texture_Normal = -1;
1268                 p->tex_Texture_Color = -1;
1269                 p->tex_Texture_Gloss = -1;
1270                 p->tex_Texture_Glow = -1;
1271                 p->tex_Texture_SecondaryNormal = -1;
1272                 p->tex_Texture_SecondaryColor = -1;
1273                 p->tex_Texture_SecondaryGloss = -1;
1274                 p->tex_Texture_SecondaryGlow = -1;
1275                 p->tex_Texture_Pants = -1;
1276                 p->tex_Texture_Shirt = -1;
1277                 p->tex_Texture_FogHeightTexture = -1;
1278                 p->tex_Texture_FogMask = -1;
1279                 p->tex_Texture_LightGrid = -1;
1280                 p->tex_Texture_Lightmap = -1;
1281                 p->tex_Texture_Deluxemap = -1;
1282                 p->tex_Texture_Attenuation = -1;
1283                 p->tex_Texture_Cube = -1;
1284                 p->tex_Texture_Refraction = -1;
1285                 p->tex_Texture_Reflection = -1;
1286                 p->tex_Texture_ShadowMap2D = -1;
1287                 p->tex_Texture_CubeProjection = -1;
1288                 p->tex_Texture_ScreenNormalMap = -1;
1289                 p->tex_Texture_ScreenDiffuse = -1;
1290                 p->tex_Texture_ScreenSpecular = -1;
1291                 p->tex_Texture_ReflectMask = -1;
1292                 p->tex_Texture_ReflectCube = -1;
1293                 p->tex_Texture_BounceGrid = -1;
1294                 // bind the texture samplers in use
1295                 sampler = 0;
1296                 if (p->loc_Texture_First           >= 0) {p->tex_Texture_First            = sampler;qglUniform1i(p->loc_Texture_First           , sampler);sampler++;}
1297                 if (p->loc_Texture_Second          >= 0) {p->tex_Texture_Second           = sampler;qglUniform1i(p->loc_Texture_Second          , sampler);sampler++;}
1298                 if (p->loc_Texture_GammaRamps      >= 0) {p->tex_Texture_GammaRamps       = sampler;qglUniform1i(p->loc_Texture_GammaRamps      , sampler);sampler++;}
1299                 if (p->loc_Texture_Normal          >= 0) {p->tex_Texture_Normal           = sampler;qglUniform1i(p->loc_Texture_Normal          , sampler);sampler++;}
1300                 if (p->loc_Texture_Color           >= 0) {p->tex_Texture_Color            = sampler;qglUniform1i(p->loc_Texture_Color           , sampler);sampler++;}
1301                 if (p->loc_Texture_Gloss           >= 0) {p->tex_Texture_Gloss            = sampler;qglUniform1i(p->loc_Texture_Gloss           , sampler);sampler++;}
1302                 if (p->loc_Texture_Glow            >= 0) {p->tex_Texture_Glow             = sampler;qglUniform1i(p->loc_Texture_Glow            , sampler);sampler++;}
1303                 if (p->loc_Texture_SecondaryNormal >= 0) {p->tex_Texture_SecondaryNormal  = sampler;qglUniform1i(p->loc_Texture_SecondaryNormal , sampler);sampler++;}
1304                 if (p->loc_Texture_SecondaryColor  >= 0) {p->tex_Texture_SecondaryColor   = sampler;qglUniform1i(p->loc_Texture_SecondaryColor  , sampler);sampler++;}
1305                 if (p->loc_Texture_SecondaryGloss  >= 0) {p->tex_Texture_SecondaryGloss   = sampler;qglUniform1i(p->loc_Texture_SecondaryGloss  , sampler);sampler++;}
1306                 if (p->loc_Texture_SecondaryGlow   >= 0) {p->tex_Texture_SecondaryGlow    = sampler;qglUniform1i(p->loc_Texture_SecondaryGlow   , sampler);sampler++;}
1307                 if (p->loc_Texture_Pants           >= 0) {p->tex_Texture_Pants            = sampler;qglUniform1i(p->loc_Texture_Pants           , sampler);sampler++;}
1308                 if (p->loc_Texture_Shirt           >= 0) {p->tex_Texture_Shirt            = sampler;qglUniform1i(p->loc_Texture_Shirt           , sampler);sampler++;}
1309                 if (p->loc_Texture_FogHeightTexture>= 0) {p->tex_Texture_FogHeightTexture = sampler;qglUniform1i(p->loc_Texture_FogHeightTexture, sampler);sampler++;}
1310                 if (p->loc_Texture_FogMask         >= 0) {p->tex_Texture_FogMask          = sampler;qglUniform1i(p->loc_Texture_FogMask         , sampler);sampler++;}
1311                 if (p->loc_Texture_LightGrid       >= 0) {p->tex_Texture_LightGrid        = sampler;qglUniform1i(p->loc_Texture_LightGrid       , sampler);sampler++;}
1312                 if (p->loc_Texture_Lightmap        >= 0) {p->tex_Texture_Lightmap         = sampler;qglUniform1i(p->loc_Texture_Lightmap        , sampler);sampler++;}
1313                 if (p->loc_Texture_Deluxemap       >= 0) {p->tex_Texture_Deluxemap        = sampler;qglUniform1i(p->loc_Texture_Deluxemap       , sampler);sampler++;}
1314                 if (p->loc_Texture_Attenuation     >= 0) {p->tex_Texture_Attenuation      = sampler;qglUniform1i(p->loc_Texture_Attenuation     , sampler);sampler++;}
1315                 if (p->loc_Texture_Cube            >= 0) {p->tex_Texture_Cube             = sampler;qglUniform1i(p->loc_Texture_Cube            , sampler);sampler++;}
1316                 if (p->loc_Texture_Refraction      >= 0) {p->tex_Texture_Refraction       = sampler;qglUniform1i(p->loc_Texture_Refraction      , sampler);sampler++;}
1317                 if (p->loc_Texture_Reflection      >= 0) {p->tex_Texture_Reflection       = sampler;qglUniform1i(p->loc_Texture_Reflection      , sampler);sampler++;}
1318                 if (p->loc_Texture_ShadowMap2D     >= 0) {p->tex_Texture_ShadowMap2D      = sampler;qglUniform1i(p->loc_Texture_ShadowMap2D     , sampler);sampler++;}
1319                 if (p->loc_Texture_CubeProjection  >= 0) {p->tex_Texture_CubeProjection   = sampler;qglUniform1i(p->loc_Texture_CubeProjection  , sampler);sampler++;}
1320                 if (p->loc_Texture_ScreenNormalMap >= 0) {p->tex_Texture_ScreenNormalMap  = sampler;qglUniform1i(p->loc_Texture_ScreenNormalMap , sampler);sampler++;}
1321                 if (p->loc_Texture_ScreenDiffuse   >= 0) {p->tex_Texture_ScreenDiffuse    = sampler;qglUniform1i(p->loc_Texture_ScreenDiffuse   , sampler);sampler++;}
1322                 if (p->loc_Texture_ScreenSpecular  >= 0) {p->tex_Texture_ScreenSpecular   = sampler;qglUniform1i(p->loc_Texture_ScreenSpecular  , sampler);sampler++;}
1323                 if (p->loc_Texture_ReflectMask     >= 0) {p->tex_Texture_ReflectMask      = sampler;qglUniform1i(p->loc_Texture_ReflectMask     , sampler);sampler++;}
1324                 if (p->loc_Texture_ReflectCube     >= 0) {p->tex_Texture_ReflectCube      = sampler;qglUniform1i(p->loc_Texture_ReflectCube     , sampler);sampler++;}
1325                 if (p->loc_Texture_BounceGrid      >= 0) {p->tex_Texture_BounceGrid       = sampler;qglUniform1i(p->loc_Texture_BounceGrid      , sampler);sampler++;}
1326                 // get the uniform block indices so we can bind them
1327                 p->ubiloc_Skeletal_Transform12_UniformBlock = -1;
1328 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1329                 p->ubiloc_Skeletal_Transform12_UniformBlock = qglGetUniformBlockIndex(p->program, "Skeletal_Transform12_UniformBlock");
1330 #endif
1331                 // clear the uniform block bindings
1332                 p->ubibind_Skeletal_Transform12_UniformBlock = -1;
1333                 // bind the uniform blocks in use
1334                 ubibind = 0;
1335 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1336                 if (p->ubiloc_Skeletal_Transform12_UniformBlock >= 0) {p->ubibind_Skeletal_Transform12_UniformBlock = ubibind;qglUniformBlockBinding(p->program, p->ubiloc_Skeletal_Transform12_UniformBlock, ubibind);ubibind++;}
1337 #endif
1338                 // we're done compiling and setting up the shader, at least until it is used
1339                 CHECKGLERROR
1340                 Con_DPrintf("^5GLSL shader %s compiled (%i textures).\n", permutationname, sampler);
1341         }
1342         else
1343                 Con_Printf("^1GLSL shader %s failed!  some features may not work properly.\n", permutationname);
1344
1345         // free the strings
1346         if (sourcestring)
1347                 Mem_Free(sourcestring);
1348 }
1349
1350 static void R_SetupShader_SetPermutationGLSL(unsigned int mode, uint64_t permutation)
1351 {
1352         r_glsl_permutation_t *perm = R_GLSL_FindPermutation(mode, permutation);
1353         if (r_glsl_permutation != perm)
1354         {
1355                 r_glsl_permutation = perm;
1356                 if (!r_glsl_permutation->program)
1357                 {
1358                         if (!r_glsl_permutation->compiled)
1359                         {
1360                                 Con_DPrintf("Compiling shader mode %u permutation %" PRIx64 "\n", mode, permutation);
1361                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1362                         }
1363                         if (!r_glsl_permutation->program)
1364                         {
1365                                 // remove features until we find a valid permutation
1366                                 int i;
1367                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1368                                 {
1369                                         // reduce i more quickly whenever it would not remove any bits
1370                                         uint64_t j = 1ll<<(SHADERPERMUTATION_COUNT-1-i);
1371                                         if (!(permutation & j))
1372                                                 continue;
1373                                         permutation -= j;
1374                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1375                                         if (!r_glsl_permutation->compiled)
1376                                                 R_GLSL_CompilePermutation(perm, mode, permutation);
1377                                         if (r_glsl_permutation->program)
1378                                                 break;
1379                                 }
1380                                 if (i >= SHADERPERMUTATION_COUNT)
1381                                 {
1382                                         //Con_Printf("Could not find a working OpenGL 2.0 shader for permutation %s %s\n", shadermodeinfo[mode].filename, shadermodeinfo[mode].pretext);
1383                                         r_glsl_permutation = R_GLSL_FindPermutation(mode, permutation);
1384                                         qglUseProgram(0);CHECKGLERROR
1385                                         return; // no bit left to clear, entire mode is broken
1386                                 }
1387                         }
1388                 }
1389                 CHECKGLERROR
1390                 qglUseProgram(r_glsl_permutation->program);CHECKGLERROR
1391         }
1392         if (r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
1393         if (r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
1394         if (r_glsl_permutation->loc_ClientTime >= 0) qglUniform1f(r_glsl_permutation->loc_ClientTime, cl.time);
1395         CHECKGLERROR
1396 }
1397
1398 void R_GLSL_Restart_f(cmd_state_t *cmd)
1399 {
1400         unsigned int i, limit;
1401         switch(vid.renderpath)
1402         {
1403         case RENDERPATH_GL32:
1404         case RENDERPATH_GLES2:
1405                 {
1406                         r_glsl_permutation_t *p;
1407                         r_glsl_permutation = NULL;
1408                         limit = (unsigned int)Mem_ExpandableArray_IndexRange(&r_glsl_permutationarray);
1409                         for (i = 0;i < limit;i++)
1410                         {
1411                                 if ((p = (r_glsl_permutation_t*)Mem_ExpandableArray_RecordAtIndex(&r_glsl_permutationarray, i)))
1412                                 {
1413                                         GL_Backend_FreeProgram(p->program);
1414                                         Mem_ExpandableArray_FreeRecord(&r_glsl_permutationarray, (void*)p);
1415                                 }
1416                         }
1417                         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
1418                 }
1419                 break;
1420         }
1421 }
1422
1423 static void R_GLSL_DumpShader_f(cmd_state_t *cmd)
1424 {
1425         int i, language, mode, dupe;
1426         char *text;
1427         shadermodeinfo_t *modeinfo;
1428         qfile_t *file;
1429
1430         for (language = 0;language < SHADERLANGUAGE_COUNT;language++)
1431         {
1432                 modeinfo = shadermodeinfo[language];
1433                 for (mode = 0;mode < SHADERMODE_COUNT;mode++)
1434                 {
1435                         // don't dump the same file multiple times (most or all shaders come from the same file)
1436                         for (dupe = mode - 1;dupe >= 0;dupe--)
1437                                 if (!strcmp(modeinfo[mode].filename, modeinfo[dupe].filename))
1438                                         break;
1439                         if (dupe >= 0)
1440                                 continue;
1441                         text = modeinfo[mode].builtinstring;
1442                         if (!text)
1443                                 continue;
1444                         file = FS_OpenRealFile(modeinfo[mode].filename, "w", false);
1445                         if (file)
1446                         {
1447                                 FS_Print(file, "/* The engine may define the following macros:\n");
1448                                 FS_Print(file, "#define VERTEX_SHADER\n#define GEOMETRY_SHADER\n#define FRAGMENT_SHADER\n");
1449                                 for (i = 0;i < SHADERMODE_COUNT;i++)
1450                                         FS_Print(file, modeinfo[i].pretext);
1451                                 for (i = 0;i < SHADERPERMUTATION_COUNT;i++)
1452                                         FS_Print(file, shaderpermutationinfo[i].pretext);
1453                                 FS_Print(file, "*/\n");
1454                                 FS_Print(file, text);
1455                                 FS_Close(file);
1456                                 Con_Printf("%s written\n", modeinfo[mode].filename);
1457                         }
1458                         else
1459                                 Con_Printf(CON_ERROR "failed to write to %s\n", modeinfo[mode].filename);
1460                 }
1461         }
1462 }
1463
1464 void R_SetupShader_Generic(rtexture_t *t, qbool usegamma, qbool notrippy, qbool suppresstexalpha)
1465 {
1466         uint64_t permutation = 0;
1467         if (r_trippy.integer && !notrippy)
1468                 permutation |= SHADERPERMUTATION_TRIPPY;
1469         permutation |= SHADERPERMUTATION_VIEWTINT;
1470         if (t)
1471                 permutation |= SHADERPERMUTATION_DIFFUSE;
1472         if (usegamma && v_glslgamma_2d.integer && !vid.sRGB2D && r_texture_gammaramps && !vid_gammatables_trivial)
1473                 permutation |= SHADERPERMUTATION_GAMMARAMPS;
1474         if (suppresstexalpha)
1475                 permutation |= SHADERPERMUTATION_REFLECTCUBE;
1476         if (vid.allowalphatocoverage)
1477                 GL_AlphaToCoverage(false);
1478         switch (vid.renderpath)
1479         {
1480         case RENDERPATH_GL32:
1481         case RENDERPATH_GLES2:
1482                 R_SetupShader_SetPermutationGLSL(SHADERMODE_GENERIC, permutation);
1483                 if (r_glsl_permutation->tex_Texture_First >= 0)
1484                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First, t);
1485                 if (r_glsl_permutation->tex_Texture_GammaRamps >= 0)
1486                         R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps);
1487                 break;
1488         }
1489 }
1490
1491 void R_SetupShader_Generic_NoTexture(qbool usegamma, qbool notrippy)
1492 {
1493         R_SetupShader_Generic(NULL, usegamma, notrippy, false);
1494 }
1495
1496 void R_SetupShader_DepthOrShadow(qbool notrippy, qbool depthrgb, qbool skeletal)
1497 {
1498         uint64_t permutation = 0;
1499         if (r_trippy.integer && !notrippy)
1500                 permutation |= SHADERPERMUTATION_TRIPPY;
1501         if (depthrgb)
1502                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1503         if (skeletal)
1504                 permutation |= SHADERPERMUTATION_SKELETAL;
1505
1506         if (vid.allowalphatocoverage)
1507                 GL_AlphaToCoverage(false);
1508         switch (vid.renderpath)
1509         {
1510         case RENDERPATH_GL32:
1511         case RENDERPATH_GLES2:
1512                 R_SetupShader_SetPermutationGLSL(SHADERMODE_DEPTH_OR_SHADOW, permutation);
1513 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1514                 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);
1515 #endif
1516                 break;
1517         }
1518 }
1519
1520 #define BLENDFUNC_ALLOWS_COLORMOD      1
1521 #define BLENDFUNC_ALLOWS_FOG           2
1522 #define BLENDFUNC_ALLOWS_FOG_HACK0     4
1523 #define BLENDFUNC_ALLOWS_FOG_HACKALPHA 8
1524 #define BLENDFUNC_ALLOWS_ANYFOG        (BLENDFUNC_ALLOWS_FOG | BLENDFUNC_ALLOWS_FOG_HACK0 | BLENDFUNC_ALLOWS_FOG_HACKALPHA)
1525 static int R_BlendFuncFlags(int src, int dst)
1526 {
1527         int r = 0;
1528
1529         // a blendfunc allows colormod if:
1530         // a) it can never keep the destination pixel invariant, or
1531         // b) it can keep the destination pixel invariant, and still can do so if colormodded
1532         // this is to prevent unintended side effects from colormod
1533
1534         // a blendfunc allows fog if:
1535         // blend(fog(src), fog(dst)) == fog(blend(src, dst))
1536         // this is to prevent unintended side effects from fog
1537
1538         // these checks are the output of fogeval.pl
1539
1540         r |= BLENDFUNC_ALLOWS_COLORMOD;
1541         if(src == GL_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1542         if(src == GL_DST_ALPHA && dst == GL_ONE_MINUS_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1543         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1544         if(src == GL_DST_COLOR && dst == GL_ONE_MINUS_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1545         if(src == GL_DST_COLOR && dst == GL_SRC_ALPHA) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1546         if(src == GL_DST_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1547         if(src == GL_DST_COLOR && dst == GL_ZERO) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1548         if(src == GL_ONE && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1549         if(src == GL_ONE && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG_HACKALPHA;
1550         if(src == GL_ONE && dst == GL_ZERO) r |= BLENDFUNC_ALLOWS_FOG;
1551         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_DST_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1552         if(src == GL_ONE_MINUS_DST_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1553         if(src == GL_ONE_MINUS_DST_COLOR && dst == GL_SRC_COLOR) r |= BLENDFUNC_ALLOWS_FOG;
1554         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1555         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1556         if(src == GL_ONE_MINUS_SRC_ALPHA && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1557         if(src == GL_ONE_MINUS_SRC_COLOR && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1558         if(src == GL_SRC_ALPHA && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG_HACK0;
1559         if(src == GL_SRC_ALPHA && dst == GL_ONE_MINUS_SRC_ALPHA) r |= BLENDFUNC_ALLOWS_FOG;
1560         if(src == GL_ZERO && dst == GL_ONE) r |= BLENDFUNC_ALLOWS_FOG;
1561         if(src == GL_ZERO && dst == GL_SRC_COLOR) r &= ~BLENDFUNC_ALLOWS_COLORMOD;
1562
1563         return r;
1564 }
1565
1566 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, qbool notrippy, qbool ui)
1567 {
1568         // select a permutation of the lighting shader appropriate to this
1569         // combination of texture, entity, light source, and fogging, only use the
1570         // minimum features necessary to avoid wasting rendering time in the
1571         // fragment shader on features that are not being used
1572         uint64_t permutation = 0;
1573         unsigned int mode = 0;
1574         int blendfuncflags;
1575         texture_t *t = rsurface.texture;
1576         float m16f[16];
1577         matrix4x4_t tempmatrix;
1578         r_waterstate_waterplane_t *waterplane = (r_waterstate_waterplane_t *)surfacewaterplane;
1579         if (r_trippy.integer && !notrippy)
1580                 permutation |= SHADERPERMUTATION_TRIPPY;
1581         if (t->currentmaterialflags & MATERIALFLAG_ALPHATEST)
1582                 permutation |= SHADERPERMUTATION_ALPHAKILL;
1583         if (t->currentmaterialflags & MATERIALFLAG_OCCLUDE)
1584                 permutation |= SHADERPERMUTATION_OCCLUDE;
1585         if (t->r_water_waterscroll[0] && t->r_water_waterscroll[1])
1586                 permutation |= SHADERPERMUTATION_NORMALMAPSCROLLBLEND; // todo: make generic
1587         if (rsurfacepass == RSURFPASS_BACKGROUND)
1588         {
1589                 // distorted background
1590                 if (t->currentmaterialflags & MATERIALFLAG_WATERSHADER)
1591                 {
1592                         mode = SHADERMODE_WATER;
1593                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1594                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1595                         if((r_wateralpha.value < 1) && (t->currentmaterialflags & MATERIALFLAG_WATERALPHA))
1596                         {
1597                                 // this is the right thing to do for wateralpha
1598                                 GL_BlendFunc(GL_ONE, GL_ZERO);
1599                                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1600                         }
1601                         else
1602                         {
1603                                 // this is the right thing to do for entity alpha
1604                                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1605                                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1606                         }
1607                 }
1608                 else if (t->currentmaterialflags & MATERIALFLAG_REFRACTION)
1609                 {
1610                         mode = SHADERMODE_REFRACTION;
1611                         if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1612                                 permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1613                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1614                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1615                 }
1616                 else
1617                 {
1618                         mode = SHADERMODE_GENERIC;
1619                         permutation |= SHADERPERMUTATION_DIFFUSE | SHADERPERMUTATION_ALPHAKILL;
1620                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1621                         blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1622                 }
1623                 if (vid.allowalphatocoverage)
1624                         GL_AlphaToCoverage(false);
1625         }
1626         else if (rsurfacepass == RSURFPASS_DEFERREDGEOMETRY)
1627         {
1628                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1629                 {
1630                         switch(t->offsetmapping)
1631                         {
1632                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1633                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1634                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1635                         case OFFSETMAPPING_OFF: break;
1636                         }
1637                 }
1638                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1639                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1640                 // normalmap (deferred prepass), may use alpha test on diffuse
1641                 mode = SHADERMODE_DEFERREDGEOMETRY;
1642                 GL_BlendFunc(GL_ONE, GL_ZERO);
1643                 blendfuncflags = R_BlendFuncFlags(GL_ONE, GL_ZERO);
1644                 if (vid.allowalphatocoverage)
1645                         GL_AlphaToCoverage(false);
1646         }
1647         else if (rsurfacepass == RSURFPASS_RTLIGHT)
1648         {
1649                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1650                 {
1651                         switch(t->offsetmapping)
1652                         {
1653                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1654                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1655                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1656                         case OFFSETMAPPING_OFF: break;
1657                         }
1658                 }
1659                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1660                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1661                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1662                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1663                 // light source
1664                 mode = SHADERMODE_LIGHTSOURCE;
1665                 if (rsurface.rtlight->currentcubemap != r_texture_whitecube)
1666                         permutation |= SHADERPERMUTATION_CUBEFILTER;
1667                 if (VectorLength2(rtlightdiffuse) > 0)
1668                         permutation |= SHADERPERMUTATION_DIFFUSE;
1669                 if (VectorLength2(rtlightspecular) > 0)
1670                         permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1671                 if (r_refdef.fogenabled)
1672                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1673                 if (t->colormapping)
1674                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1675                 if (r_shadow_usingshadowmap2d)
1676                 {
1677                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1678                         if(r_shadow_shadowmapvsdct)
1679                                 permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
1680
1681                         if (r_shadow_shadowmap2ddepthbuffer)
1682                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1683                 }
1684                 if (t->reflectmasktexture)
1685                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1686                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
1687                 blendfuncflags = R_BlendFuncFlags(GL_SRC_ALPHA, GL_ONE);
1688                 if (vid.allowalphatocoverage)
1689                         GL_AlphaToCoverage(false);
1690         }
1691         else if (t->currentmaterialflags & MATERIALFLAG_LIGHTGRID)
1692         {
1693                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1694                 {
1695                         switch(t->offsetmapping)
1696                         {
1697                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1698                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1699                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1700                         case OFFSETMAPPING_OFF: break;
1701                         }
1702                 }
1703                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1704                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1705                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1706                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1707                 // directional model lighting
1708                 mode = SHADERMODE_LIGHTGRID;
1709                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1710                         permutation |= SHADERPERMUTATION_GLOW;
1711                 permutation |= SHADERPERMUTATION_DIFFUSE;
1712                 if (t->glosstexture || t->backgroundglosstexture)
1713                         permutation |= SHADERPERMUTATION_SPECULAR;
1714                 if (r_refdef.fogenabled)
1715                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1716                 if (t->colormapping)
1717                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1718                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1719                 {
1720                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1721                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1722
1723                         if (r_shadow_shadowmap2ddepthbuffer)
1724                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1725                 }
1726                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1727                         permutation |= SHADERPERMUTATION_REFLECTION;
1728                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1729                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1730                 if (t->reflectmasktexture)
1731                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1732                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1733                 {
1734                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1735                         if (r_shadow_bouncegrid_state.directional)
1736                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1737                 }
1738                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1739                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1740                 // when using alphatocoverage, we don't need alphakill
1741                 if (vid.allowalphatocoverage)
1742                 {
1743                         if (r_transparent_alphatocoverage.integer)
1744                         {
1745                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1746                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1747                         }
1748                         else
1749                                 GL_AlphaToCoverage(false);
1750                 }
1751         }
1752         else if (t->currentmaterialflags & MATERIALFLAG_MODELLIGHT)
1753         {
1754                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1755                 {
1756                         switch(t->offsetmapping)
1757                         {
1758                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1759                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1760                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1761                         case OFFSETMAPPING_OFF: break;
1762                         }
1763                 }
1764                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1765                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1766                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1767                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1768                 // directional model lighting
1769                 mode = SHADERMODE_LIGHTDIRECTION;
1770                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1771                         permutation |= SHADERPERMUTATION_GLOW;
1772                 if (VectorLength2(t->render_modellight_diffuse))
1773                         permutation |= SHADERPERMUTATION_DIFFUSE;
1774                 if (VectorLength2(t->render_modellight_specular) > 0)
1775                         permutation |= SHADERPERMUTATION_SPECULAR;
1776                 if (r_refdef.fogenabled)
1777                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1778                 if (t->colormapping)
1779                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1780                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1781                 {
1782                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1783                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1784
1785                         if (r_shadow_shadowmap2ddepthbuffer)
1786                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1787                 }
1788                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1789                         permutation |= SHADERPERMUTATION_REFLECTION;
1790                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1791                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1792                 if (t->reflectmasktexture)
1793                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1794                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1795                 {
1796                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1797                         if (r_shadow_bouncegrid_state.directional)
1798                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1799                 }
1800                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1801                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1802                 // when using alphatocoverage, we don't need alphakill
1803                 if (vid.allowalphatocoverage)
1804                 {
1805                         if (r_transparent_alphatocoverage.integer)
1806                         {
1807                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1808                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1809                         }
1810                         else
1811                                 GL_AlphaToCoverage(false);
1812                 }
1813         }
1814         else
1815         {
1816                 if (r_glsl_offsetmapping.integer && ((R_TextureFlags(t->nmaptexture) & TEXF_ALPHA) || t->offsetbias != 0.0f))
1817                 {
1818                         switch(t->offsetmapping)
1819                         {
1820                         case OFFSETMAPPING_LINEAR: permutation |= SHADERPERMUTATION_OFFSETMAPPING;break;
1821                         case OFFSETMAPPING_RELIEF: permutation |= SHADERPERMUTATION_OFFSETMAPPING | SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1822                         case OFFSETMAPPING_DEFAULT: permutation |= SHADERPERMUTATION_OFFSETMAPPING;if (r_glsl_offsetmapping_reliefmapping.integer) permutation |= SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING;break;
1823                         case OFFSETMAPPING_OFF: break;
1824                         }
1825                 }
1826                 if (t->currentmaterialflags & MATERIALFLAG_VERTEXTEXTUREBLEND)
1827                         permutation |= SHADERPERMUTATION_VERTEXTEXTUREBLEND;
1828                 if (t->currentmaterialflags & MATERIALFLAG_ALPHAGEN_VERTEX)
1829                         permutation |= SHADERPERMUTATION_ALPHAGEN_VERTEX;
1830                 // lightmapped wall
1831                 if ((t->glowtexture || t->backgroundglowtexture) && r_hdr_glowintensity.value > 0 && !gl_lightmaps.integer)
1832                         permutation |= SHADERPERMUTATION_GLOW;
1833                 if (r_refdef.fogenabled && !ui)
1834                         permutation |= r_texture_fogheighttexture ? SHADERPERMUTATION_FOGHEIGHTTEXTURE : (r_refdef.fogplaneviewabove ? SHADERPERMUTATION_FOGOUTSIDE : SHADERPERMUTATION_FOGINSIDE);
1835                 if (t->colormapping)
1836                         permutation |= SHADERPERMUTATION_COLORMAPPING;
1837                 if (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW))
1838                 {
1839                         permutation |= SHADERPERMUTATION_SHADOWMAPORTHO;
1840                         permutation |= SHADERPERMUTATION_SHADOWMAP2D;
1841
1842                         if (r_shadow_shadowmap2ddepthbuffer)
1843                                 permutation |= SHADERPERMUTATION_DEPTHRGB;
1844                 }
1845                 if (t->currentmaterialflags & MATERIALFLAG_REFLECTION)
1846                         permutation |= SHADERPERMUTATION_REFLECTION;
1847                 if (r_shadow_usingdeferredprepass && !(t->currentmaterialflags & MATERIALFLAG_BLENDED))
1848                         permutation |= SHADERPERMUTATION_DEFERREDLIGHTMAP;
1849                 if (t->reflectmasktexture)
1850                         permutation |= SHADERPERMUTATION_REFLECTCUBE;
1851                 if (r_glsl_deluxemapping.integer >= 1 && rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping)
1852                 {
1853                         // deluxemapping (light direction texture)
1854                         if (rsurface.uselightmaptexture && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brushq3.deluxemapping && r_refdef.scene.worldmodel->brushq3.deluxemapping_modelspace)
1855                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_MODELSPACE;
1856                         else
1857                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_TANGENTSPACE;
1858                         permutation |= SHADERPERMUTATION_DIFFUSE;
1859                         if (VectorLength2(t->render_lightmap_specular) > 0)
1860                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1861                 }
1862                 else if (r_glsl_deluxemapping.integer >= 2)
1863                 {
1864                         // fake deluxemapping (uniform light direction in tangentspace)
1865                         if (rsurface.uselightmaptexture)
1866                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_LIGHTMAP;
1867                         else
1868                                 mode = SHADERMODE_LIGHTDIRECTIONMAP_FORCED_VERTEXCOLOR;
1869                         permutation |= SHADERPERMUTATION_DIFFUSE;
1870                         if (VectorLength2(t->render_lightmap_specular) > 0)
1871                                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
1872                 }
1873                 else if (rsurface.uselightmaptexture)
1874                 {
1875                         // ordinary lightmapping (q1bsp, q3bsp)
1876                         mode = SHADERMODE_LIGHTMAP;
1877                 }
1878                 else
1879                 {
1880                         // ordinary vertex coloring (q3bsp)
1881                         mode = SHADERMODE_VERTEXCOLOR;
1882                 }
1883                 if (r_shadow_bouncegrid_state.texture && cl.csqc_vidvars.drawworld && !notrippy)
1884                 {
1885                         permutation |= SHADERPERMUTATION_BOUNCEGRID;
1886                         if (r_shadow_bouncegrid_state.directional)
1887                                 permutation |= SHADERPERMUTATION_BOUNCEGRIDDIRECTIONAL;
1888                 }
1889                 GL_BlendFunc(t->currentblendfunc[0], t->currentblendfunc[1]);
1890                 blendfuncflags = R_BlendFuncFlags(t->currentblendfunc[0], t->currentblendfunc[1]);
1891                 // when using alphatocoverage, we don't need alphakill
1892                 if (vid.allowalphatocoverage)
1893                 {
1894                         if (r_transparent_alphatocoverage.integer)
1895                         {
1896                                 GL_AlphaToCoverage((t->currentmaterialflags & MATERIALFLAG_ALPHATEST) != 0);
1897                                 permutation &= ~SHADERPERMUTATION_ALPHAKILL;
1898                         }
1899                         else
1900                                 GL_AlphaToCoverage(false);
1901                 }
1902         }
1903         if(!(blendfuncflags & BLENDFUNC_ALLOWS_ANYFOG))
1904                 permutation &= ~(SHADERPERMUTATION_FOGHEIGHTTEXTURE | SHADERPERMUTATION_FOGOUTSIDE | SHADERPERMUTATION_FOGINSIDE);
1905         if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACKALPHA && !ui)
1906                 permutation |= SHADERPERMUTATION_FOGALPHAHACK;
1907         switch(vid.renderpath)
1908         {
1909         case RENDERPATH_GL32:
1910         case RENDERPATH_GLES2:
1911                 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);
1912                 RSurf_UploadBuffersForBatch();
1913                 // this has to be after RSurf_PrepareVerticesForBatch
1914                 if (rsurface.batchskeletaltransform3x4buffer)
1915                         permutation |= SHADERPERMUTATION_SKELETAL;
1916                 R_SetupShader_SetPermutationGLSL(mode, permutation);
1917 #ifndef USE_GLES2 /* FIXME: GLES3 only */
1918                 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);
1919 #endif
1920                 if (r_glsl_permutation->loc_ModelToReflectCube >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.matrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToReflectCube, 1, false, m16f);}
1921                 if (mode == SHADERMODE_LIGHTSOURCE)
1922                 {
1923                         if (r_glsl_permutation->loc_ModelToLight >= 0) {Matrix4x4_ToArrayFloatGL(&rsurface.entitytolight, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ModelToLight, 1, false, m16f);}
1924                         if (r_glsl_permutation->loc_LightPosition >= 0) qglUniform3f(r_glsl_permutation->loc_LightPosition, rsurface.entitylightorigin[0], rsurface.entitylightorigin[1], rsurface.entitylightorigin[2]);
1925                         if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1926                         if (r_glsl_permutation->loc_Color_Ambient >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Ambient, rtlightambient[0], rtlightambient[1], rtlightambient[2]);
1927                         if (r_glsl_permutation->loc_Color_Diffuse >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Diffuse, rtlightdiffuse[0], rtlightdiffuse[1], rtlightdiffuse[2]);
1928                         if (r_glsl_permutation->loc_Color_Specular >= 0) qglUniform3f(r_glsl_permutation->loc_Color_Specular, rtlightspecular[0], rtlightspecular[1], rtlightspecular[2]);
1929         
1930                         // additive passes are only darkened by fog, not tinted
1931                         if (r_glsl_permutation->loc_FogColor >= 0)
1932                                 qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1933                         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);
1934                 }
1935                 else
1936                 {
1937                         if (mode == SHADERMODE_FLATCOLOR)
1938                         {
1939                                 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]);
1940                         }
1941                         else if (mode == SHADERMODE_LIGHTGRID)
1942                         {
1943                                 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]);
1944                                 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]);
1945                                 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]);
1946                                 // other LightGrid uniforms handled below
1947                         }
1948                         else if (mode == SHADERMODE_LIGHTDIRECTION)
1949                         {
1950                                 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]);
1951                                 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]);
1952                                 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]);
1953                                 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]);
1954                                 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]);
1955                                 if (r_glsl_permutation->loc_LightColor >= 0) qglUniform3f(r_glsl_permutation->loc_LightColor, 1, 1, 1); // DEPRECATED
1956                                 if (r_glsl_permutation->loc_LightDir >= 0) qglUniform3f(r_glsl_permutation->loc_LightDir, t->render_modellight_lightdir_local[0], t->render_modellight_lightdir_local[1], t->render_modellight_lightdir_local[2]);
1957                         }
1958                         else
1959                         {
1960                                 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]);
1961                                 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]);
1962                                 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]);
1963                                 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]);
1964                                 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]);
1965                         }
1966                         // additive passes are only darkened by fog, not tinted
1967                         if (r_glsl_permutation->loc_FogColor >= 0 && !ui)
1968                         {
1969                                 if(blendfuncflags & BLENDFUNC_ALLOWS_FOG_HACK0)
1970                                         qglUniform3f(r_glsl_permutation->loc_FogColor, 0, 0, 0);
1971                                 else
1972                                         qglUniform3f(r_glsl_permutation->loc_FogColor, r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2]);
1973                         }
1974                         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);
1975                         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]);
1976                         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]);
1977                         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);
1978                         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);
1979                         if (r_glsl_permutation->loc_ReflectFactor >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectFactor, t->reflectmax - t->reflectmin);
1980                         if (r_glsl_permutation->loc_ReflectOffset >= 0) qglUniform1f(r_glsl_permutation->loc_ReflectOffset, t->reflectmin);
1981                         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);
1982                         if (r_glsl_permutation->loc_NormalmapScrollBlend >= 0) qglUniform2f(r_glsl_permutation->loc_NormalmapScrollBlend, t->r_water_waterscroll[0], t->r_water_waterscroll[1]);
1983                 }
1984                 if (r_glsl_permutation->loc_TexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currenttexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_TexMatrix, 1, false, m16f);}
1985                 if (r_glsl_permutation->loc_BackgroundTexMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&t->currentbackgroundtexmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_BackgroundTexMatrix, 1, false, m16f);}
1986                 if (r_glsl_permutation->loc_ShadowMapMatrix >= 0) {Matrix4x4_ToArrayFloatGL(&r_shadow_shadowmapmatrix, m16f);qglUniformMatrix4fv(r_glsl_permutation->loc_ShadowMapMatrix, 1, false, m16f);}
1987                 if (permutation & SHADERPERMUTATION_SHADOWMAPORTHO)
1988                 {
1989                         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]);
1990                         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]);
1991                 }
1992                 else
1993                 {
1994                         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]);
1995                         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]);
1996                 }
1997
1998                 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]);
1999                 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));
2000                 if (r_glsl_permutation->loc_EyePosition >= 0) qglUniform3f(r_glsl_permutation->loc_EyePosition, rsurface.localvieworigin[0], rsurface.localvieworigin[1], rsurface.localvieworigin[2]);
2001                 if (r_glsl_permutation->loc_Color_Pants >= 0)
2002                 {
2003                         if (t->pantstexture)
2004                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, t->render_colormap_pants[0], t->render_colormap_pants[1], t->render_colormap_pants[2]);
2005                         else
2006                                 qglUniform3f(r_glsl_permutation->loc_Color_Pants, 0, 0, 0);
2007                 }
2008                 if (r_glsl_permutation->loc_Color_Shirt >= 0)
2009                 {
2010                         if (t->shirttexture)
2011                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, t->render_colormap_shirt[0], t->render_colormap_shirt[1], t->render_colormap_shirt[2]);
2012                         else
2013                                 qglUniform3f(r_glsl_permutation->loc_Color_Shirt, 0, 0, 0);
2014                 }
2015                 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]);
2016                 if (r_glsl_permutation->loc_FogPlaneViewDist >= 0) qglUniform1f(r_glsl_permutation->loc_FogPlaneViewDist, rsurface.fogplaneviewdist);
2017                 if (r_glsl_permutation->loc_FogRangeRecip >= 0) qglUniform1f(r_glsl_permutation->loc_FogRangeRecip, rsurface.fograngerecip);
2018                 if (r_glsl_permutation->loc_FogHeightFade >= 0) qglUniform1f(r_glsl_permutation->loc_FogHeightFade, rsurface.fogheightfade);
2019                 if (r_glsl_permutation->loc_OffsetMapping_ScaleSteps >= 0) qglUniform4f(r_glsl_permutation->loc_OffsetMapping_ScaleSteps,
2020                                 r_glsl_offsetmapping_scale.value*t->offsetscale,
2021                                 max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2022                                 1.0 / max(1, (permutation & SHADERPERMUTATION_OFFSETMAPPING_RELIEFMAPPING) ? r_glsl_offsetmapping_reliefmapping_steps.integer : r_glsl_offsetmapping_steps.integer),
2023                                 max(1, r_glsl_offsetmapping_reliefmapping_refinesteps.integer)
2024                         );
2025                 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);
2026                 if (r_glsl_permutation->loc_OffsetMapping_Bias >= 0) qglUniform1f(r_glsl_permutation->loc_OffsetMapping_Bias, t->offsetbias);
2027                 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]);
2028                 if (r_glsl_permutation->loc_PixelToScreenTexCoord >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
2029                 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);}
2030                 if (r_glsl_permutation->loc_BounceGridIntensity >= 0) qglUniform1f(r_glsl_permutation->loc_BounceGridIntensity, r_shadow_bouncegrid_state.intensity*r_refdef.view.colorscale);
2031                 if (r_glsl_permutation->loc_LightGridMatrix >= 0 && r_refdef.scene.worldmodel)
2032                 {
2033                         float m9f[9];
2034                         Matrix4x4_Concat(&tempmatrix, &r_refdef.scene.worldmodel->brushq3.lightgridworldtotexturematrix, &rsurface.matrix);
2035                         Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);
2036                         qglUniformMatrix4fv(r_glsl_permutation->loc_LightGridMatrix, 1, false, m16f);
2037                         Matrix4x4_Normalize3(&tempmatrix, &rsurface.matrix);
2038                         Matrix4x4_ToArrayFloatGL(&tempmatrix, m16f);
2039                         m9f[0] = m16f[0];m9f[1] = m16f[1];m9f[2] = m16f[2];
2040                         m9f[3] = m16f[4];m9f[4] = m16f[5];m9f[5] = m16f[6];
2041                         m9f[6] = m16f[8];m9f[7] = m16f[9];m9f[8] = m16f[10];
2042                         qglUniformMatrix3fv(r_glsl_permutation->loc_LightGridNormalMatrix, 1, false, m9f);
2043                 }
2044
2045                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First            , r_texture_white                                     );
2046                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second           , r_texture_white                                     );
2047                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps       , r_texture_gammaramps                                );
2048                 if (r_glsl_permutation->tex_Texture_Normal          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Normal           , t->nmaptexture                       );
2049                 if (r_glsl_permutation->tex_Texture_Color           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Color            , t->basetexture                       );
2050                 if (r_glsl_permutation->tex_Texture_Gloss           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Gloss            , t->glosstexture                      );
2051                 if (r_glsl_permutation->tex_Texture_Glow            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Glow             , t->glowtexture                       );
2052                 if (r_glsl_permutation->tex_Texture_SecondaryNormal >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryNormal  , t->backgroundnmaptexture             );
2053                 if (r_glsl_permutation->tex_Texture_SecondaryColor  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryColor   , t->backgroundbasetexture             );
2054                 if (r_glsl_permutation->tex_Texture_SecondaryGloss  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGloss   , t->backgroundglosstexture            );
2055                 if (r_glsl_permutation->tex_Texture_SecondaryGlow   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_SecondaryGlow    , t->backgroundglowtexture             );
2056                 if (r_glsl_permutation->tex_Texture_Pants           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Pants            , t->pantstexture                      );
2057                 if (r_glsl_permutation->tex_Texture_Shirt           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Shirt            , t->shirttexture                      );
2058                 if (r_glsl_permutation->tex_Texture_ReflectMask     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectMask      , t->reflectmasktexture                );
2059                 if (r_glsl_permutation->tex_Texture_ReflectCube     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ReflectCube      , t->reflectcubetexture ? t->reflectcubetexture : r_texture_whitecube);
2060                 if (r_glsl_permutation->tex_Texture_FogHeightTexture>= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogHeightTexture , r_texture_fogheighttexture                          );
2061                 if (r_glsl_permutation->tex_Texture_FogMask         >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_FogMask          , r_texture_fogattenuation                            );
2062                 if (r_glsl_permutation->tex_Texture_Lightmap        >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Lightmap         , rsurface.lightmaptexture ? rsurface.lightmaptexture : r_texture_white);
2063                 if (r_glsl_permutation->tex_Texture_Deluxemap       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Deluxemap        , rsurface.deluxemaptexture ? rsurface.deluxemaptexture : r_texture_blanknormalmap);
2064                 if (r_glsl_permutation->tex_Texture_Attenuation     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation      , r_shadow_attenuationgradienttexture                 );
2065                 if (rsurfacepass == RSURFPASS_BACKGROUND)
2066                 {
2067                         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);
2068                         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);
2069                         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);
2070                 }
2071                 else
2072                 {
2073                         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);
2074                 }
2075                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap   , r_shadow_prepassgeometrynormalmaptexture            );
2076                 if (r_glsl_permutation->tex_Texture_ScreenDiffuse   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenDiffuse     , r_shadow_prepasslightingdiffusetexture              );
2077                 if (r_glsl_permutation->tex_Texture_ScreenSpecular  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenSpecular    , r_shadow_prepasslightingspeculartexture             );
2078                 if (rsurface.rtlight || (r_shadow_usingshadowmaportho && !(rsurface.ent_flags & RENDER_NOSELFSHADOW)))
2079                 {
2080                         if (r_glsl_permutation->tex_Texture_ShadowMap2D     >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D, r_shadow_shadowmap2ddepthtexture                           );
2081                         if (rsurface.rtlight)
2082                         {
2083                                 if (r_glsl_permutation->tex_Texture_Cube            >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube              , rsurface.rtlight->currentcubemap                    );
2084                                 if (r_glsl_permutation->tex_Texture_CubeProjection  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection    , r_shadow_shadowmapvsdcttexture                      );
2085                         }
2086                 }
2087                 if (r_glsl_permutation->tex_Texture_BounceGrid  >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_BounceGrid, r_shadow_bouncegrid_state.texture);
2088                 if (r_glsl_permutation->tex_Texture_LightGrid   >= 0 && r_refdef.scene.worldmodel) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_LightGrid, r_refdef.scene.worldmodel->brushq3.lightgridtexture);
2089                 CHECKGLERROR
2090                 break;
2091         }
2092 }
2093
2094 void R_SetupShader_DeferredLight(const rtlight_t *rtlight)
2095 {
2096         // select a permutation of the lighting shader appropriate to this
2097         // combination of texture, entity, light source, and fogging, only use the
2098         // minimum features necessary to avoid wasting rendering time in the
2099         // fragment shader on features that are not being used
2100         uint64_t permutation = 0;
2101         unsigned int mode = 0;
2102         const float *lightcolorbase = rtlight->currentcolor;
2103         float ambientscale = rtlight->ambientscale;
2104         float diffusescale = rtlight->diffusescale;
2105         float specularscale = rtlight->specularscale;
2106         // this is the location of the light in view space
2107         vec3_t viewlightorigin;
2108         // this transforms from view space (camera) to light space (cubemap)
2109         matrix4x4_t viewtolight;
2110         matrix4x4_t lighttoview;
2111         float viewtolight16f[16];
2112         // light source
2113         mode = SHADERMODE_DEFERREDLIGHTSOURCE;
2114         if (rtlight->currentcubemap != r_texture_whitecube)
2115                 permutation |= SHADERPERMUTATION_CUBEFILTER;
2116         if (diffusescale > 0)
2117                 permutation |= SHADERPERMUTATION_DIFFUSE;
2118         if (specularscale > 0 && r_shadow_gloss.integer > 0)
2119                 permutation |= SHADERPERMUTATION_SPECULAR | SHADERPERMUTATION_DIFFUSE;
2120         if (r_shadow_usingshadowmap2d)
2121         {
2122                 permutation |= SHADERPERMUTATION_SHADOWMAP2D;
2123                 if (r_shadow_shadowmapvsdct)
2124                         permutation |= SHADERPERMUTATION_SHADOWMAPVSDCT;
2125
2126                 if (r_shadow_shadowmap2ddepthbuffer)
2127                         permutation |= SHADERPERMUTATION_DEPTHRGB;
2128         }
2129         if (vid.allowalphatocoverage)
2130                 GL_AlphaToCoverage(false);
2131         Matrix4x4_Transform(&r_refdef.view.viewport.viewmatrix, rtlight->shadoworigin, viewlightorigin);
2132         Matrix4x4_Concat(&lighttoview, &r_refdef.view.viewport.viewmatrix, &rtlight->matrix_lighttoworld);
2133         Matrix4x4_Invert_Full(&viewtolight, &lighttoview);
2134         Matrix4x4_ToArrayFloatGL(&viewtolight, viewtolight16f);
2135         switch(vid.renderpath)
2136         {
2137         case RENDERPATH_GL32:
2138         case RENDERPATH_GLES2:
2139                 R_SetupShader_SetPermutationGLSL(mode, permutation);
2140                 if (r_glsl_permutation->loc_LightPosition             >= 0) qglUniform3f(       r_glsl_permutation->loc_LightPosition            , viewlightorigin[0], viewlightorigin[1], viewlightorigin[2]);
2141                 if (r_glsl_permutation->loc_ViewToLight               >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ViewToLight              , 1, false, viewtolight16f);
2142                 if (r_glsl_permutation->loc_DeferredColor_Ambient     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Ambient    , lightcolorbase[0] * ambientscale , lightcolorbase[1] * ambientscale , lightcolorbase[2] * ambientscale );
2143                 if (r_glsl_permutation->loc_DeferredColor_Diffuse     >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Diffuse    , lightcolorbase[0] * diffusescale , lightcolorbase[1] * diffusescale , lightcolorbase[2] * diffusescale );
2144                 if (r_glsl_permutation->loc_DeferredColor_Specular    >= 0) qglUniform3f(       r_glsl_permutation->loc_DeferredColor_Specular   , lightcolorbase[0] * specularscale, lightcolorbase[1] * specularscale, lightcolorbase[2] * specularscale);
2145                 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]);
2146                 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]);
2147                 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);
2148                 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]);
2149                 if (r_glsl_permutation->loc_PixelToScreenTexCoord     >= 0) qglUniform2f(       r_glsl_permutation->loc_PixelToScreenTexCoord    , 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
2150
2151                 if (r_glsl_permutation->tex_Texture_Attenuation       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Attenuation        , r_shadow_attenuationgradienttexture                 );
2152                 if (r_glsl_permutation->tex_Texture_ScreenNormalMap   >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ScreenNormalMap    , r_shadow_prepassgeometrynormalmaptexture            );
2153                 if (r_glsl_permutation->tex_Texture_Cube              >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Cube               , rsurface.rtlight->currentcubemap                    );
2154                 if (r_glsl_permutation->tex_Texture_ShadowMap2D       >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_ShadowMap2D        , r_shadow_shadowmap2ddepthtexture                    );
2155                 if (r_glsl_permutation->tex_Texture_CubeProjection    >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_CubeProjection     , r_shadow_shadowmapvsdcttexture                      );
2156                 break;
2157         }
2158 }
2159
2160 #define SKINFRAME_HASH 1024
2161
2162 typedef struct
2163 {
2164         unsigned int loadsequence; // incremented each level change
2165         memexpandablearray_t array;
2166         skinframe_t *hash[SKINFRAME_HASH];
2167 }
2168 r_skinframe_t;
2169 r_skinframe_t r_skinframe;
2170
2171 void R_SkinFrame_PrepareForPurge(void)
2172 {
2173         r_skinframe.loadsequence++;
2174         // wrap it without hitting zero
2175         if (r_skinframe.loadsequence >= 200)
2176                 r_skinframe.loadsequence = 1;
2177 }
2178
2179 void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
2180 {
2181         if (!skinframe)
2182                 return;
2183         // mark the skinframe as used for the purging code
2184         skinframe->loadsequence = r_skinframe.loadsequence;
2185 }
2186
2187 void R_SkinFrame_PurgeSkinFrame(skinframe_t *s)
2188 {
2189         if (s == NULL)
2190                 return;
2191         if (s->merged == s->base)
2192                 s->merged = NULL;
2193         R_PurgeTexture(s->stain); s->stain = NULL;
2194         R_PurgeTexture(s->merged); s->merged = NULL;
2195         R_PurgeTexture(s->base); s->base = NULL;
2196         R_PurgeTexture(s->pants); s->pants = NULL;
2197         R_PurgeTexture(s->shirt); s->shirt = NULL;
2198         R_PurgeTexture(s->nmap); s->nmap = NULL;
2199         R_PurgeTexture(s->gloss); s->gloss = NULL;
2200         R_PurgeTexture(s->glow); s->glow = NULL;
2201         R_PurgeTexture(s->fog); s->fog = NULL;
2202         R_PurgeTexture(s->reflect); s->reflect = NULL;
2203         s->loadsequence = 0;
2204 }
2205
2206 void R_SkinFrame_Purge(void)
2207 {
2208         int i;
2209         skinframe_t *s;
2210         for (i = 0;i < SKINFRAME_HASH;i++)
2211         {
2212                 for (s = r_skinframe.hash[i];s;s = s->next)
2213                 {
2214                         if (s->loadsequence && s->loadsequence != r_skinframe.loadsequence)
2215                                 R_SkinFrame_PurgeSkinFrame(s);
2216                 }
2217         }
2218 }
2219
2220 skinframe_t *R_SkinFrame_FindNextByName( skinframe_t *last, const char *name ) {
2221         skinframe_t *item;
2222         char basename[MAX_QPATH];
2223
2224         Image_StripImageExtension(name, basename, sizeof(basename));
2225
2226         if( last == NULL ) {
2227                 int hashindex;
2228                 hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2229                 item = r_skinframe.hash[hashindex];
2230         } else {
2231                 item = last->next;
2232         }
2233
2234         // linearly search through the hash bucket
2235         for( ; item ; item = item->next ) {
2236                 if( !strcmp( item->basename, basename ) ) {
2237                         return item;
2238                 }
2239         }
2240         return NULL;
2241 }
2242
2243 skinframe_t *R_SkinFrame_Find(const char *name, int textureflags, int comparewidth, int compareheight, int comparecrc, qbool add)
2244 {
2245         skinframe_t *item;
2246         int compareflags = textureflags & TEXF_IMPORTANTBITS;
2247         int hashindex;
2248         char basename[MAX_QPATH];
2249
2250         Image_StripImageExtension(name, basename, sizeof(basename));
2251
2252         hashindex = CRC_Block((unsigned char *)basename, strlen(basename)) & (SKINFRAME_HASH - 1);
2253         for (item = r_skinframe.hash[hashindex];item;item = item->next)
2254                 if (!strcmp(item->basename, basename) &&
2255                         item->textureflags == compareflags &&
2256                         item->comparewidth == comparewidth &&
2257                         item->compareheight == compareheight &&
2258                         item->comparecrc == comparecrc)
2259                         break;
2260
2261         if (!item)
2262         {
2263                 if (!add)
2264                         return NULL;
2265                 item = (skinframe_t *)Mem_ExpandableArray_AllocRecord(&r_skinframe.array);
2266                 memset(item, 0, sizeof(*item));
2267                 strlcpy(item->basename, basename, sizeof(item->basename));
2268                 item->textureflags = compareflags;
2269                 item->comparewidth = comparewidth;
2270                 item->compareheight = compareheight;
2271                 item->comparecrc = comparecrc;
2272                 item->next = r_skinframe.hash[hashindex];
2273                 r_skinframe.hash[hashindex] = item;
2274         }
2275         else if (textureflags & TEXF_FORCE_RELOAD)
2276                 R_SkinFrame_PurgeSkinFrame(item);
2277
2278         R_SkinFrame_MarkUsed(item);
2279         return item;
2280 }
2281
2282 #define R_SKINFRAME_LOAD_AVERAGE_COLORS(cnt, getpixel) \
2283         { \
2284                 unsigned long long avgcolor[5], wsum; \
2285                 int pix, comp, w; \
2286                 avgcolor[0] = 0; \
2287                 avgcolor[1] = 0; \
2288                 avgcolor[2] = 0; \
2289                 avgcolor[3] = 0; \
2290                 avgcolor[4] = 0; \
2291                 wsum = 0; \
2292                 for(pix = 0; pix < cnt; ++pix) \
2293                 { \
2294                         w = 0; \
2295                         for(comp = 0; comp < 3; ++comp) \
2296                                 w += getpixel; \
2297                         if(w) /* ignore perfectly black pixels because that is better for model skins */ \
2298                         { \
2299                                 ++wsum; \
2300                                 /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2301                                 w = getpixel; \
2302                                 for(comp = 0; comp < 3; ++comp) \
2303                                         avgcolor[comp] += getpixel * w; \
2304                                 avgcolor[3] += w; \
2305                         } \
2306                         /* comp = 3; -- not needed, comp is always 3 when we get here */ \
2307                         avgcolor[4] += getpixel; \
2308                 } \
2309                 if(avgcolor[3] == 0) /* no pixels seen? even worse */ \
2310                         avgcolor[3] = 1; \
2311                 skinframe->avgcolor[0] = avgcolor[2] / (255.0 * avgcolor[3]); \
2312                 skinframe->avgcolor[1] = avgcolor[1] / (255.0 * avgcolor[3]); \
2313                 skinframe->avgcolor[2] = avgcolor[0] / (255.0 * avgcolor[3]); \
2314                 skinframe->avgcolor[3] = avgcolor[4] / (255.0 * cnt); \
2315         }
2316
2317 skinframe_t *R_SkinFrame_LoadExternal(const char *name, int textureflags, qbool complain, qbool fallbacknotexture)
2318 {
2319         skinframe_t *skinframe;
2320
2321         if (cls.state == ca_dedicated)
2322                 return NULL;
2323
2324         // return an existing skinframe if already loaded
2325         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
2326         if (skinframe && skinframe->base)
2327                 return skinframe;
2328
2329         // if the skinframe doesn't exist this will create it
2330         return R_SkinFrame_LoadExternal_SkinFrame(skinframe, name, textureflags, complain, fallbacknotexture);
2331 }
2332
2333 extern cvar_t gl_picmip;
2334 skinframe_t *R_SkinFrame_LoadExternal_SkinFrame(skinframe_t *skinframe, const char *name, int textureflags, qbool complain, qbool fallbacknotexture)
2335 {
2336         int j;
2337         unsigned char *pixels;
2338         unsigned char *bumppixels;
2339         unsigned char *basepixels = NULL;
2340         int basepixels_width = 0;
2341         int basepixels_height = 0;
2342         rtexture_t *ddsbase = NULL;
2343         qbool ddshasalpha = false;
2344         float ddsavgcolor[4];
2345         char basename[MAX_QPATH];
2346         int miplevel = R_PicmipForFlags(textureflags);
2347         int savemiplevel = miplevel;
2348         int mymiplevel;
2349         char vabuf[1024];
2350
2351         if (cls.state == ca_dedicated)
2352                 return NULL;
2353
2354         Image_StripImageExtension(name, basename, sizeof(basename));
2355
2356         // check for DDS texture file first
2357         if (!r_loaddds || !(ddsbase = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s.dds", basename), vid.sRGB3D, textureflags, &ddshasalpha, ddsavgcolor, miplevel, false)))
2358         {
2359                 basepixels = loadimagepixelsbgra(name, complain, true, false, &miplevel);
2360                 if (basepixels == NULL && fallbacknotexture)
2361                         basepixels = Image_GenerateNoTexture();
2362                 if (basepixels == NULL)
2363                         return NULL;
2364         }
2365
2366         // FIXME handle miplevel
2367
2368         if (developer_loading.integer)
2369                 Con_Printf("loading skin \"%s\"\n", name);
2370
2371         // we've got some pixels to store, so really allocate this new texture now
2372         if (!skinframe)
2373                 skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, true);
2374         textureflags &= ~TEXF_FORCE_RELOAD;
2375         skinframe->stain = NULL;
2376         skinframe->merged = NULL;
2377         skinframe->base = NULL;
2378         skinframe->pants = NULL;
2379         skinframe->shirt = NULL;
2380         skinframe->nmap = NULL;
2381         skinframe->gloss = NULL;
2382         skinframe->glow = NULL;
2383         skinframe->fog = NULL;
2384         skinframe->reflect = NULL;
2385         skinframe->hasalpha = false;
2386         // we could store the q2animname here too
2387
2388         if (ddsbase)
2389         {
2390                 skinframe->base = ddsbase;
2391                 skinframe->hasalpha = ddshasalpha;
2392                 VectorCopy(ddsavgcolor, skinframe->avgcolor);
2393                 if (r_loadfog && skinframe->hasalpha)
2394                         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);
2395                 //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]);
2396         }
2397         else
2398         {
2399                 basepixels_width = image_width;
2400                 basepixels_height = image_height;
2401                 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);
2402                 if (textureflags & TEXF_ALPHA)
2403                 {
2404                         for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
2405                         {
2406                                 if (basepixels[j] < 255)
2407                                 {
2408                                         skinframe->hasalpha = true;
2409                                         break;
2410                                 }
2411                         }
2412                         if (r_loadfog && skinframe->hasalpha)
2413                         {
2414                                 // has transparent pixels
2415                                 pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2416                                 for (j = 0;j < image_width * image_height * 4;j += 4)
2417                                 {
2418                                         pixels[j+0] = 255;
2419                                         pixels[j+1] = 255;
2420                                         pixels[j+2] = 255;
2421                                         pixels[j+3] = basepixels[j+3];
2422                                 }
2423                                 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);
2424                                 Mem_Free(pixels);
2425                         }
2426                 }
2427                 R_SKINFRAME_LOAD_AVERAGE_COLORS(basepixels_width * basepixels_height, basepixels[4 * pix + comp]);
2428 #ifndef USE_GLES2
2429                 //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]);
2430                 if (r_savedds && skinframe->base)
2431                         R_SaveTextureDDSFile(skinframe->base, va(vabuf, sizeof(vabuf), "dds/%s.dds", skinframe->basename), r_texture_dds_save.integer < 2, skinframe->hasalpha);
2432                 if (r_savedds && skinframe->fog)
2433                         R_SaveTextureDDSFile(skinframe->fog, va(vabuf, sizeof(vabuf), "dds/%s_mask.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2434 #endif
2435         }
2436
2437         if (r_loaddds)
2438         {
2439                 mymiplevel = savemiplevel;
2440                 if (r_loadnormalmap)
2441                         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);
2442                 skinframe->glow = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2443                 if (r_loadgloss)
2444                         skinframe->gloss = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2445                 skinframe->pants = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2446                 skinframe->shirt = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2447                 skinframe->reflect = R_LoadTextureDDSFile(r_main_texturepool, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), vid.sRGB3D, textureflags, NULL, NULL, mymiplevel, true);
2448         }
2449
2450         // _norm is the name used by tenebrae and has been adopted as standard
2451         if (r_loadnormalmap && skinframe->nmap == NULL)
2452         {
2453                 mymiplevel = savemiplevel;
2454                 if ((pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_norm", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2455                 {
2456                         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);
2457                         Mem_Free(pixels);
2458                         pixels = NULL;
2459                 }
2460                 else if (r_shadow_bumpscale_bumpmap.value > 0 && (bumppixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_bump", skinframe->basename), false, false, false, &mymiplevel)) != NULL)
2461                 {
2462                         pixels = (unsigned char *)Mem_Alloc(tempmempool, image_width * image_height * 4);
2463                         Image_HeightmapToNormalmap_BGRA(bumppixels, pixels, image_width, image_height, false, r_shadow_bumpscale_bumpmap.value);
2464                         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);
2465                         Mem_Free(pixels);
2466                         Mem_Free(bumppixels);
2467                 }
2468                 else if (r_shadow_bumpscale_basetexture.value > 0)
2469                 {
2470                         pixels = (unsigned char *)Mem_Alloc(tempmempool, basepixels_width * basepixels_height * 4);
2471                         Image_HeightmapToNormalmap_BGRA(basepixels, pixels, basepixels_width, basepixels_height, false, r_shadow_bumpscale_basetexture.value);
2472                         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);
2473                         Mem_Free(pixels);
2474                 }
2475 #ifndef USE_GLES2
2476                 if (r_savedds && skinframe->nmap)
2477                         R_SaveTextureDDSFile(skinframe->nmap, va(vabuf, sizeof(vabuf), "dds/%s_norm.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2478 #endif
2479         }
2480
2481         // _luma is supported only for tenebrae compatibility
2482         // _blend and .blend are supported only for Q3 & QL compatibility, this hack can be removed if better Q3 shader support is implemented
2483         // _glow is the preferred name
2484         mymiplevel = savemiplevel;
2485         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.blend", skinframe->basename), false, false, false, &mymiplevel)) || (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_blend", skinframe->basename), false, false, false, &mymiplevel)) || (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_luma", skinframe->basename), false, false, false, &mymiplevel))))
2486         {
2487                 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);
2488 #ifndef USE_GLES2
2489                 if (r_savedds && skinframe->glow)
2490                         R_SaveTextureDDSFile(skinframe->glow, va(vabuf, sizeof(vabuf), "dds/%s_glow.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2491 #endif
2492                 Mem_Free(pixels);pixels = NULL;
2493         }
2494
2495         mymiplevel = savemiplevel;
2496         if (skinframe->gloss == NULL && r_loadgloss && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_gloss", skinframe->basename), false, false, false, &mymiplevel)))
2497         {
2498                 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);
2499 #ifndef USE_GLES2
2500                 if (r_savedds && skinframe->gloss)
2501                         R_SaveTextureDDSFile(skinframe->gloss, va(vabuf, sizeof(vabuf), "dds/%s_gloss.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2502 #endif
2503                 Mem_Free(pixels);
2504                 pixels = NULL;
2505         }
2506
2507         mymiplevel = savemiplevel;
2508         if (skinframe->pants == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_pants", skinframe->basename), false, false, false, &mymiplevel)))
2509         {
2510                 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);
2511 #ifndef USE_GLES2
2512                 if (r_savedds && skinframe->pants)
2513                         R_SaveTextureDDSFile(skinframe->pants, va(vabuf, sizeof(vabuf), "dds/%s_pants.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2514 #endif
2515                 Mem_Free(pixels);
2516                 pixels = NULL;
2517         }
2518
2519         mymiplevel = savemiplevel;
2520         if (skinframe->shirt == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_shirt", skinframe->basename), false, false, false, &mymiplevel)))
2521         {
2522                 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);
2523 #ifndef USE_GLES2
2524                 if (r_savedds && skinframe->shirt)
2525                         R_SaveTextureDDSFile(skinframe->shirt, va(vabuf, sizeof(vabuf), "dds/%s_shirt.dds", skinframe->basename), r_texture_dds_save.integer < 2, false);
2526 #endif
2527                 Mem_Free(pixels);
2528                 pixels = NULL;
2529         }
2530
2531         mymiplevel = savemiplevel;
2532         if (skinframe->reflect == NULL && (pixels = loadimagepixelsbgra(va(vabuf, sizeof(vabuf), "%s_reflect", skinframe->basename), false, false, false, &mymiplevel)))
2533         {
2534                 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);
2535 #ifndef USE_GLES2
2536                 if (r_savedds && skinframe->reflect)
2537                         R_SaveTextureDDSFile(skinframe->reflect, va(vabuf, sizeof(vabuf), "dds/%s_reflect.dds", skinframe->basename), r_texture_dds_save.integer < 2, true);
2538 #endif
2539                 Mem_Free(pixels);
2540                 pixels = NULL;
2541         }
2542
2543         if (basepixels)
2544                 Mem_Free(basepixels);
2545
2546         return skinframe;
2547 }
2548
2549 skinframe_t *R_SkinFrame_LoadInternalBGRA(const char *name, int textureflags, const unsigned char *skindata, int width, int height, int comparewidth, int compareheight, int comparecrc, qbool sRGB)
2550 {
2551         int i;
2552         skinframe_t *skinframe;
2553         char vabuf[1024];
2554
2555         if (cls.state == ca_dedicated)
2556                 return NULL;
2557
2558         // if already loaded just return it, otherwise make a new skinframe
2559         skinframe = R_SkinFrame_Find(name, textureflags, comparewidth, compareheight, comparecrc, true);
2560         if (skinframe->base)
2561                 return skinframe;
2562         textureflags &= ~TEXF_FORCE_RELOAD;
2563
2564         skinframe->stain = NULL;
2565         skinframe->merged = NULL;
2566         skinframe->base = NULL;
2567         skinframe->pants = NULL;
2568         skinframe->shirt = NULL;
2569         skinframe->nmap = NULL;
2570         skinframe->gloss = NULL;
2571         skinframe->glow = NULL;
2572         skinframe->fog = NULL;
2573         skinframe->reflect = NULL;
2574         skinframe->hasalpha = false;
2575
2576         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2577         if (!skindata)
2578                 return NULL;
2579
2580         if (developer_loading.integer)
2581                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2582
2583         if (r_loadnormalmap && r_shadow_bumpscale_basetexture.value > 0)
2584         {
2585                 unsigned char *a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2586                 unsigned char *b = a + width * height * 4;
2587                 Image_HeightmapToNormalmap_BGRA(skindata, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2588                 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);
2589                 Mem_Free(a);
2590         }
2591         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, sRGB ? TEXTYPE_SRGB_BGRA : TEXTYPE_BGRA, textureflags, -1, NULL);
2592         if (textureflags & TEXF_ALPHA)
2593         {
2594                 for (i = 3;i < width * height * 4;i += 4)
2595                 {
2596                         if (skindata[i] < 255)
2597                         {
2598                                 skinframe->hasalpha = true;
2599                                 break;
2600                         }
2601                 }
2602                 if (r_loadfog && skinframe->hasalpha)
2603                 {
2604                         unsigned char *fogpixels = (unsigned char *)Mem_Alloc(tempmempool, width * height * 4);
2605                         memcpy(fogpixels, skindata, width * height * 4);
2606                         for (i = 0;i < width * height * 4;i += 4)
2607                                 fogpixels[i] = fogpixels[i+1] = fogpixels[i+2] = 255;
2608                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, fogpixels, TEXTYPE_BGRA, textureflags, -1, NULL);
2609                         Mem_Free(fogpixels);
2610                 }
2611         }
2612
2613         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, skindata[4 * pix + comp]);
2614         //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]);
2615
2616         return skinframe;
2617 }
2618
2619 skinframe_t *R_SkinFrame_LoadInternalQuake(const char *name, int textureflags, int loadpantsandshirt, int loadglowtexture, const unsigned char *skindata, int width, int height)
2620 {
2621         int i;
2622         int featuresmask;
2623         skinframe_t *skinframe;
2624
2625         if (cls.state == ca_dedicated)
2626                 return NULL;
2627
2628         // if already loaded just return it, otherwise make a new skinframe
2629         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2630         if (skinframe->base)
2631                 return skinframe;
2632         //textureflags &= ~TEXF_FORCE_RELOAD;
2633
2634         skinframe->stain = NULL;
2635         skinframe->merged = NULL;
2636         skinframe->base = NULL;
2637         skinframe->pants = NULL;
2638         skinframe->shirt = NULL;
2639         skinframe->nmap = NULL;
2640         skinframe->gloss = NULL;
2641         skinframe->glow = NULL;
2642         skinframe->fog = NULL;
2643         skinframe->reflect = NULL;
2644         skinframe->hasalpha = false;
2645
2646         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2647         if (!skindata)
2648                 return NULL;
2649
2650         if (developer_loading.integer)
2651                 Con_Printf("loading quake skin \"%s\"\n", name);
2652
2653         // 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)
2654         skinframe->qpixels = (unsigned char *)Mem_Alloc(r_main_mempool, width*height); // FIXME LEAK
2655         memcpy(skinframe->qpixels, skindata, width*height);
2656         skinframe->qwidth = width;
2657         skinframe->qheight = height;
2658
2659         featuresmask = 0;
2660         for (i = 0;i < width * height;i++)
2661                 featuresmask |= palette_featureflags[skindata[i]];
2662
2663         skinframe->hasalpha = false;
2664         // fence textures
2665         if (name[0] == '{')
2666                 skinframe->hasalpha = true;
2667         skinframe->qhascolormapping = loadpantsandshirt && (featuresmask & (PALETTEFEATURE_PANTS | PALETTEFEATURE_SHIRT));
2668         skinframe->qgeneratenmap = r_shadow_bumpscale_basetexture.value > 0;
2669         skinframe->qgeneratemerged = true;
2670         skinframe->qgeneratebase = skinframe->qhascolormapping;
2671         skinframe->qgenerateglow = loadglowtexture && (featuresmask & PALETTEFEATURE_GLOW);
2672
2673         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette_bgra_complete)[skindata[pix]*4 + comp]);
2674         //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]);
2675
2676         return skinframe;
2677 }
2678
2679 static void R_SkinFrame_GenerateTexturesFromQPixels(skinframe_t *skinframe, qbool colormapped)
2680 {
2681         int width;
2682         int height;
2683         unsigned char *skindata;
2684         char vabuf[1024];
2685
2686         if (!skinframe->qpixels)
2687                 return;
2688
2689         if (!skinframe->qhascolormapping)
2690                 colormapped = false;
2691
2692         if (colormapped)
2693         {
2694                 if (!skinframe->qgeneratebase)
2695                         return;
2696         }
2697         else
2698         {
2699                 if (!skinframe->qgeneratemerged)
2700                         return;
2701         }
2702
2703         width = skinframe->qwidth;
2704         height = skinframe->qheight;
2705         skindata = skinframe->qpixels;
2706
2707         if (skinframe->qgeneratenmap)
2708         {
2709                 unsigned char *a, *b;
2710                 skinframe->qgeneratenmap = false;
2711                 a = (unsigned char *)Mem_Alloc(tempmempool, width * height * 8);
2712                 b = a + width * height * 4;
2713                 // use either a custom palette or the quake palette
2714                 Image_Copy8bitBGRA(skindata, a, width * height, palette_bgra_complete);
2715                 Image_HeightmapToNormalmap_BGRA(a, b, width, height, false, r_shadow_bumpscale_basetexture.value);
2716                 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);
2717                 Mem_Free(a);
2718         }
2719
2720         if (skinframe->qgenerateglow)
2721         {
2722                 skinframe->qgenerateglow = false;
2723                 if (skinframe->hasalpha) // fence textures
2724                         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
2725                 else
2726                         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
2727         }
2728
2729         if (colormapped)
2730         {
2731                 skinframe->qgeneratebase = false;
2732                 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);
2733                 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);
2734                 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);
2735         }
2736         else
2737         {
2738                 skinframe->qgeneratemerged = false;
2739                 if (skinframe->hasalpha) // fence textures
2740                         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);
2741                 else
2742                         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);
2743         }
2744
2745         if (!skinframe->qgeneratemerged && !skinframe->qgeneratebase)
2746         {
2747                 Mem_Free(skinframe->qpixels);
2748                 skinframe->qpixels = NULL;
2749         }
2750 }
2751
2752 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)
2753 {
2754         int i;
2755         skinframe_t *skinframe;
2756         char vabuf[1024];
2757
2758         if (cls.state == ca_dedicated)
2759                 return NULL;
2760
2761         // if already loaded just return it, otherwise make a new skinframe
2762         skinframe = R_SkinFrame_Find(name, textureflags, width, height, skindata ? CRC_Block(skindata, width*height) : 0, true);
2763         if (skinframe->base)
2764                 return skinframe;
2765         textureflags &= ~TEXF_FORCE_RELOAD;
2766
2767         skinframe->stain = NULL;
2768         skinframe->merged = NULL;
2769         skinframe->base = NULL;
2770         skinframe->pants = NULL;
2771         skinframe->shirt = NULL;
2772         skinframe->nmap = NULL;
2773         skinframe->gloss = NULL;
2774         skinframe->glow = NULL;
2775         skinframe->fog = NULL;
2776         skinframe->reflect = NULL;
2777         skinframe->hasalpha = false;
2778
2779         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2780         if (!skindata)
2781                 return NULL;
2782
2783         if (developer_loading.integer)
2784                 Con_Printf("loading embedded 8bit image \"%s\"\n", name);
2785
2786         skinframe->base = skinframe->merged = R_LoadTexture2D(r_main_texturepool, skinframe->basename, width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, palette);
2787         if ((textureflags & TEXF_ALPHA) && alphapalette)
2788         {
2789                 for (i = 0;i < width * height;i++)
2790                 {
2791                         if (((unsigned char *)palette)[skindata[i]*4+3] < 255)
2792                         {
2793                                 skinframe->hasalpha = true;
2794                                 break;
2795                         }
2796                 }
2797                 if (r_loadfog && skinframe->hasalpha)
2798                         skinframe->fog = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "%s_fog", skinframe->basename), width, height, skindata, TEXTYPE_PALETTE, textureflags, -1, alphapalette);
2799         }
2800
2801         R_SKINFRAME_LOAD_AVERAGE_COLORS(width * height, ((unsigned char *)palette)[skindata[pix]*4 + comp]);
2802         //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]);
2803
2804         return skinframe;
2805 }
2806
2807 skinframe_t *R_SkinFrame_LoadMissing(void)
2808 {
2809         skinframe_t *skinframe;
2810
2811         if (cls.state == ca_dedicated)
2812                 return NULL;
2813
2814         skinframe = R_SkinFrame_Find("missing", TEXF_FORCENEAREST, 0, 0, 0, true);
2815         skinframe->stain = NULL;
2816         skinframe->merged = NULL;
2817         skinframe->base = NULL;
2818         skinframe->pants = NULL;
2819         skinframe->shirt = NULL;
2820         skinframe->nmap = NULL;
2821         skinframe->gloss = NULL;
2822         skinframe->glow = NULL;
2823         skinframe->fog = NULL;
2824         skinframe->reflect = NULL;
2825         skinframe->hasalpha = false;
2826
2827         skinframe->avgcolor[0] = rand() / RAND_MAX;
2828         skinframe->avgcolor[1] = rand() / RAND_MAX;
2829         skinframe->avgcolor[2] = rand() / RAND_MAX;
2830         skinframe->avgcolor[3] = 1;
2831
2832         return skinframe;
2833 }
2834
2835 skinframe_t *R_SkinFrame_LoadNoTexture(void)
2836 {
2837         if (cls.state == ca_dedicated)
2838                 return NULL;
2839
2840         return R_SkinFrame_LoadInternalBGRA("notexture", TEXF_FORCENEAREST, Image_GenerateNoTexture(), 16, 16, 0, 0, 0, false);
2841 }
2842
2843 skinframe_t *R_SkinFrame_LoadInternalUsingTexture(const char *name, int textureflags, rtexture_t *tex, int width, int height, qbool sRGB)
2844 {
2845         skinframe_t *skinframe;
2846         if (cls.state == ca_dedicated)
2847                 return NULL;
2848         // if already loaded just return it, otherwise make a new skinframe
2849         skinframe = R_SkinFrame_Find(name, textureflags, width, height, 0, true);
2850         if (skinframe->base)
2851                 return skinframe;
2852         textureflags &= ~TEXF_FORCE_RELOAD;
2853         skinframe->stain = NULL;
2854         skinframe->merged = NULL;
2855         skinframe->base = NULL;
2856         skinframe->pants = NULL;
2857         skinframe->shirt = NULL;
2858         skinframe->nmap = NULL;
2859         skinframe->gloss = NULL;
2860         skinframe->glow = NULL;
2861         skinframe->fog = NULL;
2862         skinframe->reflect = NULL;
2863         skinframe->hasalpha = (textureflags & TEXF_ALPHA) != 0;
2864         // if no data was provided, then clearly the caller wanted to get a blank skinframe
2865         if (!tex)
2866                 return NULL;
2867         if (developer_loading.integer)
2868                 Con_Printf("loading 32bit skin \"%s\"\n", name);
2869         skinframe->base = skinframe->merged = tex;
2870         Vector4Set(skinframe->avgcolor, 1, 1, 1, 1); // bogus placeholder
2871         return skinframe;
2872 }
2873
2874 //static char *suffix[6] = {"ft", "bk", "rt", "lf", "up", "dn"};
2875 typedef struct suffixinfo_s
2876 {
2877         const char *suffix;
2878         qbool flipx, flipy, flipdiagonal;
2879 }
2880 suffixinfo_t;
2881 static suffixinfo_t suffix[3][6] =
2882 {
2883         {
2884                 {"px",   false, false, false},
2885                 {"nx",   false, false, false},
2886                 {"py",   false, false, false},
2887                 {"ny",   false, false, false},
2888                 {"pz",   false, false, false},
2889                 {"nz",   false, false, false}
2890         },
2891         {
2892                 {"posx", false, false, false},
2893                 {"negx", false, false, false},
2894                 {"posy", false, false, false},
2895                 {"negy", false, false, false},
2896                 {"posz", false, false, false},
2897                 {"negz", false, false, false}
2898         },
2899         {
2900                 {"rt",    true, false,  true},
2901                 {"lf",   false,  true,  true},
2902                 {"ft",    true,  true, false},
2903                 {"bk",   false, false, false},
2904                 {"up",    true, false,  true},
2905                 {"dn",    true, false,  true}
2906         }
2907 };
2908
2909 static int componentorder[4] = {0, 1, 2, 3};
2910
2911 static rtexture_t *R_LoadCubemap(const char *basename)
2912 {
2913         int i, j, cubemapsize, forcefilter;
2914         unsigned char *cubemappixels, *image_buffer;
2915         rtexture_t *cubemaptexture;
2916         char name[256];
2917
2918         // HACK: if the cubemap name starts with a !, the cubemap is nearest-filtered
2919         forcefilter = TEXF_FORCELINEAR;
2920         if (basename && basename[0] == '!')
2921         {
2922                 basename++;
2923                 forcefilter = TEXF_FORCENEAREST;
2924         }
2925         // must start 0 so the first loadimagepixels has no requested width/height
2926         cubemapsize = 0;
2927         cubemappixels = NULL;
2928         cubemaptexture = NULL;
2929         // keep trying different suffix groups (posx, px, rt) until one loads
2930         for (j = 0;j < 3 && !cubemappixels;j++)
2931         {
2932                 // load the 6 images in the suffix group
2933                 for (i = 0;i < 6;i++)
2934                 {
2935                         // generate an image name based on the base and and suffix
2936                         dpsnprintf(name, sizeof(name), "%s%s", basename, suffix[j][i].suffix);
2937                         // load it
2938                         if ((image_buffer = loadimagepixelsbgra(name, false, false, false, NULL)))
2939                         {
2940                                 // an image loaded, make sure width and height are equal
2941                                 if (image_width == image_height && (!cubemappixels || image_width == cubemapsize))
2942                                 {
2943                                         // if this is the first image to load successfully, allocate the cubemap memory
2944                                         if (!cubemappixels && image_width >= 1)
2945                                         {
2946                                                 cubemapsize = image_width;
2947                                                 // note this clears to black, so unavailable sides are black
2948                                                 cubemappixels = (unsigned char *)Mem_Alloc(tempmempool, 6*cubemapsize*cubemapsize*4);
2949                                         }
2950                                         // copy the image with any flipping needed by the suffix (px and posx types don't need flipping)
2951                                         if (cubemappixels)
2952                                                 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);
2953                                 }
2954                                 else
2955                                         Con_Printf("Cubemap image \"%s\" (%ix%i) is not square, OpenGL requires square cubemaps.\n", name, image_width, image_height);
2956                                 // free the image
2957                                 Mem_Free(image_buffer);
2958                         }
2959                 }
2960         }
2961         // if a cubemap loaded, upload it
2962         if (cubemappixels)
2963         {
2964                 if (developer_loading.integer)
2965                         Con_Printf("loading cubemap \"%s\"\n", basename);
2966
2967                 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) | forcefilter | TEXF_CLAMP, -1, NULL);
2968                 Mem_Free(cubemappixels);
2969         }
2970         else
2971         {
2972                 Con_DPrintf("failed to load cubemap \"%s\"\n", basename);
2973                 if (developer_loading.integer)
2974                 {
2975                         Con_Printf("(tried tried images ");
2976                         for (j = 0;j < 3;j++)
2977                                 for (i = 0;i < 6;i++)
2978                                         Con_Printf("%s\"%s%s.tga\"", j + i > 0 ? ", " : "", basename, suffix[j][i].suffix);
2979                         Con_Print(" and was unable to find any of them).\n");
2980                 }
2981         }
2982         return cubemaptexture;
2983 }
2984
2985 rtexture_t *R_GetCubemap(const char *basename)
2986 {
2987         int i;
2988         for (i = 0;i < r_texture_numcubemaps;i++)
2989                 if (r_texture_cubemaps[i] != NULL)
2990                         if (!strcasecmp(r_texture_cubemaps[i]->basename, basename))
2991                                 return r_texture_cubemaps[i]->texture ? r_texture_cubemaps[i]->texture : r_texture_whitecube;
2992         if (i >= MAX_CUBEMAPS || !r_main_mempool)
2993                 return r_texture_whitecube;
2994         r_texture_numcubemaps++;
2995         r_texture_cubemaps[i] = (cubemapinfo_t *)Mem_Alloc(r_main_mempool, sizeof(cubemapinfo_t));
2996         strlcpy(r_texture_cubemaps[i]->basename, basename, sizeof(r_texture_cubemaps[i]->basename));
2997         r_texture_cubemaps[i]->texture = R_LoadCubemap(r_texture_cubemaps[i]->basename);
2998         return r_texture_cubemaps[i]->texture;
2999 }
3000
3001 static void R_Main_FreeViewCache(void)
3002 {
3003         if (r_refdef.viewcache.entityvisible)
3004                 Mem_Free(r_refdef.viewcache.entityvisible);
3005         if (r_refdef.viewcache.world_pvsbits)
3006                 Mem_Free(r_refdef.viewcache.world_pvsbits);
3007         if (r_refdef.viewcache.world_leafvisible)
3008                 Mem_Free(r_refdef.viewcache.world_leafvisible);
3009         if (r_refdef.viewcache.world_surfacevisible)
3010                 Mem_Free(r_refdef.viewcache.world_surfacevisible);
3011         memset(&r_refdef.viewcache, 0, sizeof(r_refdef.viewcache));
3012 }
3013
3014 static void R_Main_ResizeViewCache(void)
3015 {
3016         int numentities = r_refdef.scene.numentities;
3017         int numclusters = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusters : 1;
3018         int numclusterbytes = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_pvsclusterbytes : 1;
3019         int numleafs = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->brush.num_leafs : 1;
3020         int numsurfaces = r_refdef.scene.worldmodel ? r_refdef.scene.worldmodel->num_surfaces : 1;
3021         if (r_refdef.viewcache.maxentities < numentities)
3022         {
3023                 r_refdef.viewcache.maxentities = numentities;
3024                 if (r_refdef.viewcache.entityvisible)
3025                         Mem_Free(r_refdef.viewcache.entityvisible);
3026                 r_refdef.viewcache.entityvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.maxentities);
3027         }
3028         if (r_refdef.viewcache.world_numclusters != numclusters)
3029         {
3030                 r_refdef.viewcache.world_numclusters = numclusters;
3031                 r_refdef.viewcache.world_numclusterbytes = numclusterbytes;
3032                 if (r_refdef.viewcache.world_pvsbits)
3033                         Mem_Free(r_refdef.viewcache.world_pvsbits);
3034                 r_refdef.viewcache.world_pvsbits = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numclusterbytes);
3035         }
3036         if (r_refdef.viewcache.world_numleafs != numleafs)
3037         {
3038                 r_refdef.viewcache.world_numleafs = numleafs;
3039                 if (r_refdef.viewcache.world_leafvisible)
3040                         Mem_Free(r_refdef.viewcache.world_leafvisible);
3041                 r_refdef.viewcache.world_leafvisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numleafs);
3042         }
3043         if (r_refdef.viewcache.world_numsurfaces != numsurfaces)
3044         {
3045                 r_refdef.viewcache.world_numsurfaces = numsurfaces;
3046                 if (r_refdef.viewcache.world_surfacevisible)
3047                         Mem_Free(r_refdef.viewcache.world_surfacevisible);
3048                 r_refdef.viewcache.world_surfacevisible = (unsigned char *)Mem_Alloc(r_main_mempool, r_refdef.viewcache.world_numsurfaces);
3049         }
3050 }
3051
3052 extern rtexture_t *loadingscreentexture;
3053 static void gl_main_start(void)
3054 {
3055         loadingscreentexture = NULL;
3056         r_texture_blanknormalmap = NULL;
3057         r_texture_white = NULL;
3058         r_texture_grey128 = NULL;
3059         r_texture_black = NULL;
3060         r_texture_whitecube = NULL;
3061         r_texture_normalizationcube = NULL;
3062         r_texture_fogattenuation = NULL;
3063         r_texture_fogheighttexture = NULL;
3064         r_texture_gammaramps = NULL;
3065         r_texture_numcubemaps = 0;
3066         r_uniformbufferalignment = 32;
3067
3068         r_loaddds = r_texture_dds_load.integer != 0;
3069         r_savedds = vid.support.ext_texture_compression_s3tc && r_texture_dds_save.integer;
3070
3071         switch(vid.renderpath)
3072         {
3073         case RENDERPATH_GL32:
3074         case RENDERPATH_GLES2:
3075                 Cvar_SetValueQuick(&r_textureunits, MAX_TEXTUREUNITS);
3076                 Cvar_SetValueQuick(&gl_combine, 1);
3077                 Cvar_SetValueQuick(&r_glsl, 1);
3078                 r_loadnormalmap = true;
3079                 r_loadgloss = true;
3080                 r_loadfog = false;
3081 #ifdef GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT
3082                 qglGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &r_uniformbufferalignment);
3083 #endif
3084                 break;
3085         }
3086
3087         R_AnimCache_Free();
3088         R_FrameData_Reset();
3089         R_BufferData_Reset();
3090
3091         r_numqueries = 0;
3092         r_maxqueries = 0;
3093         memset(r_queries, 0, sizeof(r_queries));
3094
3095         r_qwskincache = NULL;
3096         r_qwskincache_size = 0;
3097
3098         // due to caching of texture_t references, the collision cache must be reset
3099         Collision_Cache_Reset(true);
3100
3101         // set up r_skinframe loading system for textures
3102         memset(&r_skinframe, 0, sizeof(r_skinframe));
3103         r_skinframe.loadsequence = 1;
3104         Mem_ExpandableArray_NewArray(&r_skinframe.array, r_main_mempool, sizeof(skinframe_t), 256);
3105
3106         r_main_texturepool = R_AllocTexturePool();
3107         R_BuildBlankTextures();
3108         R_BuildNoTexture();
3109         R_BuildWhiteCube();
3110 #ifndef USE_GLES2
3111         R_BuildNormalizationCube();
3112 #endif //USE_GLES2
3113         r_texture_fogattenuation = NULL;
3114         r_texture_fogheighttexture = NULL;
3115         r_texture_gammaramps = NULL;
3116         //r_texture_fogintensity = NULL;
3117         memset(&r_fb, 0, sizeof(r_fb));
3118         Mem_ExpandableArray_NewArray(&r_fb.rendertargets, r_main_mempool, sizeof(r_rendertarget_t), 128);
3119         r_glsl_permutation = NULL;
3120         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3121         Mem_ExpandableArray_NewArray(&r_glsl_permutationarray, r_main_mempool, sizeof(r_glsl_permutation_t), 256);
3122         memset(&r_svbsp, 0, sizeof (r_svbsp));
3123
3124         memset(r_texture_cubemaps, 0, sizeof(r_texture_cubemaps));
3125         r_texture_numcubemaps = 0;
3126
3127         r_refdef.fogmasktable_density = 0;
3128
3129 #ifdef __ANDROID__
3130         // For Steelstorm Android
3131         // FIXME CACHE the program and reload
3132         // FIXME see possible combinations for SS:BR android
3133         Con_DPrintf("Compiling most used shaders for SS:BR android... START\n");
3134         R_SetupShader_SetPermutationGLSL(0, 12);
3135         R_SetupShader_SetPermutationGLSL(0, 13);
3136         R_SetupShader_SetPermutationGLSL(0, 8388621);
3137         R_SetupShader_SetPermutationGLSL(3, 0);
3138         R_SetupShader_SetPermutationGLSL(3, 2048);
3139         R_SetupShader_SetPermutationGLSL(5, 0);
3140         R_SetupShader_SetPermutationGLSL(5, 2);
3141         R_SetupShader_SetPermutationGLSL(5, 2048);
3142         R_SetupShader_SetPermutationGLSL(5, 8388608);
3143         R_SetupShader_SetPermutationGLSL(11, 1);
3144         R_SetupShader_SetPermutationGLSL(11, 2049);
3145         R_SetupShader_SetPermutationGLSL(11, 8193);
3146         R_SetupShader_SetPermutationGLSL(11, 10241);
3147         Con_DPrintf("Compiling most used shaders for SS:BR android... END\n");
3148 #endif
3149 }
3150
3151 extern unsigned int r_shadow_occlusion_buf;
3152
3153 static void gl_main_shutdown(void)
3154 {
3155         R_RenderTarget_FreeUnused(true);
3156         Mem_ExpandableArray_FreeArray(&r_fb.rendertargets);
3157         R_AnimCache_Free();
3158         R_FrameData_Reset();
3159         R_BufferData_Reset();
3160
3161         R_Main_FreeViewCache();
3162
3163         switch(vid.renderpath)
3164         {
3165         case RENDERPATH_GL32:
3166         case RENDERPATH_GLES2:
3167 #if defined(GL_SAMPLES_PASSED) && !defined(USE_GLES2)
3168                 if (r_maxqueries)
3169                         qglDeleteQueries(r_maxqueries, r_queries);
3170 #endif
3171                 break;
3172         }
3173         r_shadow_occlusion_buf = 0;
3174         r_numqueries = 0;
3175         r_maxqueries = 0;
3176         memset(r_queries, 0, sizeof(r_queries));
3177
3178         r_qwskincache = NULL;
3179         r_qwskincache_size = 0;
3180
3181         // clear out the r_skinframe state
3182         Mem_ExpandableArray_FreeArray(&r_skinframe.array);
3183         memset(&r_skinframe, 0, sizeof(r_skinframe));
3184
3185         if (r_svbsp.nodes)
3186                 Mem_Free(r_svbsp.nodes);
3187         memset(&r_svbsp, 0, sizeof (r_svbsp));
3188         R_FreeTexturePool(&r_main_texturepool);
3189         loadingscreentexture = NULL;
3190         r_texture_blanknormalmap = NULL;
3191         r_texture_white = NULL;
3192         r_texture_grey128 = NULL;
3193         r_texture_black = NULL;
3194         r_texture_whitecube = NULL;
3195         r_texture_normalizationcube = NULL;
3196         r_texture_fogattenuation = NULL;
3197         r_texture_fogheighttexture = NULL;
3198         r_texture_gammaramps = NULL;
3199         r_texture_numcubemaps = 0;
3200         //r_texture_fogintensity = NULL;
3201         memset(&r_fb, 0, sizeof(r_fb));
3202         R_GLSL_Restart_f(cmd_local);
3203
3204         r_glsl_permutation = NULL;
3205         memset(r_glsl_permutationhash, 0, sizeof(r_glsl_permutationhash));
3206         Mem_ExpandableArray_FreeArray(&r_glsl_permutationarray);
3207 }
3208
3209 static void gl_main_newmap(void)
3210 {
3211         // FIXME: move this code to client
3212         char *entities, entname[MAX_QPATH];
3213         if (r_qwskincache)
3214                 Mem_Free(r_qwskincache);
3215         r_qwskincache = NULL;
3216         r_qwskincache_size = 0;
3217         if (cl.worldmodel)
3218         {
3219                 dpsnprintf(entname, sizeof(entname), "%s.ent", cl.worldnamenoextension);
3220                 if ((entities = (char *)FS_LoadFile(entname, tempmempool, true, NULL)))
3221                 {
3222                         CL_ParseEntityLump(entities);
3223                         Mem_Free(entities);
3224                         return;
3225                 }
3226                 if (cl.worldmodel->brush.entities)
3227                         CL_ParseEntityLump(cl.worldmodel->brush.entities);
3228         }
3229         R_Main_FreeViewCache();
3230
3231         R_FrameData_Reset();
3232         R_BufferData_Reset();
3233 }
3234
3235 void GL_Main_Init(void)
3236 {
3237         int i;
3238         r_main_mempool = Mem_AllocPool("Renderer", 0, NULL);
3239         R_InitShaderModeInfo();
3240
3241         Cmd_AddCommand(CF_CLIENT, "r_glsl_restart", R_GLSL_Restart_f, "unloads GLSL shaders, they will then be reloaded as needed");
3242         Cmd_AddCommand(CF_CLIENT, "r_glsl_dumpshader", R_GLSL_DumpShader_f, "dumps the engine internal default.glsl shader into glsl/default.glsl");
3243         // FIXME: the client should set up r_refdef.fog stuff including the fogmasktable
3244         if (gamemode == GAME_NEHAHRA)
3245         {
3246                 Cvar_RegisterVariable (&gl_fogenable);
3247                 Cvar_RegisterVariable (&gl_fogdensity);
3248                 Cvar_RegisterVariable (&gl_fogred);
3249                 Cvar_RegisterVariable (&gl_foggreen);
3250                 Cvar_RegisterVariable (&gl_fogblue);
3251                 Cvar_RegisterVariable (&gl_fogstart);
3252                 Cvar_RegisterVariable (&gl_fogend);
3253                 Cvar_RegisterVariable (&gl_skyclip);
3254         }
3255         Cvar_RegisterVariable(&r_motionblur);
3256         Cvar_RegisterVariable(&r_damageblur);
3257         Cvar_RegisterVariable(&r_motionblur_averaging);
3258         Cvar_RegisterVariable(&r_motionblur_randomize);
3259         Cvar_RegisterVariable(&r_motionblur_minblur);
3260         Cvar_RegisterVariable(&r_motionblur_maxblur);
3261         Cvar_RegisterVariable(&r_motionblur_velocityfactor);
3262         Cvar_RegisterVariable(&r_motionblur_velocityfactor_minspeed);
3263         Cvar_RegisterVariable(&r_motionblur_velocityfactor_maxspeed);
3264         Cvar_RegisterVariable(&r_motionblur_mousefactor);
3265         Cvar_RegisterVariable(&r_motionblur_mousefactor_minspeed);
3266         Cvar_RegisterVariable(&r_motionblur_mousefactor_maxspeed);
3267         Cvar_RegisterVariable(&r_depthfirst);
3268         Cvar_RegisterVariable(&r_useinfinitefarclip);
3269         Cvar_RegisterVariable(&r_farclip_base);
3270         Cvar_RegisterVariable(&r_farclip_world);
3271         Cvar_RegisterVariable(&r_nearclip);
3272         Cvar_RegisterVariable(&r_deformvertexes);
3273         Cvar_RegisterVariable(&r_transparent);
3274         Cvar_RegisterVariable(&r_transparent_alphatocoverage);
3275         Cvar_RegisterVariable(&r_transparent_sortsurfacesbynearest);
3276         Cvar_RegisterVariable(&r_transparent_useplanardistance);
3277         Cvar_RegisterVariable(&r_showoverdraw);
3278         Cvar_RegisterVariable(&r_showbboxes);
3279         Cvar_RegisterVariable(&r_showbboxes_client);
3280         Cvar_RegisterVariable(&r_showsurfaces);
3281         Cvar_RegisterVariable(&r_showtris);
3282         Cvar_RegisterVariable(&r_shownormals);
3283         Cvar_RegisterVariable(&r_showlighting);
3284         Cvar_RegisterVariable(&r_showcollisionbrushes);
3285         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonfactor);
3286         Cvar_RegisterVariable(&r_showcollisionbrushes_polygonoffset);
3287         Cvar_RegisterVariable(&r_showdisabledepthtest);
3288         Cvar_RegisterVariable(&r_showspriteedges);
3289         Cvar_RegisterVariable(&r_showparticleedges);
3290         Cvar_RegisterVariable(&r_drawportals);
3291         Cvar_RegisterVariable(&r_drawentities);
3292         Cvar_RegisterVariable(&r_draw2d);
3293         Cvar_RegisterVariable(&r_drawworld);
3294         Cvar_RegisterVariable(&r_cullentities_trace);
3295         Cvar_RegisterVariable(&r_cullentities_trace_entityocclusion);
3296         Cvar_RegisterVariable(&r_cullentities_trace_samples);
3297         Cvar_RegisterVariable(&r_cullentities_trace_tempentitysamples);
3298         Cvar_RegisterVariable(&r_cullentities_trace_enlarge);
3299         Cvar_RegisterVariable(&r_cullentities_trace_expand);
3300         Cvar_RegisterVariable(&r_cullentities_trace_pad);
3301         Cvar_RegisterVariable(&r_cullentities_trace_delay);
3302         Cvar_RegisterVariable(&r_cullentities_trace_eyejitter);
3303         Cvar_RegisterVariable(&r_sortentities);
3304         Cvar_RegisterVariable(&r_drawviewmodel);
3305         Cvar_RegisterVariable(&r_drawexteriormodel);
3306         Cvar_RegisterVariable(&r_speeds);
3307         Cvar_RegisterVariable(&r_fullbrights);
3308         Cvar_RegisterVariable(&r_wateralpha);
3309         Cvar_RegisterVariable(&r_dynamic);
3310         Cvar_RegisterVariable(&r_fullbright_directed);
3311         Cvar_RegisterVariable(&r_fullbright_directed_ambient);
3312         Cvar_RegisterVariable(&r_fullbright_directed_diffuse);
3313         Cvar_RegisterVariable(&r_fullbright_directed_pitch);
3314         Cvar_RegisterVariable(&r_fullbright_directed_pitch_relative);
3315         Cvar_RegisterVariable(&r_fullbright);
3316         Cvar_RegisterVariable(&r_shadows);
3317         Cvar_RegisterVariable(&r_shadows_darken);
3318         Cvar_RegisterVariable(&r_shadows_drawafterrtlighting);
3319         Cvar_RegisterVariable(&r_shadows_castfrombmodels);
3320         Cvar_RegisterVariable(&r_shadows_throwdistance);
3321         Cvar_RegisterVariable(&r_shadows_throwdirection);
3322         Cvar_RegisterVariable(&r_shadows_focus);
3323         Cvar_RegisterVariable(&r_shadows_shadowmapscale);
3324         Cvar_RegisterVariable(&r_shadows_shadowmapbias);
3325         Cvar_RegisterVariable(&r_q1bsp_skymasking);
3326         Cvar_RegisterVariable(&r_polygonoffset_submodel_factor);
3327         Cvar_RegisterVariable(&r_polygonoffset_submodel_offset);
3328         Cvar_RegisterVariable(&r_polygonoffset_decals_factor);
3329         Cvar_RegisterVariable(&r_polygonoffset_decals_offset);
3330         Cvar_RegisterVariable(&r_fog_exp2);
3331         Cvar_RegisterVariable(&r_fog_clear);
3332         Cvar_RegisterVariable(&r_drawfog);
3333         Cvar_RegisterVariable(&r_transparentdepthmasking);
3334         Cvar_RegisterVariable(&r_transparent_sortmindist);
3335         Cvar_RegisterVariable(&r_transparent_sortmaxdist);
3336         Cvar_RegisterVariable(&r_transparent_sortarraysize);
3337         Cvar_RegisterVariable(&r_texture_dds_load);
3338         Cvar_RegisterVariable(&r_texture_dds_save);
3339         Cvar_RegisterVariable(&r_textureunits);
3340         Cvar_RegisterVariable(&gl_combine);
3341         Cvar_RegisterVariable(&r_usedepthtextures);
3342         Cvar_RegisterVariable(&r_viewfbo);
3343         Cvar_RegisterVariable(&r_rendertarget_debug);
3344         Cvar_RegisterVariable(&r_viewscale);
3345         Cvar_RegisterVariable(&r_viewscale_fpsscaling);
3346         Cvar_RegisterVariable(&r_viewscale_fpsscaling_min);
3347         Cvar_RegisterVariable(&r_viewscale_fpsscaling_multiply);
3348         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepsize);
3349         Cvar_RegisterVariable(&r_viewscale_fpsscaling_stepmax);
3350         Cvar_RegisterVariable(&r_viewscale_fpsscaling_target);
3351         Cvar_RegisterVariable(&r_glsl);
3352         Cvar_RegisterVariable(&r_glsl_deluxemapping);
3353         Cvar_RegisterVariable(&r_glsl_offsetmapping);
3354         Cvar_RegisterVariable(&r_glsl_offsetmapping_steps);
3355         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping);
3356         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_steps);
3357         Cvar_RegisterVariable(&r_glsl_offsetmapping_reliefmapping_refinesteps);
3358         Cvar_RegisterVariable(&r_glsl_offsetmapping_scale);
3359         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod);
3360         Cvar_RegisterVariable(&r_glsl_offsetmapping_lod_distance);
3361         Cvar_RegisterVariable(&r_glsl_postprocess);
3362         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1);
3363         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2);
3364         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3);
3365         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4);
3366         Cvar_RegisterVariable(&r_glsl_postprocess_uservec1_enable);
3367         Cvar_RegisterVariable(&r_glsl_postprocess_uservec2_enable);
3368         Cvar_RegisterVariable(&r_glsl_postprocess_uservec3_enable);
3369         Cvar_RegisterVariable(&r_glsl_postprocess_uservec4_enable);
3370         Cvar_RegisterVariable(&r_celshading);
3371         Cvar_RegisterVariable(&r_celoutlines);
3372         Cvar_RegisterVariable(&r_fxaa);
3373
3374         Cvar_RegisterVariable(&r_water);
3375         Cvar_RegisterVariable(&r_water_cameraentitiesonly);
3376         Cvar_RegisterVariable(&r_water_resolutionmultiplier);
3377         Cvar_RegisterVariable(&r_water_clippingplanebias);
3378         Cvar_RegisterVariable(&r_water_refractdistort);
3379         Cvar_RegisterVariable(&r_water_reflectdistort);
3380         Cvar_RegisterVariable(&r_water_scissormode);
3381         Cvar_RegisterVariable(&r_water_lowquality);
3382         Cvar_RegisterVariable(&r_water_hideplayer);
3383
3384         Cvar_RegisterVariable(&r_lerpsprites);
3385         Cvar_RegisterVariable(&r_lerpmodels);
3386         Cvar_RegisterVariable(&r_nolerp_list);
3387         Cvar_RegisterVariable(&r_lerplightstyles);
3388         Cvar_RegisterVariable(&r_waterscroll);
3389         Cvar_RegisterVariable(&r_bloom);
3390         Cvar_RegisterVariable(&r_colorfringe);
3391         Cvar_RegisterVariable(&r_bloom_colorscale);
3392         Cvar_RegisterVariable(&r_bloom_brighten);
3393         Cvar_RegisterVariable(&r_bloom_blur);
3394         Cvar_RegisterVariable(&r_bloom_resolution);
3395         Cvar_RegisterVariable(&r_bloom_colorexponent);
3396         Cvar_RegisterVariable(&r_bloom_colorsubtract);
3397         Cvar_RegisterVariable(&r_bloom_scenebrightness);
3398         Cvar_RegisterVariable(&r_hdr_scenebrightness);
3399         Cvar_RegisterVariable(&r_hdr_glowintensity);
3400         Cvar_RegisterVariable(&r_hdr_irisadaptation);
3401         Cvar_RegisterVariable(&r_hdr_irisadaptation_multiplier);
3402         Cvar_RegisterVariable(&r_hdr_irisadaptation_minvalue);
3403         Cvar_RegisterVariable(&r_hdr_irisadaptation_maxvalue);
3404         Cvar_RegisterVariable(&r_hdr_irisadaptation_value);
3405         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_up);
3406         Cvar_RegisterVariable(&r_hdr_irisadaptation_fade_down);
3407         Cvar_RegisterVariable(&r_hdr_irisadaptation_radius);
3408         Cvar_RegisterVariable(&r_smoothnormals_areaweighting);
3409         Cvar_RegisterVariable(&developer_texturelogging);
3410         Cvar_RegisterVariable(&gl_lightmaps);
3411         Cvar_RegisterVariable(&r_test);
3412         Cvar_RegisterVariable(&r_batch_multidraw);
3413         Cvar_RegisterVariable(&r_batch_multidraw_mintriangles);
3414         Cvar_RegisterVariable(&r_batch_debugdynamicvertexpath);
3415         Cvar_RegisterVariable(&r_glsl_skeletal);
3416         Cvar_RegisterVariable(&r_glsl_saturation);
3417         Cvar_RegisterVariable(&r_glsl_saturation_redcompensate);
3418         Cvar_RegisterVariable(&r_glsl_vertextextureblend_usebothalphas);
3419         Cvar_RegisterVariable(&r_framedatasize);
3420         for (i = 0;i < R_BUFFERDATA_COUNT;i++)
3421                 Cvar_RegisterVariable(&r_buffermegs[i]);
3422         Cvar_RegisterVariable(&r_batch_dynamicbuffer);
3423         Cvar_RegisterVariable(&r_q1bsp_lightmap_updates_enabled);
3424         Cvar_RegisterVariable(&r_q1bsp_lightmap_updates_combine);
3425         Cvar_RegisterVariable(&r_q1bsp_lightmap_updates_hidden_surfaces);
3426         if (gamemode == GAME_NEHAHRA || gamemode == GAME_TENEBRAE)
3427                 Cvar_SetValue(&cvars_all, "r_fullbrights", 0);
3428 #ifdef DP_MOBILETOUCH
3429         // GLES devices have terrible depth precision in general, so...
3430         Cvar_SetValueQuick(&r_nearclip, 4);
3431         Cvar_SetValueQuick(&r_farclip_base, 4096);
3432         Cvar_SetValueQuick(&r_farclip_world, 0);
3433         Cvar_SetValueQuick(&r_useinfinitefarclip, 0);
3434 #endif
3435         R_RegisterModule("GL_Main", gl_main_start, gl_main_shutdown, gl_main_newmap, NULL, NULL);
3436 }
3437
3438 void Render_Init(void)
3439 {
3440         gl_backend_init();
3441         R_Textures_Init();
3442         GL_Main_Init();
3443         Font_Init();
3444         GL_Draw_Init();
3445         R_Shadow_Init();
3446         R_Sky_Init();
3447         GL_Surf_Init();
3448         Sbar_Init();
3449         R_Particles_Init();
3450         R_Explosion_Init();
3451         R_LightningBeams_Init();
3452         CL_MeshEntities_Init();
3453         Mod_RenderInit();
3454 }
3455
3456 static void R_GetCornerOfBox(vec3_t out, const vec3_t mins, const vec3_t maxs, int signbits)
3457 {
3458         out[0] = ((signbits & 1) ? mins : maxs)[0];
3459         out[1] = ((signbits & 2) ? mins : maxs)[1];
3460         out[2] = ((signbits & 4) ? mins : maxs)[2];
3461 }
3462
3463 static qbool _R_CullBox(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes, int ignore)
3464 {
3465         int i;
3466         const mplane_t *p;
3467         vec3_t corner;
3468         if (r_trippy.integer)
3469                 return false;
3470         for (i = 0;i < numplanes;i++)
3471         {
3472                 if(i == ignore)
3473                         continue;
3474                 p = planes + i;
3475                 R_GetCornerOfBox(corner, mins, maxs, p->signbits);
3476                 if (DotProduct(p->normal, corner) < p->dist)
3477                         return true;
3478         }
3479         return false;
3480 }
3481
3482 qbool R_CullFrustum(const vec3_t mins, const vec3_t maxs)
3483 {
3484         // skip nearclip plane, it often culls portals when you are very close, and is almost never useful
3485         return _R_CullBox(mins, maxs, r_refdef.view.numfrustumplanes, r_refdef.view.frustum, 4);
3486 }
3487
3488 qbool R_CullBox(const vec3_t mins, const vec3_t maxs, int numplanes, const mplane_t *planes)
3489 {
3490         // nothing to ignore
3491         return _R_CullBox(mins, maxs, numplanes, planes, -1);
3492 }
3493
3494 //==================================================================================
3495
3496 // LadyHavoc: this stores temporary data used within the same frame
3497
3498 typedef struct r_framedata_mem_s
3499 {
3500         struct r_framedata_mem_s *purge; // older mem block to free on next frame
3501         size_t size; // how much usable space
3502         size_t current; // how much space in use
3503         size_t mark; // last "mark" location, temporary memory can be freed by returning to this
3504         size_t wantedsize; // how much space was allocated
3505         unsigned char *data; // start of real data (16byte aligned)
3506 }
3507 r_framedata_mem_t;
3508
3509 static r_framedata_mem_t *r_framedata_mem;
3510
3511 void R_FrameData_Reset(void)
3512 {
3513         while (r_framedata_mem)
3514         {
3515                 r_framedata_mem_t *next = r_framedata_mem->purge;
3516                 Mem_Free(r_framedata_mem);
3517                 r_framedata_mem = next;
3518         }
3519 }
3520
3521 static void R_FrameData_Resize(qbool mustgrow)
3522 {
3523         size_t wantedsize;
3524         wantedsize = (size_t)(r_framedatasize.value * 1024*1024);
3525         wantedsize = bound(65536, wantedsize, 1000*1024*1024);
3526         if (!r_framedata_mem || r_framedata_mem->wantedsize != wantedsize || mustgrow)
3527         {
3528                 r_framedata_mem_t *newmem = (r_framedata_mem_t *)Mem_Alloc(r_main_mempool, wantedsize);
3529                 newmem->wantedsize = wantedsize;
3530                 newmem->data = (unsigned char *)(((size_t)(newmem+1) + 15) & ~15);
3531                 newmem->size = (unsigned char *)newmem + wantedsize - newmem->data;
3532                 newmem->current = 0;
3533                 newmem->mark = 0;
3534                 newmem->purge = r_framedata_mem;
3535                 r_framedata_mem = newmem;
3536         }
3537 }
3538
3539 void R_FrameData_NewFrame(void)
3540 {
3541         R_FrameData_Resize(false);
3542         if (!r_framedata_mem)
3543                 return;
3544         // if we ran out of space on the last frame, free the old memory now
3545         while (r_framedata_mem->purge)
3546         {
3547                 // repeatedly remove the second item in the list, leaving only head
3548                 r_framedata_mem_t *next = r_framedata_mem->purge->purge;
3549                 Mem_Free(r_framedata_mem->purge);
3550                 r_framedata_mem->purge = next;
3551         }
3552         // reset the current mem pointer
3553         r_framedata_mem->current = 0;
3554         r_framedata_mem->mark = 0;
3555 }
3556
3557 void *R_FrameData_Alloc(size_t size)
3558 {
3559         void *data;
3560         float newvalue;
3561
3562         // align to 16 byte boundary - the data pointer is already aligned, so we
3563         // only need to ensure the size of every allocation is also aligned
3564         size = (size + 15) & ~15;
3565
3566         while (!r_framedata_mem || r_framedata_mem->current + size > r_framedata_mem->size)
3567         {
3568                 // emergency - we ran out of space, allocate more memory
3569                 // note: this has no upper-bound, we'll fail to allocate memory eventually and just die
3570                 newvalue = r_framedatasize.value * 2.0f;
3571                 // 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
3572                 if (sizeof(size_t) >= 8)
3573                         newvalue = bound(0.25f, newvalue, (float)(1ll << 42));
3574                 else
3575                         newvalue = bound(0.25f, newvalue, (float)(1 << 10));
3576                 // this might not be a growing it, but we'll allocate another buffer every time
3577                 Cvar_SetValueQuick(&r_framedatasize, newvalue);
3578                 R_FrameData_Resize(true);
3579         }
3580
3581         data = r_framedata_mem->data + r_framedata_mem->current;
3582         r_framedata_mem->current += size;
3583
3584         // count the usage for stats
3585         r_refdef.stats[r_stat_framedatacurrent] = max(r_refdef.stats[r_stat_framedatacurrent], (int)r_framedata_mem->current);
3586         r_refdef.stats[r_stat_framedatasize] = max(r_refdef.stats[r_stat_framedatasize], (int)r_framedata_mem->size);
3587
3588         return (void *)data;
3589 }
3590
3591 void *R_FrameData_Store(size_t size, void *data)
3592 {
3593         void *d = R_FrameData_Alloc(size);
3594         if (d && data)
3595                 memcpy(d, data, size);
3596         return d;
3597 }
3598
3599 void R_FrameData_SetMark(void)
3600 {
3601         if (!r_framedata_mem)
3602                 return;
3603         r_framedata_mem->mark = r_framedata_mem->current;
3604 }
3605
3606 void R_FrameData_ReturnToMark(void)
3607 {
3608         if (!r_framedata_mem)
3609                 return;
3610         r_framedata_mem->current = r_framedata_mem->mark;
3611 }
3612
3613 //==================================================================================
3614
3615 // avoid reusing the same buffer objects on consecutive frames
3616 #define R_BUFFERDATA_CYCLE 3
3617
3618 typedef struct r_bufferdata_buffer_s
3619 {
3620         struct r_bufferdata_buffer_s *purge; // older buffer to free on next frame
3621         size_t size; // how much usable space
3622         size_t current; // how much space in use
3623         r_meshbuffer_t *buffer; // the buffer itself
3624 }
3625 r_bufferdata_buffer_t;
3626
3627 static int r_bufferdata_cycle = 0; // incremented and wrapped each frame
3628 static r_bufferdata_buffer_t *r_bufferdata_buffer[R_BUFFERDATA_CYCLE][R_BUFFERDATA_COUNT];
3629
3630 /// frees all dynamic buffers
3631 void R_BufferData_Reset(void)
3632 {
3633         int cycle, type;
3634         r_bufferdata_buffer_t **p, *mem;
3635         for (cycle = 0;cycle < R_BUFFERDATA_CYCLE;cycle++)
3636         {
3637                 for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3638                 {
3639                         // free all buffers
3640                         p = &r_bufferdata_buffer[cycle][type];
3641                         while (*p)
3642                         {
3643                                 mem = *p;
3644                                 *p = (*p)->purge;
3645                                 if (mem->buffer)
3646                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3647                                 Mem_Free(mem);
3648                         }
3649                 }
3650         }
3651 }
3652
3653 // resize buffer as needed (this actually makes a new one, the old one will be recycled next frame)
3654 static void R_BufferData_Resize(r_bufferdata_type_t type, qbool mustgrow, size_t minsize)
3655 {
3656         r_bufferdata_buffer_t *mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3657         size_t size;
3658         float newvalue = r_buffermegs[type].value;
3659
3660         // increase the cvar if we have to (but only if we already have a mem)
3661         if (mustgrow && mem)
3662                 newvalue *= 2.0f;
3663         newvalue = bound(0.25f, newvalue, 256.0f);
3664         while (newvalue * 1024*1024 < minsize)
3665                 newvalue *= 2.0f;
3666
3667         // clamp the cvar to valid range
3668         newvalue = bound(0.25f, newvalue, 256.0f);
3669         if (r_buffermegs[type].value != newvalue)
3670                 Cvar_SetValueQuick(&r_buffermegs[type], newvalue);
3671
3672         // calculate size in bytes
3673         size = (size_t)(newvalue * 1024*1024);
3674         size = bound(131072, size, 256*1024*1024);
3675
3676         // allocate a new buffer if the size is different (purge old one later)
3677         // or if we were told we must grow the buffer
3678         if (!mem || mem->size != size || mustgrow)
3679         {
3680                 mem = (r_bufferdata_buffer_t *)Mem_Alloc(r_main_mempool, sizeof(*mem));
3681                 mem->size = size;
3682                 mem->current = 0;
3683                 if (type == R_BUFFERDATA_VERTEX)
3684                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbuffervertex", false, false, true, false);
3685                 else if (type == R_BUFFERDATA_INDEX16)
3686                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex16", true, false, true, true);
3687                 else if (type == R_BUFFERDATA_INDEX32)
3688                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferindex32", true, false, true, false);
3689                 else if (type == R_BUFFERDATA_UNIFORM)
3690                         mem->buffer = R_Mesh_CreateMeshBuffer(NULL, mem->size, "dynamicbufferuniform", false, true, true, false);
3691                 mem->purge = r_bufferdata_buffer[r_bufferdata_cycle][type];
3692                 r_bufferdata_buffer[r_bufferdata_cycle][type] = mem;
3693         }
3694 }
3695
3696 void R_BufferData_NewFrame(void)
3697 {
3698         int type;
3699         r_bufferdata_buffer_t **p, *mem;
3700         // cycle to the next frame's buffers
3701         r_bufferdata_cycle = (r_bufferdata_cycle + 1) % R_BUFFERDATA_CYCLE;
3702         // if we ran out of space on the last time we used these buffers, free the old memory now
3703         for (type = 0;type < R_BUFFERDATA_COUNT;type++)
3704         {
3705                 if (r_bufferdata_buffer[r_bufferdata_cycle][type])
3706                 {
3707                         R_BufferData_Resize((r_bufferdata_type_t)type, false, 131072);
3708                         // free all but the head buffer, this is how we recycle obsolete
3709                         // buffers after they are no longer in use
3710                         p = &r_bufferdata_buffer[r_bufferdata_cycle][type]->purge;
3711                         while (*p)
3712                         {
3713                                 mem = *p;
3714                                 *p = (*p)->purge;
3715                                 if (mem->buffer)
3716                                         R_Mesh_DestroyMeshBuffer(mem->buffer);
3717                                 Mem_Free(mem);
3718                         }
3719                         // reset the current offset
3720                         r_bufferdata_buffer[r_bufferdata_cycle][type]->current = 0;
3721                 }
3722         }
3723 }
3724
3725 r_meshbuffer_t *R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset)
3726 {
3727         r_bufferdata_buffer_t *mem;
3728         int offset = 0;
3729         int padsize;
3730
3731         *returnbufferoffset = 0;
3732
3733         // align size to a byte boundary appropriate for the buffer type, this
3734         // makes all allocations have aligned start offsets
3735         if (type == R_BUFFERDATA_UNIFORM)
3736                 padsize = (datasize + r_uniformbufferalignment - 1) & ~(r_uniformbufferalignment - 1);
3737         else
3738                 padsize = (datasize + 15) & ~15;
3739
3740         // if we ran out of space in this buffer we must allocate a new one
3741         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)
3742                 R_BufferData_Resize(type, true, padsize);
3743
3744         // if the resize did not give us enough memory, fail
3745         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)
3746                 Sys_Error("R_BufferData_Store: failed to create a new buffer of sufficient size\n");
3747
3748         mem = r_bufferdata_buffer[r_bufferdata_cycle][type];
3749         offset = (int)mem->current;
3750         mem->current += padsize;
3751
3752         // upload the data to the buffer at the chosen offset
3753         if (offset == 0)
3754                 R_Mesh_UpdateMeshBuffer(mem->buffer, NULL, mem->size, false, 0);
3755         R_Mesh_UpdateMeshBuffer(mem->buffer, data, datasize, true, offset);
3756
3757         // count the usage for stats
3758         r_refdef.stats[r_stat_bufferdatacurrent_vertex + type] = max(r_refdef.stats[r_stat_bufferdatacurrent_vertex + type], (int)mem->current);
3759         r_refdef.stats[r_stat_bufferdatasize_vertex + type] = max(r_refdef.stats[r_stat_bufferdatasize_vertex + type], (int)mem->size);
3760
3761         // return the buffer offset
3762         *returnbufferoffset = offset;
3763
3764         return mem->buffer;
3765 }
3766
3767 //==================================================================================
3768
3769 // LadyHavoc: animcache originally written by Echon, rewritten since then
3770
3771 /**
3772  * Animation cache prevents re-generating mesh data for an animated model
3773  * multiple times in one frame for lighting, shadowing, reflections, etc.
3774  */
3775
3776 void R_AnimCache_Free(void)
3777 {
3778 }
3779
3780 void R_AnimCache_ClearCache(void)
3781 {
3782         int i;
3783         entity_render_t *ent;
3784
3785         for (i = 0;i < r_refdef.scene.numentities;i++)
3786         {
3787                 ent = r_refdef.scene.entities[i];
3788                 ent->animcache_vertex3f = NULL;
3789                 ent->animcache_vertex3f_vertexbuffer = NULL;
3790                 ent->animcache_vertex3f_bufferoffset = 0;
3791                 ent->animcache_normal3f = NULL;
3792                 ent->animcache_normal3f_vertexbuffer = NULL;
3793                 ent->animcache_normal3f_bufferoffset = 0;
3794                 ent->animcache_svector3f = NULL;
3795                 ent->animcache_svector3f_vertexbuffer = NULL;
3796                 ent->animcache_svector3f_bufferoffset = 0;
3797                 ent->animcache_tvector3f = NULL;
3798                 ent->animcache_tvector3f_vertexbuffer = NULL;
3799                 ent->animcache_tvector3f_bufferoffset = 0;
3800                 ent->animcache_skeletaltransform3x4 = NULL;
3801                 ent->animcache_skeletaltransform3x4buffer = NULL;
3802                 ent->animcache_skeletaltransform3x4offset = 0;
3803                 ent->animcache_skeletaltransform3x4size = 0;
3804         }
3805 }
3806
3807 qbool R_AnimCache_GetEntity(entity_render_t *ent, qbool wantnormals, qbool wanttangents)
3808 {
3809         model_t *model = ent->model;
3810         int numvertices;
3811
3812         // see if this ent is worth caching
3813         if (!model || !model->Draw || !model->AnimateVertices)
3814                 return false;
3815         // nothing to cache if it contains no animations and has no skeleton
3816         if (!model->surfmesh.isanimated && !(model->num_bones && ent->skeleton && ent->skeleton->relativetransforms))
3817                 return false;
3818         // see if it is already cached for gpuskeletal
3819         if (ent->animcache_skeletaltransform3x4)
3820                 return false;
3821         // see if it is already cached as a mesh
3822         if (ent->animcache_vertex3f)
3823         {
3824                 // check if we need to add normals or tangents
3825                 if (ent->animcache_normal3f)
3826                         wantnormals = false;
3827                 if (ent->animcache_svector3f)
3828                         wanttangents = false;
3829                 if (!wantnormals && !wanttangents)
3830                         return false;
3831         }
3832
3833         // check which kind of cache we need to generate
3834         if (r_gpuskeletal && model->num_bones > 0 && model->surfmesh.data_skeletalindex4ub)
3835         {
3836                 // cache the skeleton so the vertex shader can use it
3837                 r_refdef.stats[r_stat_animcache_skeletal_count] += 1;
3838                 r_refdef.stats[r_stat_animcache_skeletal_bones] += model->num_bones;
3839                 r_refdef.stats[r_stat_animcache_skeletal_maxbones] = max(r_refdef.stats[r_stat_animcache_skeletal_maxbones], model->num_bones);
3840                 ent->animcache_skeletaltransform3x4 = (float *)R_FrameData_Alloc(sizeof(float[3][4]) * model->num_bones);
3841                 Mod_Skeletal_BuildTransforms(model, ent->frameblend, ent->skeleton, NULL, ent->animcache_skeletaltransform3x4); 
3842                 // note: this can fail if the buffer is at the grow limit
3843                 ent->animcache_skeletaltransform3x4size = sizeof(float[3][4]) * model->num_bones;
3844                 ent->animcache_skeletaltransform3x4buffer = R_BufferData_Store(ent->animcache_skeletaltransform3x4size, ent->animcache_skeletaltransform3x4, R_BUFFERDATA_UNIFORM, &ent->animcache_skeletaltransform3x4offset);
3845         }
3846         else if (ent->animcache_vertex3f)
3847         {
3848                 // mesh was already cached but we may need to add normals/tangents
3849                 // (this only happens with multiple views, reflections, cameras, etc)
3850                 if (wantnormals || wanttangents)
3851                 {
3852                         numvertices = model->surfmesh.num_vertices;
3853                         if (wantnormals)
3854                                 ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3855                         if (wanttangents)
3856                         {
3857                                 ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3858                                 ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3859                         }
3860                         model->AnimateVertices(model, ent->frameblend, ent->skeleton, NULL, wantnormals ? ent->animcache_normal3f : NULL, wanttangents ? ent->animcache_svector3f : NULL, wanttangents ? ent->animcache_tvector3f : NULL);
3861                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3862                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3863                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3864                 }
3865         }
3866         else
3867         {
3868                 // generate mesh cache
3869                 numvertices = model->surfmesh.num_vertices;
3870                 ent->animcache_vertex3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3871                 if (wantnormals)
3872                         ent->animcache_normal3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3873                 if (wanttangents)
3874                 {
3875                         ent->animcache_svector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3876                         ent->animcache_tvector3f = (float *)R_FrameData_Alloc(sizeof(float[3])*numvertices);
3877                 }
3878                 model->AnimateVertices(model, ent->frameblend, ent->skeleton, ent->animcache_vertex3f, ent->animcache_normal3f, ent->animcache_svector3f, ent->animcache_tvector3f);
3879                 if (wantnormals || wanttangents)
3880                 {
3881                         r_refdef.stats[r_stat_animcache_shade_count] += 1;
3882                         r_refdef.stats[r_stat_animcache_shade_vertices] += numvertices;
3883                         r_refdef.stats[r_stat_animcache_shade_maxvertices] = max(r_refdef.stats[r_stat_animcache_shade_maxvertices], numvertices);
3884                 }
3885                 r_refdef.stats[r_stat_animcache_shape_count] += 1;
3886                 r_refdef.stats[r_stat_animcache_shape_vertices] += numvertices;
3887                 r_refdef.stats[r_stat_animcache_shape_maxvertices] = max(r_refdef.stats[r_stat_animcache_shape_maxvertices], numvertices);
3888         }
3889         return true;
3890 }
3891
3892 void R_AnimCache_CacheVisibleEntities(void)
3893 {
3894         int i;
3895
3896         // TODO: thread this
3897         // NOTE: R_PrepareRTLights() also caches entities
3898
3899         for (i = 0;i < r_refdef.scene.numentities;i++)
3900                 if (r_refdef.viewcache.entityvisible[i])
3901                         R_AnimCache_GetEntity(r_refdef.scene.entities[i], true, true);
3902 }
3903
3904 //==================================================================================
3905
3906 qbool 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)
3907 {
3908         long unsigned int i;
3909         int j;
3910         vec3_t eyemins, eyemaxs;
3911         vec3_t boxmins, boxmaxs;
3912         vec3_t padmins, padmaxs;
3913         vec3_t start;
3914         vec3_t end;
3915         model_t *model = r_refdef.scene.worldmodel;
3916         static vec3_t positions[] = {
3917                 { 0.5f, 0.5f, 0.5f },
3918                 { 0.0f, 0.0f, 0.0f },
3919                 { 0.0f, 0.0f, 1.0f },
3920                 { 0.0f, 1.0f, 0.0f },
3921                 { 0.0f, 1.0f, 1.0f },
3922                 { 1.0f, 0.0f, 0.0f },
3923                 { 1.0f, 0.0f, 1.0f },
3924                 { 1.0f, 1.0f, 0.0f },
3925                 { 1.0f, 1.0f, 1.0f },
3926         };
3927
3928         // sample count can be set to -1 to skip this logic, for flicker-prone objects
3929         if (numsamples < 0)
3930                 return true;
3931
3932         // view origin is not used for culling in portal/reflection/refraction renders or isometric views
3933         if (!r_refdef.view.usevieworiginculling)
3934                 return true;
3935
3936         if (!r_cullentities_trace_entityocclusion.integer && (!model || !model->brush.TraceLineOfSight))
3937                 return true;
3938
3939         // expand the eye box a little
3940         eyemins[0] = eye[0] - eyejitter;
3941         eyemaxs[0] = eye[0] + eyejitter;
3942         eyemins[1] = eye[1] - eyejitter;
3943         eyemaxs[1] = eye[1] + eyejitter;
3944         eyemins[2] = eye[2] - eyejitter;
3945         eyemaxs[2] = eye[2] + eyejitter;
3946         // expand the box a little
3947         boxmins[0] = (entboxenlarge + 1) * entboxmins[0] - entboxenlarge * entboxmaxs[0] - entboxexpand;
3948         boxmaxs[0] = (entboxenlarge + 1) * entboxmaxs[0] - entboxenlarge * entboxmins[0] + entboxexpand;
3949         boxmins[1] = (entboxenlarge + 1) * entboxmins[1] - entboxenlarge * entboxmaxs[1] - entboxexpand;
3950         boxmaxs[1] = (entboxenlarge + 1) * entboxmaxs[1] - entboxenlarge * entboxmins[1] + entboxexpand;
3951         boxmins[2] = (entboxenlarge + 1) * entboxmins[2] - entboxenlarge * entboxmaxs[2] - entboxexpand;
3952         boxmaxs[2] = (entboxenlarge + 1) * entboxmaxs[2] - entboxenlarge * entboxmins[2] + entboxexpand;
3953         // make an even larger box for the acceptable area
3954         padmins[0] = boxmins[0] - pad;
3955         padmaxs[0] = boxmaxs[0] + pad;
3956         padmins[1] = boxmins[1] - pad;
3957         padmaxs[1] = boxmaxs[1] + pad;
3958         padmins[2] = boxmins[2] - pad;
3959         padmaxs[2] = boxmaxs[2] + pad;
3960
3961         // return true if eye overlaps enlarged box
3962         if (BoxesOverlap(boxmins, boxmaxs, eyemins, eyemaxs))
3963                 return true;
3964
3965         VectorCopy(eye, start);
3966         // try specific positions in the box first - note that these can be cached
3967         if (r_cullentities_trace_entityocclusion.integer)
3968         {
3969                 for (i = 0; i < sizeof(positions) / sizeof(positions[0]); i++)
3970                 {
3971                         trace_t trace;
3972                         end[0] = boxmins[0] + (boxmaxs[0] - boxmins[0]) * positions[i][0];
3973                         end[1] = boxmins[1] + (boxmaxs[1] - boxmins[1]) * positions[i][1];
3974                         end[2] = boxmins[2] + (boxmaxs[2] - boxmins[2]) * positions[i][2];
3975                         //trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
3976                         trace = CL_Cache_TraceLineSurfaces(start, end, MOVE_NORMAL, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT);
3977                         // not picky - if the trace ended anywhere in the box we're good
3978                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
3979                                 return true;
3980                 }
3981         }
3982         else
3983         {
3984                 // try center
3985                 VectorMAM(0.5f, boxmins, 0.5f, boxmaxs, end);
3986                 if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
3987                         return true;
3988         }
3989
3990         // try various random positions
3991         for (j = 0; j < numsamples; j++)
3992         {
3993                 VectorSet(start, lhrandom(eyemins[0], eyemaxs[0]), lhrandom(eyemins[1], eyemaxs[1]), lhrandom(eyemins[2], eyemaxs[2]));
3994                 VectorSet(end, lhrandom(boxmins[0], boxmaxs[0]), lhrandom(boxmins[1], boxmaxs[1]), lhrandom(boxmins[2], boxmaxs[2]));
3995                 if (r_cullentities_trace_entityocclusion.integer)
3996                 {
3997                         trace_t trace = CL_TraceLine(start, end, MOVE_NORMAL, NULL, SUPERCONTENTS_SOLID, SUPERCONTENTS_SKY, MATERIALFLAGMASK_TRANSLUCENT, 0.0f, true, false, NULL, true, true);
3998                         // not picky - if the trace ended anywhere in the box we're good
3999                         if (BoxesOverlap(trace.endpos, trace.endpos, padmins, padmaxs))
4000                                 return true;
4001                 }
4002                 else if (model->brush.TraceLineOfSight(model, start, end, padmins, padmaxs))
4003                         return true;
4004         }
4005
4006         return false;
4007 }
4008
4009
4010 static void R_View_UpdateEntityVisible (void)
4011 {
4012         int i;
4013         int renderimask;
4014         int samples;
4015         entity_render_t *ent;
4016
4017         if (r_refdef.envmap || r_fb.water.hideplayer)
4018                 renderimask = RENDER_EXTERIORMODEL | RENDER_VIEWMODEL;
4019         else if (chase_active.integer || r_fb.water.renderingscene)
4020                 renderimask = RENDER_VIEWMODEL;
4021         else
4022                 renderimask = RENDER_EXTERIORMODEL;
4023         if (!r_drawviewmodel.integer)
4024                 renderimask |= RENDER_VIEWMODEL;
4025         if (!r_drawexteriormodel.integer)
4026                 renderimask |= RENDER_EXTERIORMODEL;
4027         memset(r_refdef.viewcache.entityvisible, 0, r_refdef.scene.numentities);
4028         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.BoxTouchingVisibleLeafs)
4029         {
4030                 // worldmodel can check visibility
4031                 for (i = 0;i < r_refdef.scene.numentities;i++)
4032                 {
4033                         ent = r_refdef.scene.entities[i];
4034                         if (r_refdef.viewcache.world_novis && !(ent->flags & RENDER_VIEWMODEL))
4035                         {
4036                                 r_refdef.viewcache.entityvisible[i] = false;
4037                                 continue;
4038                         }
4039                         if (!(ent->flags & renderimask))
4040                         if (!R_CullFrustum(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)))
4041                         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))
4042                                 r_refdef.viewcache.entityvisible[i] = true;
4043                 }
4044         }
4045         else
4046         {
4047                 // no worldmodel or it can't check visibility
4048                 for (i = 0;i < r_refdef.scene.numentities;i++)
4049                 {
4050                         ent = r_refdef.scene.entities[i];
4051                         if (!(ent->flags & renderimask))
4052                         if (!R_CullFrustum(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)))
4053                                 r_refdef.viewcache.entityvisible[i] = true;
4054                 }
4055         }
4056         if (r_cullentities_trace.integer)
4057         {
4058                 for (i = 0;i < r_refdef.scene.numentities;i++)
4059                 {
4060                         if (!r_refdef.viewcache.entityvisible[i])
4061                                 continue;
4062                         ent = r_refdef.scene.entities[i];
4063                         if (!(ent->flags & (RENDER_VIEWMODEL | RENDER_WORLDOBJECT | RENDER_NODEPTHTEST)) && !(ent->model && (ent->model->name[0] == '*')))
4064                         {
4065                                 samples = ent->last_trace_visibility == 0 ? r_cullentities_trace_tempentitysamples.integer : r_cullentities_trace_samples.integer;
4066                                 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))
4067                                         ent->last_trace_visibility = host.realtime;
4068                                 if (ent->last_trace_visibility < host.realtime - r_cullentities_trace_delay.value)
4069                                         r_refdef.viewcache.entityvisible[i] = 0;
4070                         }
4071                 }
4072         }
4073 }
4074
4075 /// only used if skyrendermasked, and normally returns false
4076 static int R_DrawBrushModelsSky (void)
4077 {
4078         int i, sky;
4079         entity_render_t *ent;
4080
4081         sky = false;
4082         for (i = 0;i < r_refdef.scene.numentities;i++)
4083         {
4084                 if (!r_refdef.viewcache.entityvisible[i])
4085                         continue;
4086                 ent = r_refdef.scene.entities[i];
4087                 if (!ent->model || !ent->model->DrawSky)
4088                         continue;
4089                 ent->model->DrawSky(ent);
4090                 sky = true;
4091         }
4092         return sky;
4093 }
4094
4095 static void R_DrawNoModel(entity_render_t *ent);
4096 static void R_DrawModels(void)
4097 {
4098         int i;
4099         entity_render_t *ent;
4100
4101         for (i = 0;i < r_refdef.scene.numentities;i++)
4102         {
4103                 if (!r_refdef.viewcache.entityvisible[i])
4104                         continue;
4105                 ent = r_refdef.scene.entities[i];
4106                 r_refdef.stats[r_stat_entities]++;
4107
4108                 if (ent->model && ent->model->Draw != NULL)
4109                         ent->model->Draw(ent);
4110                 else
4111                         R_DrawNoModel(ent);
4112         }
4113 }
4114
4115 static void R_DrawModelsDepth(void)
4116 {
4117         int i;
4118         entity_render_t *ent;
4119
4120         for (i = 0;i < r_refdef.scene.numentities;i++)
4121         {
4122                 if (!r_refdef.viewcache.entityvisible[i])
4123                         continue;
4124                 ent = r_refdef.scene.entities[i];
4125                 if (ent->model && ent->model->DrawDepth != NULL)
4126                         ent->model->DrawDepth(ent);
4127         }
4128 }
4129
4130 static void R_DrawModelsDebug(void)
4131 {
4132         int i;
4133         entity_render_t *ent;
4134
4135         for (i = 0;i < r_refdef.scene.numentities;i++)
4136         {
4137                 if (!r_refdef.viewcache.entityvisible[i])
4138                         continue;
4139                 ent = r_refdef.scene.entities[i];
4140                 if (ent->model && ent->model->DrawDebug != NULL)
4141                         ent->model->DrawDebug(ent);
4142         }
4143 }
4144
4145 static void R_DrawModelsAddWaterPlanes(void)
4146 {
4147         int i;
4148         entity_render_t *ent;
4149
4150         for (i = 0;i < r_refdef.scene.numentities;i++)
4151         {
4152                 if (!r_refdef.viewcache.entityvisible[i])
4153                         continue;
4154                 ent = r_refdef.scene.entities[i];
4155                 if (ent->model && ent->model->DrawAddWaterPlanes != NULL)
4156                         ent->model->DrawAddWaterPlanes(ent);
4157         }
4158 }
4159
4160 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}};
4161
4162 void R_HDR_UpdateIrisAdaptation(const vec3_t point)
4163 {
4164         if (r_hdr_irisadaptation.integer)
4165         {
4166                 vec3_t p;
4167                 vec3_t ambient;
4168                 vec3_t diffuse;
4169                 vec3_t diffusenormal;
4170                 vec3_t forward;
4171                 vec_t brightness = 0.0f;
4172                 vec_t goal;
4173                 vec_t current;
4174                 vec_t d;
4175                 int c;
4176                 VectorCopy(r_refdef.view.forward, forward);
4177                 for (c = 0;c < (int)(sizeof(irisvecs)/sizeof(irisvecs[0]));c++)
4178                 {
4179                         p[0] = point[0] + irisvecs[c][0] * r_hdr_irisadaptation_radius.value;
4180                         p[1] = point[1] + irisvecs[c][1] * r_hdr_irisadaptation_radius.value;
4181                         p[2] = point[2] + irisvecs[c][2] * r_hdr_irisadaptation_radius.value;
4182                         R_CompleteLightPoint(ambient, diffuse, diffusenormal, p, LP_LIGHTMAP | LP_RTWORLD | LP_DYNLIGHT, r_refdef.scene.lightmapintensity, r_refdef.scene.ambientintensity);
4183                         d = DotProduct(forward, diffusenormal);
4184                         brightness += VectorLength(ambient);
4185                         if (d > 0)
4186                                 brightness += d * VectorLength(diffuse);
4187                 }
4188                 brightness *= 1.0f / c;
4189                 brightness += 0.00001f; // make sure it's never zero
4190                 goal = r_hdr_irisadaptation_multiplier.value / brightness;
4191                 goal = bound(r_hdr_irisadaptation_minvalue.value, goal, r_hdr_irisadaptation_maxvalue.value);
4192                 current = r_hdr_irisadaptation_value.value;
4193                 if (current < goal)
4194                         current = min(current + r_hdr_irisadaptation_fade_up.value * cl.realframetime, goal);
4195                 else if (current > goal)
4196                         current = max(current - r_hdr_irisadaptation_fade_down.value * cl.realframetime, goal);
4197                 if (fabs(r_hdr_irisadaptation_value.value - current) > 0.0001f)
4198                         Cvar_SetValueQuick(&r_hdr_irisadaptation_value, current);
4199         }
4200         else if (r_hdr_irisadaptation_value.value != 1.0f)
4201                 Cvar_SetValueQuick(&r_hdr_irisadaptation_value, 1.0f);
4202 }
4203
4204 extern cvar_t r_lockvisibility;
4205 extern cvar_t r_lockpvs;
4206
4207 static void R_View_SetFrustum(const int *scissor)
4208 {
4209         int i;
4210         double fpx = +1, fnx = -1, fpy = +1, fny = -1;
4211         vec3_t forward, left, up, origin, v;
4212         if(r_lockvisibility.integer)
4213                 return;
4214         if(scissor)
4215         {
4216                 // flipped x coordinates (because x points left here)
4217                 fpx =  1.0 - 2.0 * (scissor[0]              - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4218                 fnx =  1.0 - 2.0 * (scissor[0] + scissor[2] - r_refdef.view.viewport.x) / (double) (r_refdef.view.viewport.width);
4219                 // non-flipped y coordinates
4220                 fny = -1.0 + 2.0 * (scissor[1]              - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4221                 fpy = -1.0 + 2.0 * (scissor[1] + scissor[3] - r_refdef.view.viewport.y) / (double) (r_refdef.view.viewport.height);
4222         }
4223
4224         // we can't trust r_refdef.view.forward and friends in reflected scenes
4225         Matrix4x4_ToVectors(&r_refdef.view.matrix, forward, left, up, origin);
4226
4227 #if 0
4228         r_refdef.view.frustum[0].normal[0] = 0 - 1.0 / r_refdef.view.frustum_x;
4229         r_refdef.view.frustum[0].normal[1] = 0 - 0;
4230         r_refdef.view.frustum[0].normal[2] = -1 - 0;
4231         r_refdef.view.frustum[1].normal[0] = 0 + 1.0 / r_refdef.view.frustum_x;
4232         r_refdef.view.frustum[1].normal[1] = 0 + 0;
4233         r_refdef.view.frustum[1].normal[2] = -1 + 0;
4234         r_refdef.view.frustum[2].normal[0] = 0 - 0;
4235         r_refdef.view.frustum[2].normal[1] = 0 - 1.0 / r_refdef.view.frustum_y;
4236         r_refdef.view.frustum[2].normal[2] = -1 - 0;
4237         r_refdef.view.frustum[3].normal[0] = 0 + 0;
4238         r_refdef.view.frustum[3].normal[1] = 0 + 1.0 / r_refdef.view.frustum_y;
4239         r_refdef.view.frustum[3].normal[2] = -1 + 0;
4240 #endif
4241
4242 #if 0
4243         zNear = r_refdef.nearclip;
4244         nudge = 1.0 - 1.0 / (1<<23);
4245         r_refdef.view.frustum[4].normal[0] = 0 - 0;
4246         r_refdef.view.frustum[4].normal[1] = 0 - 0;
4247         r_refdef.view.frustum[4].normal[2] = -1 - -nudge;
4248         r_refdef.view.frustum[4].dist = 0 - -2 * zNear * nudge;
4249         r_refdef.view.frustum[5].normal[0] = 0 + 0;
4250         r_refdef.view.frustum[5].normal[1] = 0 + 0;
4251         r_refdef.view.frustum[5].normal[2] = -1 + -nudge;
4252         r_refdef.view.frustum[5].dist = 0 + -2 * zNear * nudge;
4253 #endif
4254
4255
4256
4257 #if 0
4258         r_refdef.view.frustum[0].normal[0] = m[3] - m[0];
4259         r_refdef.view.frustum[0].normal[1] = m[7] - m[4];
4260         r_refdef.view.frustum[0].normal[2] = m[11] - m[8];
4261         r_refdef.view.frustum[0].dist = m[15] - m[12];
4262
4263         r_refdef.view.frustum[1].normal[0] = m[3] + m[0];
4264         r_refdef.view.frustum[1].normal[1] = m[7] + m[4];
4265         r_refdef.view.frustum[1].normal[2] = m[11] + m[8];
4266         r_refdef.view.frustum[1].dist = m[15] + m[12];
4267
4268         r_refdef.view.frustum[2].normal[0] = m[3] - m[1];
4269         r_refdef.view.frustum[2].normal[1] = m[7] - m[5];
4270         r_refdef.view.frustum[2].normal[2] = m[11] - m[9];
4271         r_refdef.view.frustum[2].dist = m[15] - m[13];
4272
4273         r_refdef.view.frustum[3].normal[0] = m[3] + m[1];
4274         r_refdef.view.frustum[3].normal[1] = m[7] + m[5];
4275         r_refdef.view.frustum[3].normal[2] = m[11] + m[9];
4276         r_refdef.view.frustum[3].dist = m[15] + m[13];
4277
4278         r_refdef.view.frustum[4].normal[0] = m[3] - m[2];
4279         r_refdef.view.frustum[4].normal[1] = m[7] - m[6];
4280         r_refdef.view.frustum[4].normal[2] = m[11] - m[10];
4281         r_refdef.view.frustum[4].dist = m[15] - m[14];
4282
4283         r_refdef.view.frustum[5].normal[0] = m[3] + m[2];
4284         r_refdef.view.frustum[5].normal[1] = m[7] + m[6];
4285         r_refdef.view.frustum[5].normal[2] = m[11] + m[10];
4286         r_refdef.view.frustum[5].dist = m[15] + m[14];
4287 #endif
4288
4289         if (r_refdef.view.useperspective)
4290         {
4291                 // calculate frustum corners, which are used to calculate deformed frustum planes for shadow caster culling
4292                 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]);
4293                 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]);
4294                 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]);
4295                 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]);
4296
4297                 // then the normals from the corners relative to origin
4298                 CrossProduct(r_refdef.view.frustumcorner[2], r_refdef.view.frustumcorner[0], r_refdef.view.frustum[0].normal);
4299                 CrossProduct(r_refdef.view.frustumcorner[1], r_refdef.view.frustumcorner[3], r_refdef.view.frustum[1].normal);
4300                 CrossProduct(r_refdef.view.frustumcorner[0], r_refdef.view.frustumcorner[1], r_refdef.view.frustum[2].normal);
4301                 CrossProduct(r_refdef.view.frustumcorner[3], r_refdef.view.frustumcorner[2], r_refdef.view.frustum[3].normal);
4302
4303                 // in a NORMAL view, forward cross left == up
4304                 // in a REFLECTED view, forward cross left == down
4305                 // so our cross products above need to be adjusted for a left handed coordinate system
4306                 CrossProduct(forward, left, v);
4307                 if(DotProduct(v, up) < 0)
4308                 {
4309                         VectorNegate(r_refdef.view.frustum[0].normal, r_refdef.view.frustum[0].normal);
4310                         VectorNegate(r_refdef.view.frustum[1].normal, r_refdef.view.frustum[1].normal);
4311                         VectorNegate(r_refdef.view.frustum[2].normal, r_refdef.view.frustum[2].normal);
4312                         VectorNegate(r_refdef.view.frustum[3].normal, r_refdef.view.frustum[3].normal);
4313                 }
4314
4315                 // Leaving those out was a mistake, those were in the old code, and they
4316                 // fix a reproducable bug in this one: frustum culling got fucked up when viewmatrix was an identity matrix
4317                 // I couldn't reproduce it after adding those normalizations. --blub
4318                 VectorNormalize(r_refdef.view.frustum[0].normal);
4319                 VectorNormalize(r_refdef.view.frustum[1].normal);
4320                 VectorNormalize(r_refdef.view.frustum[2].normal);
4321                 VectorNormalize(r_refdef.view.frustum[3].normal);
4322
4323                 // make the corners absolute
4324                 VectorAdd(r_refdef.view.frustumcorner[0], r_refdef.view.origin, r_refdef.view.frustumcorner[0]);
4325                 VectorAdd(r_refdef.view.frustumcorner[1], r_refdef.view.origin, r_refdef.view.frustumcorner[1]);
4326                 VectorAdd(r_refdef.view.frustumcorner[2], r_refdef.view.origin, r_refdef.view.frustumcorner[2]);
4327                 VectorAdd(r_refdef.view.frustumcorner[3], r_refdef.view.origin, r_refdef.view.frustumcorner[3]);
4328
4329                 // one more normal
4330                 VectorCopy(forward, r_refdef.view.frustum[4].normal);
4331
4332                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal);
4333                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal);
4334                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal);
4335                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal);
4336                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) + r_refdef.nearclip;
4337         }
4338         else
4339         {
4340                 VectorScale(left, -1.0f, r_refdef.view.frustum[0].normal);
4341                 VectorScale(left,  1.0f, r_refdef.view.frustum[1].normal);
4342                 VectorScale(up, -1.0f, r_refdef.view.frustum[2].normal);
4343                 VectorScale(up,  1.0f, r_refdef.view.frustum[3].normal);
4344                 VectorScale(forward, -1.0f, r_refdef.view.frustum[4].normal);
4345                 r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[0].normal) - r_refdef.view.ortho_x;
4346                 r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[1].normal) - r_refdef.view.ortho_x;
4347                 r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[2].normal) - r_refdef.view.ortho_y;
4348                 r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[3].normal) - r_refdef.view.ortho_y;
4349                 r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, r_refdef.view.frustum[4].normal) - r_refdef.farclip;
4350         }
4351         r_refdef.view.numfrustumplanes = 5;
4352
4353         if (r_refdef.view.useclipplane)
4354         {
4355                 r_refdef.view.numfrustumplanes = 6;
4356                 r_refdef.view.frustum[5] = r_refdef.view.clipplane;
4357         }
4358
4359         for (i = 0;i < r_refdef.view.numfrustumplanes;i++)
4360                 PlaneClassify(r_refdef.view.frustum + i);
4361
4362         // LadyHavoc: note to all quake engine coders, Quake had a special case
4363         // for 90 degrees which assumed a square view (wrong), so I removed it,
4364         // Quake2 has it disabled as well.
4365
4366         // rotate R_VIEWFORWARD right by FOV_X/2 degrees
4367         //RotatePointAroundVector( r_refdef.view.frustum[0].normal, up, forward, -(90 - r_refdef.fov_x / 2));
4368         //r_refdef.view.frustum[0].dist = DotProduct (r_refdef.view.origin, frustum[0].normal);
4369         //PlaneClassify(&frustum[0]);
4370
4371         // rotate R_VIEWFORWARD left by FOV_X/2 degrees
4372         //RotatePointAroundVector( r_refdef.view.frustum[1].normal, up, forward, (90 - r_refdef.fov_x / 2));
4373         //r_refdef.view.frustum[1].dist = DotProduct (r_refdef.view.origin, frustum[1].normal);
4374         //PlaneClassify(&frustum[1]);
4375
4376         // rotate R_VIEWFORWARD up by FOV_X/2 degrees
4377         //RotatePointAroundVector( r_refdef.view.frustum[2].normal, left, forward, -(90 - r_refdef.fov_y / 2));
4378         //r_refdef.view.frustum[2].dist = DotProduct (r_refdef.view.origin, frustum[2].normal);
4379         //PlaneClassify(&frustum[2]);
4380
4381         // rotate R_VIEWFORWARD down by FOV_X/2 degrees
4382         //RotatePointAroundVector( r_refdef.view.frustum[3].normal, left, forward, (90 - r_refdef.fov_y / 2));
4383         //r_refdef.view.frustum[3].dist = DotProduct (r_refdef.view.origin, frustum[3].normal);
4384         //PlaneClassify(&frustum[3]);
4385
4386         // nearclip plane
4387         //VectorCopy(forward, r_refdef.view.frustum[4].normal);
4388         //r_refdef.view.frustum[4].dist = DotProduct (r_refdef.view.origin, frustum[4].normal) + r_nearclip.value;
4389         //PlaneClassify(&frustum[4]);
4390 }
4391
4392 static void R_View_UpdateWithScissor(const int *myscissor)
4393 {
4394         R_Main_ResizeViewCache();
4395         R_View_SetFrustum(myscissor);
4396         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4397         R_View_UpdateEntityVisible();
4398 }
4399
4400 static void R_View_Update(void)
4401 {
4402         R_Main_ResizeViewCache();
4403         R_View_SetFrustum(NULL);
4404         R_View_WorldVisibility(!r_refdef.view.usevieworiginculling);
4405         R_View_UpdateEntityVisible();
4406 }
4407
4408 float viewscalefpsadjusted = 1.0f;
4409
4410 void R_SetupView(qbool allowwaterclippingplane, int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4411 {
4412         const float *customclipplane = NULL;
4413         float plane[4];
4414         int /*rtwidth,*/ rtheight;
4415         if (r_refdef.view.useclipplane && allowwaterclippingplane)
4416         {
4417                 // LadyHavoc: couldn't figure out how to make this approach work the same in DPSOFTRAST
4418                 vec_t dist = r_refdef.view.clipplane.dist - r_water_clippingplanebias.value;
4419                 vec_t viewdist = DotProduct(r_refdef.view.origin, r_refdef.view.clipplane.normal);
4420                 if (viewdist < r_refdef.view.clipplane.dist + r_water_clippingplanebias.value)
4421                         dist = r_refdef.view.clipplane.dist;
4422                 plane[0] = r_refdef.view.clipplane.normal[0];
4423                 plane[1] = r_refdef.view.clipplane.normal[1];
4424                 plane[2] = r_refdef.view.clipplane.normal[2];
4425                 plane[3] = -dist;
4426                 customclipplane = plane;
4427         }
4428
4429         //rtwidth = viewfbo ? R_TextureWidth(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.width;
4430         rtheight = viewfbo ? R_TextureHeight(viewdepthtexture ? viewdepthtexture : viewcolortexture) : vid.height;
4431
4432         if (!r_refdef.view.useperspective)
4433                 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);
4434         else if (vid.stencil && r_useinfinitefarclip.integer)
4435                 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);
4436         else
4437                 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);
4438         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4439         R_SetViewport(&r_refdef.view.viewport);
4440 }
4441
4442 void R_EntityMatrix(const matrix4x4_t *matrix)
4443 {
4444         if (gl_modelmatrixchanged || memcmp(matrix, &gl_modelmatrix, sizeof(matrix4x4_t)))
4445         {
4446                 gl_modelmatrixchanged = false;
4447                 gl_modelmatrix = *matrix;
4448                 Matrix4x4_Concat(&gl_modelviewmatrix, &gl_viewmatrix, &gl_modelmatrix);
4449                 Matrix4x4_Concat(&gl_modelviewprojectionmatrix, &gl_projectionmatrix, &gl_modelviewmatrix);
4450                 Matrix4x4_ToArrayFloatGL(&gl_modelviewmatrix, gl_modelview16f);
4451                 Matrix4x4_ToArrayFloatGL(&gl_modelviewprojectionmatrix, gl_modelviewprojection16f);
4452                 CHECKGLERROR
4453                 switch(vid.renderpath)
4454                 {
4455                 case RENDERPATH_GL32:
4456                 case RENDERPATH_GLES2:
4457                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewProjectionMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewProjectionMatrix, 1, false, gl_modelviewprojection16f);
4458                         if (r_glsl_permutation && r_glsl_permutation->loc_ModelViewMatrix >= 0) qglUniformMatrix4fv(r_glsl_permutation->loc_ModelViewMatrix, 1, false, gl_modelview16f);
4459                         break;
4460                 }
4461         }
4462 }
4463
4464 void R_ResetViewRendering2D_Common(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight, float x2, float y2)
4465 {
4466         r_viewport_t viewport;
4467
4468         CHECKGLERROR
4469
4470         // GL is weird because it's bottom to top, r_refdef.view.y is top to bottom
4471         R_Viewport_InitOrtho(&viewport, &identitymatrix, viewx, vid.height - viewheight - viewy, viewwidth, viewheight, 0, 0, x2, y2, -10, 100, NULL);
4472         R_Mesh_SetRenderTargets(viewfbo, viewdepthtexture, viewcolortexture, NULL, NULL, NULL);
4473         R_SetViewport(&viewport);
4474         GL_Scissor(viewport.x, viewport.y, viewport.width, viewport.height);
4475         GL_Color(1, 1, 1, 1);
4476         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4477         GL_BlendFunc(GL_ONE, GL_ZERO);
4478         GL_ScissorTest(false);
4479         GL_DepthMask(false);
4480         GL_DepthRange(0, 1);
4481         GL_DepthTest(false);
4482         GL_DepthFunc(GL_LEQUAL);
4483         R_EntityMatrix(&identitymatrix);
4484         R_Mesh_ResetTextureState();
4485         GL_PolygonOffset(0, 0);
4486         switch(vid.renderpath)
4487         {
4488         case RENDERPATH_GL32:
4489         case RENDERPATH_GLES2:
4490                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4491                 break;
4492         }
4493         GL_CullFace(GL_NONE);
4494
4495         CHECKGLERROR
4496 }
4497
4498 void R_ResetViewRendering2D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4499 {
4500         R_ResetViewRendering2D_Common(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight, 1.0f, 1.0f);
4501 }
4502
4503 void R_ResetViewRendering3D(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
4504 {
4505         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
4506         GL_Scissor(r_refdef.view.viewport.x, r_refdef.view.viewport.y, r_refdef.view.viewport.width, r_refdef.view.viewport.height);
4507         GL_Color(1, 1, 1, 1);
4508         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
4509         GL_BlendFunc(GL_ONE, GL_ZERO);
4510         GL_ScissorTest(true);
4511         GL_DepthMask(true);
4512         GL_DepthRange(0, 1);
4513         GL_DepthTest(true);
4514         GL_DepthFunc(GL_LEQUAL);
4515         R_EntityMatrix(&identitymatrix);
4516         R_Mesh_ResetTextureState();
4517         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
4518         switch(vid.renderpath)
4519         {
4520         case RENDERPATH_GL32:
4521         case RENDERPATH_GLES2:
4522                 qglEnable(GL_POLYGON_OFFSET_FILL);CHECKGLERROR
4523                 break;
4524         }
4525         GL_CullFace(r_refdef.view.cullface_back);
4526 }
4527
4528 /*
4529 ================
4530 R_RenderView_UpdateViewVectors
4531 ================
4532 */
4533 void R_RenderView_UpdateViewVectors(void)
4534 {
4535         // break apart the view matrix into vectors for various purposes
4536         // it is important that this occurs outside the RenderScene function because that can be called from reflection renders, where the vectors come out wrong
4537         // however the r_refdef.view.origin IS updated in RenderScene intentionally - otherwise the sky renders at the wrong origin, etc
4538         Matrix4x4_ToVectors(&r_refdef.view.matrix, r_refdef.view.forward, r_refdef.view.left, r_refdef.view.up, r_refdef.view.origin);
4539         VectorNegate(r_refdef.view.left, r_refdef.view.right);
4540         // make an inverted copy of the view matrix for tracking sprites
4541         Matrix4x4_Invert_Full(&r_refdef.view.inverse_matrix, &r_refdef.view.matrix);
4542 }
4543
4544 void R_RenderTarget_FreeUnused(qbool force)
4545 {
4546         unsigned int i, j, end;
4547         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4548         for (i = 0; i < end; i++)
4549         {
4550                 r_rendertarget_t *r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4551                 // free resources for rendertargets that have not been used for a while
4552                 // (note: this check is run after the frame render, so any targets used
4553                 // this frame will not be affected even at low framerates)
4554                 if (r && (host.realtime - r->lastusetime > 0.2 || force))
4555                 {
4556                         if (r->fbo)
4557                                 R_Mesh_DestroyFramebufferObject(r->fbo);
4558                         for (j = 0; j < sizeof(r->colortexture) / sizeof(r->colortexture[0]); j++)
4559                                 if (r->colortexture[j])
4560                                         R_FreeTexture(r->colortexture[j]);
4561                         if (r->depthtexture)
4562                                 R_FreeTexture(r->depthtexture);
4563                         Mem_ExpandableArray_FreeRecord(&r_fb.rendertargets, r);
4564                 }
4565         }
4566 }
4567
4568 static void R_CalcTexCoordsForView(float x, float y, float w, float h, float tw, float th, float *texcoord2f)
4569 {
4570         float iw = 1.0f / tw, ih = 1.0f / th, x1, y1, x2, y2;
4571         x1 = x * iw;
4572         x2 = (x + w) * iw;
4573         y1 = (th - y) * ih;
4574         y2 = (th - y - h) * ih;
4575         texcoord2f[0] = x1;
4576         texcoord2f[2] = x2;
4577         texcoord2f[4] = x2;
4578         texcoord2f[6] = x1;
4579         texcoord2f[1] = y1;
4580         texcoord2f[3] = y1;
4581         texcoord2f[5] = y2;
4582         texcoord2f[7] = y2;
4583 }
4584
4585 r_rendertarget_t *R_RenderTarget_Get(int texturewidth, int textureheight, textype_t depthtextype, qbool depthisrenderbuffer, textype_t colortextype0, textype_t colortextype1, textype_t colortextype2, textype_t colortextype3)
4586 {
4587         unsigned int i, j, end;
4588         r_rendertarget_t *r = NULL;
4589         char vabuf[256];
4590         // first try to reuse an existing slot if possible
4591         end = (unsigned int)Mem_ExpandableArray_IndexRange(&r_fb.rendertargets); // checked
4592         for (i = 0; i < end; i++)
4593         {
4594                 r = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, i);
4595                 if (r && r->lastusetime != host.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)
4596                         break;
4597         }
4598         if (i == end)
4599         {
4600                 // no unused exact match found, so we have to make one in the first unused slot
4601                 r = (r_rendertarget_t *)Mem_ExpandableArray_AllocRecord(&r_fb.rendertargets);
4602                 r->texturewidth = texturewidth;
4603                 r->textureheight = textureheight;
4604                 r->colortextype[0] = colortextype0;
4605                 r->colortextype[1] = colortextype1;
4606                 r->colortextype[2] = colortextype2;
4607                 r->colortextype[3] = colortextype3;
4608                 r->depthtextype = depthtextype;
4609                 r->depthisrenderbuffer = depthisrenderbuffer;
4610                 for (j = 0; j < 4; j++)
4611                         if (r->colortextype[j])
4612                                 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);
4613                 if (r->depthtextype)
4614                 {
4615                         if (r->depthisrenderbuffer)
4616                                 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);
4617                         else
4618                                 r->depthtexture = R_LoadTexture2D(r_main_texturepool, va(vabuf, sizeof(vabuf), "rendertarget%i_depth_type%i", i, (int)r->depthtextype), r->texturewidth, r->textureheight, NULL, r->depthtextype, TEXF_RENDERTARGET | TEXF_FORCELINEAR | TEXF_CLAMP, -1, NULL);
4619                 }
4620                 r->fbo = R_Mesh_CreateFramebufferObject(r->depthtexture, r->colortexture[0], r->colortexture[1], r->colortexture[2], r->colortexture[3]);
4621         }
4622         r_refdef.stats[r_stat_rendertargets_used]++;
4623         r_refdef.stats[r_stat_rendertargets_pixels] += r->texturewidth * r->textureheight;
4624         r->lastusetime = host.realtime;
4625         R_CalcTexCoordsForView(0, 0, r->texturewidth, r->textureheight, r->texturewidth, r->textureheight, r->texcoord2f);
4626         return r;
4627 }
4628
4629 static void R_Water_StartFrame(int viewwidth, int viewheight)
4630 {
4631         int waterwidth, waterheight;
4632
4633         if (viewwidth > (int)vid.maxtexturesize_2d || viewheight > (int)vid.maxtexturesize_2d)
4634                 return;
4635
4636         // set waterwidth and waterheight to the water resolution that will be
4637         // used (often less than the screen resolution for faster rendering)
4638         waterwidth = (int)bound(16, viewwidth * r_water_resolutionmultiplier.value, viewwidth);
4639         waterheight = (int)bound(16, viewheight * r_water_resolutionmultiplier.value, viewheight);
4640
4641         if (!r_water.integer || r_showsurfaces.integer || r_lockvisibility.integer || r_lockpvs.integer)
4642                 waterwidth = waterheight = 0;
4643
4644         // set up variables that will be used in shader setup
4645         r_fb.water.waterwidth = waterwidth;
4646         r_fb.water.waterheight = waterheight;
4647         r_fb.water.texturewidth = waterwidth;
4648         r_fb.water.textureheight = waterheight;
4649         r_fb.water.camerawidth = waterwidth;
4650         r_fb.water.cameraheight = waterheight;
4651         r_fb.water.screenscale[0] = 0.5f;
4652         r_fb.water.screenscale[1] = 0.5f;
4653         r_fb.water.screencenter[0] = 0.5f;
4654         r_fb.water.screencenter[1] = 0.5f;
4655         r_fb.water.enabled = waterwidth != 0;
4656
4657         r_fb.water.maxwaterplanes = MAX_WATERPLANES;
4658         r_fb.water.numwaterplanes = 0;
4659 }
4660
4661 void R_Water_AddWaterPlane(msurface_t *surface, int entno)
4662 {
4663         int planeindex, bestplaneindex, vertexindex;
4664         vec3_t mins, maxs, normal, center, v, n;
4665         vec_t planescore, bestplanescore;
4666         mplane_t plane;
4667         r_waterstate_waterplane_t *p;
4668         texture_t *t = R_GetCurrentTexture(surface->texture);
4669
4670         rsurface.texture = t;
4671         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_NOGAPS, 1, ((const msurface_t **)&surface));
4672         // if the model has no normals, it's probably off-screen and they were not generated, so don't add it anyway
4673         if (!rsurface.batchnormal3f || rsurface.batchnumvertices < 1)
4674                 return;
4675         // average the vertex normals, find the surface bounds (after deformvertexes)
4676         Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f, v);
4677         Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f, n);
4678         VectorCopy(n, normal);
4679         VectorCopy(v, mins);
4680         VectorCopy(v, maxs);
4681         for (vertexindex = 1;vertexindex < rsurface.batchnumvertices;vertexindex++)
4682         {
4683                 Matrix4x4_Transform(&rsurface.matrix, rsurface.batchvertex3f + vertexindex*3, v);
4684                 Matrix4x4_Transform3x3(&rsurface.matrix, rsurface.batchnormal3f + vertexindex*3, n);
4685                 VectorAdd(normal, n, normal);
4686                 mins[0] = min(mins[0], v[0]);
4687                 mins[1] = min(mins[1], v[1]);
4688                 mins[2] = min(mins[2], v[2]);
4689                 maxs[0] = max(maxs[0], v[0]);
4690                 maxs[1] = max(maxs[1], v[1]);
4691                 maxs[2] = max(maxs[2], v[2]);
4692         }
4693         VectorNormalize(normal);
4694         VectorMAM(0.5f, mins, 0.5f, maxs, center);
4695
4696         VectorCopy(normal, plane.normal);
4697         VectorNormalize(plane.normal);
4698         plane.dist = DotProduct(center, plane.normal);
4699         PlaneClassify(&plane);
4700         if (PlaneDiff(r_refdef.view.origin, &plane) < 0)
4701         {
4702                 // skip backfaces (except if nocullface is set)
4703 //              if (!(t->currentmaterialflags & MATERIALFLAG_NOCULLFACE))
4704 //                      return;
4705                 VectorNegate(plane.normal, plane.normal);
4706                 plane.dist *= -1;
4707                 PlaneClassify(&plane);
4708         }
4709
4710
4711         // find a matching plane if there is one
4712         bestplaneindex = -1;
4713         bestplanescore = 1048576.0f;
4714         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4715         {
4716                 if(p->camera_entity == t->camera_entity)
4717                 {
4718                         planescore = 1.0f - DotProduct(plane.normal, p->plane.normal) + fabs(plane.dist - p->plane.dist) * 0.001f;
4719                         if (bestplaneindex < 0 || bestplanescore > planescore)
4720                         {
4721                                 bestplaneindex = planeindex;
4722                                 bestplanescore = planescore;
4723                         }
4724                 }
4725         }
4726         planeindex = bestplaneindex;
4727
4728         // if this surface does not fit any known plane rendered this frame, add one
4729         if (planeindex < 0 || bestplanescore > 0.001f)
4730         {
4731                 if (r_fb.water.numwaterplanes < r_fb.water.maxwaterplanes)
4732                 {
4733                         // store the new plane
4734                         planeindex = r_fb.water.numwaterplanes++;
4735                         p = r_fb.water.waterplanes + planeindex;
4736                         p->plane = plane;
4737                         // clear materialflags and pvs
4738                         p->materialflags = 0;
4739                         p->pvsvalid = false;
4740                         p->camera_entity = t->camera_entity;
4741                         VectorCopy(mins, p->mins);
4742                         VectorCopy(maxs, p->maxs);
4743                 }
4744                 else
4745                 {
4746                         // We're totally screwed.
4747                         return;
4748                 }
4749         }
4750         else
4751         {
4752                 // merge mins/maxs when we're adding this surface to the plane
4753                 p = r_fb.water.waterplanes + planeindex;
4754                 p->mins[0] = min(p->mins[0], mins[0]);
4755                 p->mins[1] = min(p->mins[1], mins[1]);
4756                 p->mins[2] = min(p->mins[2], mins[2]);
4757                 p->maxs[0] = max(p->maxs[0], maxs[0]);
4758                 p->maxs[1] = max(p->maxs[1], maxs[1]);
4759                 p->maxs[2] = max(p->maxs[2], maxs[2]);
4760         }
4761         // merge this surface's materialflags into the waterplane
4762         p->materialflags |= t->currentmaterialflags;
4763         if(!(p->materialflags & MATERIALFLAG_CAMERA))
4764         {
4765                 // merge this surface's PVS into the waterplane
4766                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION) && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS
4767                  && r_refdef.scene.worldmodel->brush.PointInLeaf && r_refdef.scene.worldmodel->brush.PointInLeaf(r_refdef.scene.worldmodel, center)->clusterindex >= 0)
4768                 {
4769                         r_refdef.scene.worldmodel->brush.FatPVS(r_refdef.scene.worldmodel, center, 2, p->pvsbits, sizeof(p->pvsbits), p->pvsvalid);
4770                         p->pvsvalid = true;
4771                 }
4772         }
4773 }
4774
4775 extern cvar_t r_drawparticles;
4776 extern cvar_t r_drawdecals;
4777
4778 static void R_Water_ProcessPlanes(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int viewx, int viewy, int viewwidth, int viewheight)
4779 {
4780         int myscissor[4];
4781         r_refdef_view_t originalview;
4782         r_refdef_view_t myview;
4783         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;
4784         r_waterstate_waterplane_t *p;
4785         vec3_t visorigin;
4786         r_rendertarget_t *rt;
4787
4788         originalview = r_refdef.view;
4789
4790         // lowquality hack, temporarily shut down some cvars and restore afterwards
4791         qualityreduction = r_water_lowquality.integer;
4792         if (qualityreduction > 0)
4793         {
4794                 if (qualityreduction >= 1)
4795                 {
4796                         old_r_shadows = r_shadows.integer;
4797                         old_r_worldrtlight = r_shadow_realtime_world.integer;
4798                         old_r_dlight = r_shadow_realtime_dlight.integer;
4799                         Cvar_SetValueQuick(&r_shadows, 0);
4800                         Cvar_SetValueQuick(&r_shadow_realtime_world, 0);
4801                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, 0);
4802                 }
4803                 if (qualityreduction >= 2)
4804                 {
4805                         old_r_dynamic = r_dynamic.integer;
4806                         old_r_particles = r_drawparticles.integer;
4807                         old_r_decals = r_drawdecals.integer;
4808                         Cvar_SetValueQuick(&r_dynamic, 0);
4809                         Cvar_SetValueQuick(&r_drawparticles, 0);
4810                         Cvar_SetValueQuick(&r_drawdecals, 0);
4811                 }
4812         }
4813
4814         for (planeindex = 0, p = r_fb.water.waterplanes; planeindex < r_fb.water.numwaterplanes; planeindex++, p++)
4815         {
4816                 p->rt_reflection = NULL;
4817                 p->rt_refraction = NULL;
4818                 p->rt_camera = NULL;
4819         }
4820
4821         // render views
4822         r_refdef.view = originalview;
4823         r_refdef.view.showdebug = false;
4824         r_refdef.view.width = r_fb.water.waterwidth;
4825         r_refdef.view.height = r_fb.water.waterheight;
4826         r_refdef.view.useclipplane = true;
4827         myview = r_refdef.view;
4828         r_fb.water.renderingscene = true;
4829         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
4830         {
4831                 if (r_water_cameraentitiesonly.value != 0 && !p->camera_entity)
4832                         continue;
4833
4834                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION))
4835                 {
4836                         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);
4837                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4838                                 goto error;
4839                         r_refdef.view = myview;
4840                         Matrix4x4_Reflect(&r_refdef.view.matrix, p->plane.normal[0], p->plane.normal[1], p->plane.normal[2], p->plane.dist, -2);
4841                         Matrix4x4_OriginFromMatrix(&r_refdef.view.matrix, r_refdef.view.origin);
4842                         if(r_water_scissormode.integer)
4843                         {
4844                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4845                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4846                                 {
4847                                         p->rt_reflection = NULL;
4848                                         p->rt_refraction = NULL;
4849                                         p->rt_camera = NULL;
4850                                         continue;
4851                                 }
4852                         }
4853
4854                         r_refdef.view.clipplane = p->plane;
4855                         // reflected view origin may be in solid, so don't cull with it
4856                         r_refdef.view.usevieworiginculling = false;
4857                         // reverse the cullface settings for this render
4858                         r_refdef.view.cullface_front = GL_FRONT;
4859                         r_refdef.view.cullface_back = GL_BACK;
4860                         // combined pvs (based on what can be seen from each surface center)
4861                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4862                         {
4863                                 r_refdef.view.usecustompvs = true;
4864                                 if (p->pvsvalid)
4865                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4866                                 else
4867                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4868                         }
4869
4870                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 2) && !chase_active.integer);
4871                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4872                         GL_ScissorTest(false);
4873                         R_ClearScreen(r_refdef.fogenabled);
4874                         GL_ScissorTest(true);
4875                         if(r_water_scissormode.integer & 2)
4876                                 R_View_UpdateWithScissor(myscissor);
4877                         else
4878                                 R_View_Update();
4879                         R_AnimCache_CacheVisibleEntities();
4880                         if(r_water_scissormode.integer & 1)
4881                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4882                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4883
4884                         r_fb.water.hideplayer = false;
4885                         p->rt_reflection = rt;
4886                 }
4887
4888                 // render the normal view scene and copy into texture
4889                 // (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)
4890                 if (p->materialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
4891                 {
4892                         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);
4893                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4894                                 goto error;
4895                         r_refdef.view = myview;
4896                         if(r_water_scissormode.integer)
4897                         {
4898                                 R_SetupView(true, rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, r_fb.water.waterwidth, r_fb.water.waterheight);
4899                                 if (R_ScissorForBBox(p->mins, p->maxs, myscissor))
4900                                 {
4901                                         p->rt_reflection = NULL;
4902                                         p->rt_refraction = NULL;
4903                                         p->rt_camera = NULL;
4904                                         continue;
4905                                 }
4906                         }
4907
4908                         // combined pvs (based on what can be seen from each surface center)
4909                         if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.num_pvsclusterbytes)
4910                         {
4911                                 r_refdef.view.usecustompvs = true;
4912                                 if (p->pvsvalid)
4913                                         memcpy(r_refdef.viewcache.world_pvsbits, p->pvsbits, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4914                                 else
4915                                         memset(r_refdef.viewcache.world_pvsbits, 0xFF, r_refdef.scene.worldmodel->brush.num_pvsclusterbytes);
4916                         }
4917
4918                         r_fb.water.hideplayer = ((r_water_hideplayer.integer >= 1) && !chase_active.integer);
4919
4920                         r_refdef.view.clipplane = p->plane;
4921                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
4922                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
4923
4924                         if((p->materialflags & MATERIALFLAG_CAMERA) && p->camera_entity)
4925                         {
4926                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
4927                                 r_fb.water.hideplayer = false; // we don't want to hide the player model from these ones
4928                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
4929                                 R_RenderView_UpdateViewVectors();
4930                                 if(r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
4931                                 {
4932                                         r_refdef.view.usecustompvs = true;
4933                                         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);
4934                                 }
4935                         }
4936
4937                         PlaneClassify(&r_refdef.view.clipplane);
4938
4939                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4940                         GL_ScissorTest(false);
4941                         R_ClearScreen(r_refdef.fogenabled);
4942                         GL_ScissorTest(true);
4943                         if(r_water_scissormode.integer & 2)
4944                                 R_View_UpdateWithScissor(myscissor);
4945                         else
4946                                 R_View_Update();
4947                         R_AnimCache_CacheVisibleEntities();
4948                         if(r_water_scissormode.integer & 1)
4949                                 GL_Scissor(myscissor[0], myscissor[1], myscissor[2], myscissor[3]);
4950                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
4951
4952                         r_fb.water.hideplayer = false;
4953                         p->rt_refraction = rt;
4954                 }
4955                 else if (p->materialflags & MATERIALFLAG_CAMERA)
4956                 {
4957                         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);
4958                         if (rt->colortexture[0] == NULL || rt->depthtexture == NULL)
4959                                 goto error;
4960                         r_refdef.view = myview;
4961
4962                         r_refdef.view.clipplane = p->plane;
4963                         VectorNegate(r_refdef.view.clipplane.normal, r_refdef.view.clipplane.normal);
4964                         r_refdef.view.clipplane.dist = -r_refdef.view.clipplane.dist;
4965
4966                         r_refdef.view.width = r_fb.water.camerawidth;
4967                         r_refdef.view.height = r_fb.water.cameraheight;
4968                         r_refdef.view.frustum_x = 1; // tan(45 * M_PI / 180.0);
4969                         r_refdef.view.frustum_y = 1; // tan(45 * M_PI / 180.0);
4970                         r_refdef.view.ortho_x = 90; // abused as angle by VM_CL_R_SetView
4971                         r_refdef.view.ortho_y = 90; // abused as angle by VM_CL_R_SetView
4972
4973                         if(p->camera_entity)
4974                         {
4975                                 // we need to perform a matrix transform to render the view... so let's get the transformation matrix
4976                                 CL_VM_TransformView(p->camera_entity - MAX_EDICTS, &r_refdef.view.matrix, &r_refdef.view.clipplane, visorigin);
4977                         }
4978
4979                         // note: all of the view is used for displaying... so
4980                         // there is no use in scissoring
4981
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                         // also reverse the view matrix
4986                         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
4987                         R_RenderView_UpdateViewVectors();
4988                         if(p->camera_entity && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->brush.FatPVS)
4989                         {
4990                                 r_refdef.view.usecustompvs = true;
4991                                 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);
4992                         }
4993                         
4994                         // camera needs no clipplane
4995                         r_refdef.view.useclipplane = false;
4996                         // TODO: is the camera origin always valid?  if so we don't need to clear this
4997                         r_refdef.view.usevieworiginculling = false;
4998
4999                         PlaneClassify(&r_refdef.view.clipplane);
5000
5001                         r_fb.water.hideplayer = false;
5002
5003                         R_ResetViewRendering3D(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5004                         GL_ScissorTest(false);
5005                         R_ClearScreen(r_refdef.fogenabled);
5006                         GL_ScissorTest(true);
5007                         R_View_Update();
5008                         R_AnimCache_CacheVisibleEntities();
5009                         R_RenderScene(rt->fbo, rt->depthtexture, rt->colortexture[0], 0, 0, rt->texturewidth, rt->textureheight);
5010
5011                         r_fb.water.hideplayer = false;
5012                         p->rt_camera = rt;
5013                 }
5014
5015         }
5016         r_fb.water.renderingscene = false;
5017         r_refdef.view = originalview;
5018         R_ResetViewRendering3D(fbo, depthtexture, colortexture, viewx, viewy, viewwidth, viewheight);
5019         R_View_Update();
5020         R_AnimCache_CacheVisibleEntities();
5021         goto finish;
5022 error:
5023         r_refdef.view = originalview;
5024         r_fb.water.renderingscene = false;
5025         Cvar_SetValueQuick(&r_water, 0);
5026         Con_Printf("R_Water_ProcessPlanes: Error: texture creation failed!  Turned off r_water.\n");
5027 finish:
5028         // lowquality hack, restore cvars
5029         if (qualityreduction > 0)
5030         {
5031                 if (qualityreduction >= 1)
5032                 {
5033                         Cvar_SetValueQuick(&r_shadows, old_r_shadows);
5034                         Cvar_SetValueQuick(&r_shadow_realtime_world, old_r_worldrtlight);
5035                         Cvar_SetValueQuick(&r_shadow_realtime_dlight, old_r_dlight);
5036                 }
5037                 if (qualityreduction >= 2)
5038                 {
5039                         Cvar_SetValueQuick(&r_dynamic, old_r_dynamic);
5040                         Cvar_SetValueQuick(&r_drawparticles, old_r_particles);
5041                         Cvar_SetValueQuick(&r_drawdecals, old_r_decals);
5042                 }
5043         }
5044 }
5045
5046 static void R_Bloom_StartFrame(void)
5047 {
5048         int screentexturewidth, screentextureheight;
5049         textype_t textype = TEXTYPE_COLORBUFFER;
5050         double scale;
5051
5052         // clear the pointers to rendertargets from last frame as they're stale
5053         r_fb.rt_screen = NULL;
5054         r_fb.rt_bloom = NULL;
5055
5056         switch (vid.renderpath)
5057         {
5058         case RENDERPATH_GL32:
5059                 r_fb.usedepthtextures = r_usedepthtextures.integer != 0;
5060                 if (r_viewfbo.integer == 2) textype = TEXTYPE_COLORBUFFER16F;
5061                 if (r_viewfbo.integer == 3) textype = TEXTYPE_COLORBUFFER32F;
5062                 break;
5063         case RENDERPATH_GLES2:
5064                 r_fb.usedepthtextures = false;
5065                 break;
5066         }
5067
5068         if (r_viewscale_fpsscaling.integer)
5069         {
5070                 double actualframetime;
5071                 double targetframetime;
5072                 double adjust;
5073                 actualframetime = r_refdef.lastdrawscreentime;
5074                 targetframetime = (1.0 / r_viewscale_fpsscaling_target.value);
5075                 adjust = (targetframetime - actualframetime) * r_viewscale_fpsscaling_multiply.value;
5076                 adjust = bound(-r_viewscale_fpsscaling_stepmax.value, adjust, r_viewscale_fpsscaling_stepmax.value);
5077                 if (r_viewscale_fpsscaling_stepsize.value > 0)
5078                 {
5079                         if (adjust > 0)
5080                                 adjust = floor(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5081                         else
5082                                 adjust = ceil(adjust / r_viewscale_fpsscaling_stepsize.value) * r_viewscale_fpsscaling_stepsize.value;
5083                 }
5084                 viewscalefpsadjusted += adjust;
5085                 viewscalefpsadjusted = bound(r_viewscale_fpsscaling_min.value, viewscalefpsadjusted, 1.0f);
5086         }
5087         else
5088                 viewscalefpsadjusted = 1.0f;
5089
5090         scale = r_viewscale.value * sqrt(viewscalefpsadjusted);
5091         if (vid.samples)
5092                 scale *= sqrt(vid.samples); // supersampling
5093         scale = bound(0.03125f, scale, 4.0f);
5094         screentexturewidth = (int)ceil(r_refdef.view.width * scale);
5095         screentextureheight = (int)ceil(r_refdef.view.height * scale);
5096         screentexturewidth = bound(1, screentexturewidth, (int)vid.maxtexturesize_2d);
5097         screentextureheight = bound(1, screentextureheight, (int)vid.maxtexturesize_2d);
5098
5099         // set bloomwidth and bloomheight to the bloom resolution that will be
5100         // used (often less than the screen resolution for faster rendering)
5101         r_fb.bloomheight = bound(1, r_bloom_resolution.value * 0.75f, screentextureheight);
5102         r_fb.bloomwidth = r_fb.bloomheight * screentexturewidth / screentextureheight;
5103         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, screentexturewidth);
5104         r_fb.bloomwidth = bound(1, r_fb.bloomwidth, (int)vid.maxtexturesize_2d);
5105         r_fb.bloomheight = bound(1, r_fb.bloomheight, (int)vid.maxtexturesize_2d);
5106
5107         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))
5108         {
5109                 Cvar_SetValueQuick(&r_bloom, 0);
5110                 Cvar_SetValueQuick(&r_motionblur, 0);
5111                 Cvar_SetValueQuick(&r_damageblur, 0);
5112         }
5113         if (!r_bloom.integer)
5114                 r_fb.bloomwidth = r_fb.bloomheight = 0;
5115
5116         // allocate motionblur ghost texture if needed - this is the only persistent texture and is only useful on the main view
5117         if (r_refdef.view.ismain && (r_fb.screentexturewidth != screentexturewidth || r_fb.screentextureheight != screentextureheight || r_fb.textype != textype))
5118         {
5119                 if (r_fb.ghosttexture)
5120                         R_FreeTexture(r_fb.ghosttexture);
5121                 r_fb.ghosttexture = NULL;
5122
5123                 r_fb.screentexturewidth = screentexturewidth;
5124                 r_fb.screentextureheight = screentextureheight;
5125                 r_fb.textype = textype;
5126
5127                 if (r_fb.screentexturewidth && r_fb.screentextureheight)
5128                 {
5129                         if (r_motionblur.value > 0 || r_damageblur.value > 0)
5130                                 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);
5131                         r_fb.ghosttexture_valid = false;
5132                 }
5133         }
5134
5135         r_fb.rt_screen = R_RenderTarget_Get(screentexturewidth, screentextureheight, TEXTYPE_DEPTHBUFFER24STENCIL8, true, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5136
5137         r_refdef.view.clear = true;
5138 }
5139
5140 static void R_Bloom_MakeTexture(void)
5141 {
5142         int x, range, dir;
5143         float xoffset, yoffset, r, brighten;
5144         float colorscale = r_bloom_colorscale.value;
5145         r_viewport_t bloomviewport;
5146         r_rendertarget_t *prev, *cur;
5147         textype_t textype = r_fb.rt_screen->colortextype[0];
5148
5149         r_refdef.stats[r_stat_bloom]++;
5150
5151         R_Viewport_InitOrtho(&bloomviewport, &identitymatrix, 0, 0, r_fb.bloomwidth, r_fb.bloomheight, 0, 0, 1, 1, -10, 100, NULL);
5152
5153         // scale down screen texture to the bloom texture size
5154         CHECKGLERROR
5155         prev = r_fb.rt_screen;
5156         cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5157         R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5158         R_SetViewport(&bloomviewport);
5159         GL_CullFace(GL_NONE);
5160         GL_DepthTest(false);
5161         GL_BlendFunc(GL_ONE, GL_ZERO);
5162         GL_Color(colorscale, colorscale, colorscale, 1);
5163         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5164         // TODO: do boxfilter scale-down in shader?
5165         R_SetupShader_Generic(prev->colortexture[0], false, true, true);
5166         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5167         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5168         // we now have a properly scaled bloom image
5169
5170         // multiply bloom image by itself as many times as desired to darken it
5171         // TODO: if people actually use this it could be done more quickly in the previous shader pass
5172         for (x = 1;x < min(r_bloom_colorexponent.value, 32);)
5173         {
5174                 prev = cur;
5175                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5176                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5177                 x *= 2;
5178                 r = bound(0, r_bloom_colorexponent.value / x, 1); // always 0.5 to 1
5179                 if(x <= 2)
5180                         GL_Clear(GL_COLOR_BUFFER_BIT, NULL, 1.0f, 0);
5181                 GL_BlendFunc(GL_SRC_COLOR, GL_ZERO); // square it
5182                 GL_Color(1,1,1,1); // no fix factor supported here
5183                 R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, prev->texcoord2f);
5184                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5185                 R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5186                 r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5187         }
5188         CHECKGLERROR
5189
5190         range = r_bloom_blur.integer * r_fb.bloomwidth / 320;
5191         brighten = r_bloom_brighten.value;
5192         brighten = sqrt(brighten);
5193         if(range >= 1)
5194                 brighten *= (3 * range) / (2 * range - 1); // compensate for the "dot particle"
5195
5196         for (dir = 0;dir < 2;dir++)
5197         {
5198                 prev = cur;
5199                 cur = R_RenderTarget_Get(r_fb.bloomwidth, r_fb.bloomheight, TEXTYPE_UNUSED, false, textype, TEXTYPE_UNUSED, TEXTYPE_UNUSED, TEXTYPE_UNUSED);
5200                 R_Mesh_SetRenderTargets(cur->fbo, NULL, cur->colortexture[0], NULL, NULL, NULL);
5201                 // blend on at multiple vertical offsets to achieve a vertical blur
5202                 // TODO: do offset blends using GLSL
5203                 // TODO instead of changing the texcoords, change the target positions to prevent artifacts at edges
5204                 CHECKGLERROR
5205                 GL_BlendFunc(GL_ONE, GL_ZERO);
5206                 CHECKGLERROR
5207                 R_SetupShader_Generic(prev->colortexture[0], false, true, false);
5208                 CHECKGLERROR
5209                 for (x = -range;x <= range;x++)
5210                 {
5211                         if (!dir){xoffset = 0;yoffset = x;}
5212                         else {xoffset = x;yoffset = 0;}
5213                         xoffset /= (float)prev->texturewidth;
5214                         yoffset /= (float)prev->textureheight;
5215                         // compute a texcoord array with the specified x and y offset
5216                         r_fb.offsettexcoord2f[0] = xoffset+prev->texcoord2f[0];
5217                         r_fb.offsettexcoord2f[1] = yoffset+prev->texcoord2f[1];
5218                         r_fb.offsettexcoord2f[2] = xoffset+prev->texcoord2f[2];
5219                         r_fb.offsettexcoord2f[3] = yoffset+prev->texcoord2f[3];
5220                         r_fb.offsettexcoord2f[4] = xoffset+prev->texcoord2f[4];
5221                         r_fb.offsettexcoord2f[5] = yoffset+prev->texcoord2f[5];
5222                         r_fb.offsettexcoord2f[6] = xoffset+prev->texcoord2f[6];
5223                         r_fb.offsettexcoord2f[7] = yoffset+prev->texcoord2f[7];
5224                         // this r value looks like a 'dot' particle, fading sharply to
5225                         // black at the edges
5226                         // (probably not realistic but looks good enough)
5227                         //r = ((range*range+1)/((float)(x*x+1)))/(range*2+1);
5228                         //r = brighten/(range*2+1);
5229                         r = brighten / (range * 2 + 1);
5230                         if(range >= 1)
5231                                 r *= (1 - x*x/(float)((range+1)*(range+1)));
5232                         if (r <= 0)
5233                                 continue;
5234                         CHECKGLERROR
5235                         GL_Color(r, r, r, 1);
5236                         CHECKGLERROR
5237                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.offsettexcoord2f);
5238                         CHECKGLERROR
5239                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5240                         r_refdef.stats[r_stat_bloom_drawpixels] += r_fb.bloomwidth * r_fb.bloomheight;
5241                         CHECKGLERROR
5242                         GL_BlendFunc(GL_ONE, GL_ONE);
5243                         CHECKGLERROR
5244                 }
5245         }
5246
5247         // now we have the bloom image, so keep track of it
5248         r_fb.rt_bloom = cur;
5249 }
5250
5251 static void R_BlendView(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5252 {
5253         uint64_t permutation;
5254         float uservecs[4][4];
5255         rtexture_t *viewtexture;
5256         rtexture_t *bloomtexture;
5257
5258         R_EntityMatrix(&identitymatrix);
5259
5260         if(r_refdef.view.ismain && !R_Stereo_Active() && (r_motionblur.value > 0 || r_damageblur.value > 0) && r_fb.ghosttexture)
5261         {
5262                 // declare variables
5263                 float blur_factor, blur_mouseaccel, blur_velocity;
5264                 static float blur_average; 
5265                 static vec3_t blur_oldangles; // used to see how quickly the mouse is moving
5266
5267                 // set a goal for the factoring
5268                 blur_velocity = bound(0, (VectorLength(cl.movement_velocity) - r_motionblur_velocityfactor_minspeed.value) 
5269                         / max(1, r_motionblur_velocityfactor_maxspeed.value - r_motionblur_velocityfactor_minspeed.value), 1);
5270                 blur_mouseaccel = bound(0, ((fabs(VectorLength(cl.viewangles) - VectorLength(blur_oldangles)) * 10) - r_motionblur_mousefactor_minspeed.value) 
5271                         / max(1, r_motionblur_mousefactor_maxspeed.value - r_motionblur_mousefactor_minspeed.value), 1);
5272                 blur_factor = ((blur_velocity * r_motionblur_velocityfactor.value) 
5273                         + (blur_mouseaccel * r_motionblur_mousefactor.value));
5274
5275                 // from the goal, pick an averaged value between goal and last value
5276                 cl.motionbluralpha = bound(0, (cl.time - cl.oldtime) / max(0.001, r_motionblur_averaging.value), 1);
5277                 blur_average = blur_average * (1 - cl.motionbluralpha) + blur_factor * cl.motionbluralpha;
5278
5279                 // enforce minimum amount of blur 
5280                 blur_factor = blur_average * (1 - r_motionblur_minblur.value) + r_motionblur_minblur.value;
5281
5282                 //Con_Printf("motionblur: direct factor: %f, averaged factor: %f, velocity: %f, mouse accel: %f \n", blur_factor, blur_average, blur_velocity, blur_mouseaccel);
5283
5284                 // calculate values into a standard alpha
5285                 cl.motionbluralpha = 1 - exp(-
5286                                 (
5287                                         (r_motionblur.value * blur_factor / 80)
5288                                         +
5289                                         (r_damageblur.value * (cl.cshifts[CSHIFT_DAMAGE].percent / 1600))
5290                                 )
5291                                 /
5292                                 max(0.0001, cl.time - cl.oldtime) // fps independent
5293                                 );
5294
5295                 // randomization for the blur value to combat persistent ghosting
5296                 cl.motionbluralpha *= lhrandom(1 - r_motionblur_randomize.value, 1 + r_motionblur_randomize.value);
5297                 cl.motionbluralpha = bound(0, cl.motionbluralpha, r_motionblur_maxblur.value);
5298
5299                 // apply the blur
5300                 R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5301                 if (cl.motionbluralpha > 0 && !r_refdef.envmap && r_fb.ghosttexture_valid)
5302                 {
5303                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
5304                         GL_Color(1, 1, 1, cl.motionbluralpha);
5305                         R_CalcTexCoordsForView(0, 0, viewwidth, viewheight, viewwidth, viewheight, r_fb.ghosttexcoord2f);
5306                         R_Mesh_PrepareVertices_Generic_Arrays(4, r_screenvertex3f, NULL, r_fb.ghosttexcoord2f);
5307                         R_SetupShader_Generic(r_fb.ghosttexture, false, true, true);
5308                         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5309                         r_refdef.stats[r_stat_bloom_drawpixels] += viewwidth * viewheight;
5310                 }
5311
5312                 // updates old view angles for next pass
5313                 VectorCopy(cl.viewangles, blur_oldangles);
5314
5315                 // copy view into the ghost texture
5316                 R_Mesh_CopyToTexture(r_fb.ghosttexture, 0, 0, viewx, viewy, viewwidth, viewheight);
5317                 r_refdef.stats[r_stat_bloom_copypixels] += viewwidth * viewheight;
5318                 r_fb.ghosttexture_valid = true;
5319         }
5320
5321         if (r_fb.bloomwidth)
5322         {
5323                 // make the bloom texture
5324                 R_Bloom_MakeTexture();
5325         }
5326
5327 #if _MSC_VER >= 1400
5328 #define sscanf sscanf_s
5329 #endif
5330         memset(uservecs, 0, sizeof(uservecs));
5331         if (r_glsl_postprocess_uservec1_enable.integer)
5332                 sscanf(r_glsl_postprocess_uservec1.string, "%f %f %f %f", &uservecs[0][0], &uservecs[0][1], &uservecs[0][2], &uservecs[0][3]);
5333         if (r_glsl_postprocess_uservec2_enable.integer)
5334                 sscanf(r_glsl_postprocess_uservec2.string, "%f %f %f %f", &uservecs[1][0], &uservecs[1][1], &uservecs[1][2], &uservecs[1][3]);
5335         if (r_glsl_postprocess_uservec3_enable.integer)
5336                 sscanf(r_glsl_postprocess_uservec3.string, "%f %f %f %f", &uservecs[2][0], &uservecs[2][1], &uservecs[2][2], &uservecs[2][3]);
5337         if (r_glsl_postprocess_uservec4_enable.integer)
5338                 sscanf(r_glsl_postprocess_uservec4.string, "%f %f %f %f", &uservecs[3][0], &uservecs[3][1], &uservecs[3][2], &uservecs[3][3]);
5339
5340         // render to the screen fbo
5341         R_ResetViewRendering2D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5342         GL_Color(1, 1, 1, 1);
5343         GL_BlendFunc(GL_ONE, GL_ZERO);
5344
5345         viewtexture = r_fb.rt_screen->colortexture[0];
5346         bloomtexture = r_fb.rt_bloom ? r_fb.rt_bloom->colortexture[0] : NULL;
5347
5348         if (r_rendertarget_debug.integer >= 0)
5349         {
5350                 r_rendertarget_t *rt = (r_rendertarget_t *)Mem_ExpandableArray_RecordAtIndex(&r_fb.rendertargets, r_rendertarget_debug.integer);
5351                 if (rt && rt->colortexture[0])
5352                 {
5353                         viewtexture = rt->colortexture[0];
5354                         bloomtexture = NULL;
5355                 }
5356         }
5357
5358         R_Mesh_PrepareVertices_Mesh_Arrays(4, r_screenvertex3f, NULL, NULL, NULL, NULL, r_fb.rt_screen->texcoord2f, bloomtexture ? r_fb.rt_bloom->texcoord2f : NULL);
5359         switch(vid.renderpath)
5360         {
5361         case RENDERPATH_GL32:
5362         case RENDERPATH_GLES2:
5363                 permutation =
5364                         (r_fb.bloomwidth ? SHADERPERMUTATION_BLOOM : 0)
5365                         | (r_refdef.viewblend[3] > 0 ? SHADERPERMUTATION_VIEWTINT : 0)
5366                         | (!vid_gammatables_trivial ? SHADERPERMUTATION_GAMMARAMPS : 0)
5367                         | (r_glsl_postprocess.integer ? SHADERPERMUTATION_POSTPROCESSING : 0)
5368                         | ((!R_Stereo_ColorMasking() && r_glsl_saturation.value != 1) ? SHADERPERMUTATION_SATURATION : 0);
5369                 R_SetupShader_SetPermutationGLSL(SHADERMODE_POSTPROCESS, permutation);
5370                 if (r_glsl_permutation->tex_Texture_First           >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_First     , viewtexture);
5371                 if (r_glsl_permutation->tex_Texture_Second          >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_Second    , bloomtexture);
5372                 if (r_glsl_permutation->tex_Texture_GammaRamps      >= 0) R_Mesh_TexBind(r_glsl_permutation->tex_Texture_GammaRamps, r_texture_gammaramps       );
5373                 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]);
5374                 if (r_glsl_permutation->loc_PixelSize               >= 0) qglUniform2f(r_glsl_permutation->loc_PixelSize         , 1.0/r_fb.screentexturewidth, 1.0/r_fb.screentextureheight);
5375                 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]);
5376                 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]);
5377                 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]);
5378                 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]);
5379                 if (r_glsl_permutation->loc_Saturation              >= 0) qglUniform1f(r_glsl_permutation->loc_Saturation        , r_glsl_saturation.value);
5380                 if (r_glsl_permutation->loc_PixelToScreenTexCoord   >= 0) qglUniform2f(r_glsl_permutation->loc_PixelToScreenTexCoord, 1.0f/r_fb.screentexturewidth, 1.0f/r_fb.screentextureheight);
5381                 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);
5382                 if (r_glsl_permutation->loc_ColorFringe             >= 0) qglUniform1f(r_glsl_permutation->loc_ColorFringe, r_colorfringe.value );
5383                 break;
5384         }
5385         R_Mesh_Draw(0, 4, 0, 2, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
5386         r_refdef.stats[r_stat_bloom_drawpixels] += r_refdef.view.width * r_refdef.view.height;
5387 }
5388
5389 matrix4x4_t r_waterscrollmatrix;
5390
5391 void R_UpdateFog(void)
5392 {
5393         // Nehahra fog
5394         if (gamemode == GAME_NEHAHRA)
5395         {
5396                 if (gl_fogenable.integer)
5397                 {
5398                         r_refdef.oldgl_fogenable = true;
5399                         r_refdef.fog_density = gl_fogdensity.value;
5400                         r_refdef.fog_red = gl_fogred.value;
5401                         r_refdef.fog_green = gl_foggreen.value;
5402                         r_refdef.fog_blue = gl_fogblue.value;
5403                         r_refdef.fog_alpha = 1;
5404                         r_refdef.fog_start = 0;
5405                         r_refdef.fog_end = gl_skyclip.value;
5406                         r_refdef.fog_height = 1<<30;
5407                         r_refdef.fog_fadedepth = 128;
5408                 }
5409                 else if (r_refdef.oldgl_fogenable)
5410                 {
5411                         r_refdef.oldgl_fogenable = false;
5412                         r_refdef.fog_density = 0;
5413                         r_refdef.fog_red = 0;
5414                         r_refdef.fog_green = 0;
5415                         r_refdef.fog_blue = 0;
5416                         r_refdef.fog_alpha = 0;
5417                         r_refdef.fog_start = 0;
5418                         r_refdef.fog_end = 0;
5419                         r_refdef.fog_height = 1<<30;
5420                         r_refdef.fog_fadedepth = 128;
5421                 }
5422         }
5423
5424         // fog parms
5425         r_refdef.fog_alpha = bound(0, r_refdef.fog_alpha, 1);
5426         r_refdef.fog_start = max(0, r_refdef.fog_start);
5427         r_refdef.fog_end = max(r_refdef.fog_start + 0.01, r_refdef.fog_end);
5428
5429         if (r_refdef.fog_density && r_drawfog.integer)
5430         {
5431                 r_refdef.fogenabled = true;
5432                 // this is the point where the fog reaches 0.9986 alpha, which we
5433                 // consider a good enough cutoff point for the texture
5434                 // (0.9986 * 256 == 255.6)
5435                 if (r_fog_exp2.integer)
5436                         r_refdef.fogrange = 32 / (r_refdef.fog_density * r_refdef.fog_density) + r_refdef.fog_start;
5437                 else
5438                         r_refdef.fogrange = 2048 / r_refdef.fog_density + r_refdef.fog_start;
5439                 r_refdef.fogrange = bound(r_refdef.fog_start, r_refdef.fogrange, r_refdef.fog_end);
5440                 r_refdef.fograngerecip = 1.0f / r_refdef.fogrange;
5441                 r_refdef.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * r_refdef.fograngerecip;
5442                 if (strcmp(r_refdef.fogheighttexturename, r_refdef.fog_height_texturename))
5443                         R_BuildFogHeightTexture();
5444                 // fog color was already set
5445                 // update the fog texture
5446                 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)
5447                         R_BuildFogTexture();
5448                 r_refdef.fog_height_texcoordscale = 1.0f / max(0.125f, r_refdef.fog_fadedepth);
5449                 r_refdef.fog_height_tablescale = r_refdef.fog_height_tablesize * r_refdef.fog_height_texcoordscale;
5450         }
5451         else
5452                 r_refdef.fogenabled = false;
5453
5454         // fog color
5455         if (r_refdef.fog_density)
5456         {
5457                 r_refdef.fogcolor[0] = r_refdef.fog_red;
5458                 r_refdef.fogcolor[1] = r_refdef.fog_green;
5459                 r_refdef.fogcolor[2] = r_refdef.fog_blue;
5460
5461                 Vector4Set(r_refdef.fogplane, 0, 0, 1, -r_refdef.fog_height);
5462                 r_refdef.fogplaneviewdist = DotProduct(r_refdef.fogplane, r_refdef.view.origin) + r_refdef.fogplane[3];
5463                 r_refdef.fogplaneviewabove = r_refdef.fogplaneviewdist >= 0;
5464                 r_refdef.fogheightfade = -0.5f/max(0.125f, r_refdef.fog_fadedepth);
5465
5466                 {
5467                         vec3_t fogvec;
5468                         VectorCopy(r_refdef.fogcolor, fogvec);
5469                         //   color.rgb *= ContrastBoost * SceneBrightness;
5470                         VectorScale(fogvec, r_refdef.view.colorscale, fogvec);
5471                         r_refdef.fogcolor[0] = bound(0.0f, fogvec[0], 1.0f);
5472                         r_refdef.fogcolor[1] = bound(0.0f, fogvec[1], 1.0f);
5473                         r_refdef.fogcolor[2] = bound(0.0f, fogvec[2], 1.0f);
5474                 }
5475         }
5476 }
5477
5478 void R_UpdateVariables(void)
5479 {
5480         R_Textures_Frame();
5481
5482         r_refdef.scene.ambientintensity = r_ambient.value * (1.0f / 64.0f);
5483
5484         r_refdef.farclip = r_farclip_base.value;
5485         if (r_refdef.scene.worldmodel)
5486                 r_refdef.farclip += r_refdef.scene.worldmodel->radius * r_farclip_world.value * 2;
5487         r_refdef.nearclip = bound (0.001f, r_nearclip.value, r_refdef.farclip - 1.0f);
5488
5489         if (r_shadow_frontsidecasting.integer < 0 || r_shadow_frontsidecasting.integer > 1)
5490                 Cvar_SetValueQuick(&r_shadow_frontsidecasting, 1);
5491         r_refdef.polygonfactor = 0;
5492         r_refdef.polygonoffset = 0;
5493
5494         r_refdef.scene.rtworld = r_shadow_realtime_world.integer != 0;
5495         r_refdef.scene.rtworldshadows = r_shadow_realtime_world_shadows.integer && vid.stencil;
5496         r_refdef.scene.rtdlight = r_shadow_realtime_dlight.integer != 0 && !gl_flashblend.integer && r_dynamic.integer;
5497         r_refdef.scene.rtdlightshadows = r_refdef.scene.rtdlight && r_shadow_realtime_dlight_shadows.integer && vid.stencil;
5498         r_refdef.scene.lightmapintensity = r_refdef.scene.rtworld ? r_shadow_realtime_world_lightmaps.value : 1;
5499         if (r_refdef.scene.worldmodel)
5500         {
5501                 r_refdef.scene.lightmapintensity *= r_refdef.scene.worldmodel->lightmapscale;
5502         }
5503         if (r_showsurfaces.integer)
5504         {
5505                 r_refdef.scene.rtworld = false;
5506                 r_refdef.scene.rtworldshadows = false;
5507                 r_refdef.scene.rtdlight = false;
5508                 r_refdef.scene.rtdlightshadows = false;
5509                 r_refdef.scene.lightmapintensity = 0;
5510         }
5511
5512         r_gpuskeletal = false;
5513         switch(vid.renderpath)
5514         {
5515         case RENDERPATH_GL32:
5516                 r_gpuskeletal = r_glsl_skeletal.integer && !r_showsurfaces.integer;
5517         case RENDERPATH_GLES2:
5518                 if(!vid_gammatables_trivial)
5519                 {
5520                         if(!r_texture_gammaramps || vid_gammatables_serial != r_texture_gammaramps_serial)
5521                         {
5522                                 // build GLSL gamma texture
5523 #define RAMPWIDTH 256
5524                                 unsigned short ramp[RAMPWIDTH * 3];
5525                                 unsigned char rampbgr[RAMPWIDTH][4];
5526                                 int i;
5527
5528                                 r_texture_gammaramps_serial = vid_gammatables_serial;
5529
5530                                 VID_BuildGammaTables(&ramp[0], RAMPWIDTH);
5531                                 for(i = 0; i < RAMPWIDTH; ++i)
5532                                 {
5533                                         rampbgr[i][0] = (unsigned char) (ramp[i + 2 * RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5534                                         rampbgr[i][1] = (unsigned char) (ramp[i + RAMPWIDTH] * 255.0 / 65535.0 + 0.5);
5535                                         rampbgr[i][2] = (unsigned char) (ramp[i] * 255.0 / 65535.0 + 0.5);
5536                                         rampbgr[i][3] = 0;
5537                                 }
5538                                 if (r_texture_gammaramps)
5539                                 {
5540                                         R_UpdateTexture(r_texture_gammaramps, &rampbgr[0][0], 0, 0, 0, RAMPWIDTH, 1, 1, 0);
5541                                 }
5542                                 else
5543                                 {
5544                                         r_texture_gammaramps = R_LoadTexture2D(r_main_texturepool, "gammaramps", RAMPWIDTH, 1, &rampbgr[0][0], TEXTYPE_BGRA, TEXF_FORCELINEAR | TEXF_CLAMP | TEXF_PERSISTENT, -1, NULL);
5545                                 }
5546                         }
5547                 }
5548                 else
5549                 {
5550                         // remove GLSL gamma texture
5551                 }
5552                 break;
5553         }
5554 }
5555
5556 static r_refdef_scene_type_t r_currentscenetype = RST_CLIENT;
5557 static r_refdef_scene_t r_scenes_store[ RST_COUNT ];
5558 /*
5559 ================
5560 R_SelectScene
5561 ================
5562 */
5563 void R_SelectScene( r_refdef_scene_type_t scenetype ) {
5564         if( scenetype != r_currentscenetype ) {
5565                 // store the old scenetype
5566                 r_scenes_store[ r_currentscenetype ] = r_refdef.scene;
5567                 r_currentscenetype = scenetype;
5568                 // move in the new scene
5569                 r_refdef.scene = r_scenes_store[ r_currentscenetype ];
5570         }
5571 }
5572
5573 /*
5574 ================
5575 R_GetScenePointer
5576 ================
5577 */
5578 r_refdef_scene_t * R_GetScenePointer( r_refdef_scene_type_t scenetype )
5579 {
5580         // of course, we could also add a qbool that provides a lock state and a ReleaseScenePointer function..
5581         if( scenetype == r_currentscenetype ) {
5582                 return &r_refdef.scene;
5583         } else {
5584                 return &r_scenes_store[ scenetype ];
5585         }
5586 }
5587
5588 static int R_SortEntities_Compare(const void *ap, const void *bp)
5589 {
5590         const entity_render_t *a = *(const entity_render_t **)ap;
5591         const entity_render_t *b = *(const entity_render_t **)bp;
5592
5593         // 1. compare model
5594         if(a->model < b->model)
5595                 return -1;
5596         if(a->model > b->model)
5597                 return +1;
5598
5599         // 2. compare skin
5600         // TODO possibly calculate the REAL skinnum here first using
5601         // skinscenes?
5602         if(a->skinnum < b->skinnum)
5603                 return -1;
5604         if(a->skinnum > b->skinnum)
5605                 return +1;
5606
5607         // everything we compared is equal
5608         return 0;
5609 }
5610 static void R_SortEntities(void)
5611 {
5612         // below or equal 2 ents, sorting never gains anything
5613         if(r_refdef.scene.numentities <= 2)
5614                 return;
5615         // sort
5616         qsort(r_refdef.scene.entities, r_refdef.scene.numentities, sizeof(*r_refdef.scene.entities), R_SortEntities_Compare);
5617 }
5618
5619 /*
5620 ================
5621 R_RenderView
5622 ================
5623 */
5624 extern cvar_t r_shadow_bouncegrid;
5625 extern cvar_t v_isometric;
5626 extern void V_MakeViewIsometric(void);
5627 void R_RenderView(int fbo, rtexture_t *depthtexture, rtexture_t *colortexture, int x, int y, int width, int height)
5628 {
5629         matrix4x4_t originalmatrix = r_refdef.view.matrix, offsetmatrix;
5630         int viewfbo = 0;
5631         rtexture_t *viewdepthtexture = NULL;
5632         rtexture_t *viewcolortexture = NULL;
5633         int viewx = r_refdef.view.x, viewy = r_refdef.view.y, viewwidth = r_refdef.view.width, viewheight = r_refdef.view.height;
5634
5635         // finish any 2D rendering that was queued
5636         DrawQ_Finish();
5637
5638         if (r_timereport_active)
5639                 R_TimeReport("start");
5640         r_textureframe++; // used only by R_GetCurrentTexture
5641         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
5642
5643         if(R_CompileShader_CheckStaticParms())
5644                 R_GLSL_Restart_f(cmd_local);
5645
5646         if (!r_drawentities.integer)
5647                 r_refdef.scene.numentities = 0;
5648         else if (r_sortentities.integer)
5649                 R_SortEntities();
5650
5651         R_AnimCache_ClearCache();
5652
5653         /* adjust for stereo display */
5654         if(R_Stereo_Active())
5655         {
5656                 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);
5657                 Matrix4x4_Concat(&r_refdef.view.matrix, &originalmatrix, &offsetmatrix);
5658         }
5659
5660         if (r_refdef.view.isoverlay)
5661         {
5662                 // TODO: FIXME: move this into its own backend function maybe? [2/5/2008 Andreas]
5663                 R_Mesh_SetRenderTargets(0, NULL, NULL, NULL, NULL, NULL);
5664                 GL_Clear(GL_DEPTH_BUFFER_BIT, NULL, 1.0f, 0);
5665                 R_TimeReport("depthclear");
5666
5667                 r_refdef.view.showdebug = false;
5668
5669                 r_fb.water.enabled = false;
5670                 r_fb.water.numwaterplanes = 0;
5671
5672                 R_RenderScene(0, NULL, NULL, r_refdef.view.x, r_refdef.view.y, r_refdef.view.width, r_refdef.view.height);
5673
5674                 r_refdef.view.matrix = originalmatrix;
5675
5676                 CHECKGLERROR
5677                 return;
5678         }
5679
5680         if (!r_refdef.scene.entities || r_refdef.view.width * r_refdef.view.height == 0 || !r_renderview.integer || cl_videoplaying/* || !r_refdef.scene.worldmodel*/)
5681         {
5682                 r_refdef.view.matrix = originalmatrix;
5683                 return;
5684         }
5685
5686         r_refdef.view.usevieworiginculling = !r_trippy.value && r_refdef.view.useperspective;
5687         if (v_isometric.integer && r_refdef.view.ismain)
5688                 V_MakeViewIsometric();
5689
5690         r_refdef.view.colorscale = r_hdr_scenebrightness.value * r_hdr_irisadaptation_value.value;
5691
5692         if(vid_sRGB.integer && vid_sRGB_fallback.integer && !vid.sRGB3D)
5693                 // in sRGB fallback, behave similar to true sRGB: convert this
5694                 // value from linear to sRGB
5695                 r_refdef.view.colorscale = Image_sRGBFloatFromLinearFloat(r_refdef.view.colorscale);
5696
5697         R_RenderView_UpdateViewVectors();
5698
5699         R_Shadow_UpdateWorldLightSelection();
5700
5701         // this will set up r_fb.rt_screen
5702         R_Bloom_StartFrame();
5703
5704         // apply bloom brightness offset
5705         if(r_fb.rt_bloom)
5706                 r_refdef.view.colorscale *= r_bloom_scenebrightness.value;
5707
5708         // R_Bloom_StartFrame probably set up an fbo for us to render into, it will be rendered to the window later in R_BlendView
5709         if (r_fb.rt_screen)
5710         {
5711                 viewfbo = r_fb.rt_screen->fbo;
5712                 viewdepthtexture = r_fb.rt_screen->depthtexture;
5713                 viewcolortexture = r_fb.rt_screen->colortexture[0];
5714                 viewx = 0;
5715                 viewy = 0;
5716                 viewwidth = r_fb.rt_screen->texturewidth;
5717                 viewheight = r_fb.rt_screen->textureheight;
5718         }
5719
5720         R_Water_StartFrame(viewwidth, viewheight);
5721
5722         CHECKGLERROR
5723         if (r_timereport_active)
5724                 R_TimeReport("viewsetup");
5725
5726         R_ResetViewRendering3D(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5727
5728         // clear the whole fbo every frame - otherwise the driver will consider
5729         // it to be an inter-frame texture and stall in multi-gpu configurations
5730         if (r_fb.rt_screen)
5731                 GL_ScissorTest(false);
5732         R_ClearScreen(r_refdef.fogenabled);
5733         if (r_timereport_active)
5734                 R_TimeReport("viewclear");
5735
5736         r_refdef.view.clear = true;
5737
5738         r_refdef.view.showdebug = true;
5739
5740         R_View_Update();
5741         if (r_timereport_active)
5742                 R_TimeReport("visibility");
5743
5744         R_AnimCache_CacheVisibleEntities();
5745         if (r_timereport_active)
5746                 R_TimeReport("animcache");
5747
5748         R_Shadow_UpdateBounceGridTexture();
5749         // R_Shadow_UpdateBounceGridTexture called R_TimeReport a few times internally, so we don't need to do that here.
5750
5751         r_fb.water.numwaterplanes = 0;
5752         if (r_fb.water.enabled)
5753                 R_RenderWaterPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5754
5755         // for the actual view render we use scissoring a fair amount, so scissor
5756         // test needs to be on
5757         if (r_fb.rt_screen)
5758                 GL_ScissorTest(true);
5759         GL_Scissor(viewx, viewy, viewwidth, viewheight);
5760         R_RenderScene(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5761         r_fb.water.numwaterplanes = 0;
5762
5763         // postprocess uses textures that are not aligned with the viewport we're rendering, so no scissoring
5764         GL_ScissorTest(false);
5765
5766         R_BlendView(fbo, depthtexture, colortexture, x, y, width, height);
5767         if (r_timereport_active)
5768                 R_TimeReport("blendview");
5769
5770         r_refdef.view.matrix = originalmatrix;
5771
5772         CHECKGLERROR
5773
5774         // go back to 2d rendering
5775         DrawQ_Start();
5776 }
5777
5778 void R_RenderWaterPlanes(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5779 {
5780         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawAddWaterPlanes)
5781         {
5782                 r_refdef.scene.worldmodel->DrawAddWaterPlanes(r_refdef.scene.worldentity);
5783                 if (r_timereport_active)
5784                         R_TimeReport("waterworld");
5785         }
5786
5787         // don't let sound skip if going slow
5788         if (r_refdef.scene.extraupdate)
5789                 S_ExtraUpdate ();
5790
5791         R_DrawModelsAddWaterPlanes();
5792         if (r_timereport_active)
5793                 R_TimeReport("watermodels");
5794
5795         if (r_fb.water.numwaterplanes)
5796         {
5797                 R_Water_ProcessPlanes(viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5798                 if (r_timereport_active)
5799                         R_TimeReport("waterscenes");
5800         }
5801 }
5802
5803 extern cvar_t cl_locs_show;
5804 static void R_DrawLocs(void);
5805 static void R_DrawEntityBBoxes(prvm_prog_t *prog);
5806 static void R_DrawModelDecals(void);
5807 extern qbool r_shadow_usingdeferredprepass;
5808 extern int r_shadow_shadowmapatlas_modelshadows_size;
5809 void R_RenderScene(int viewfbo, rtexture_t *viewdepthtexture, rtexture_t *viewcolortexture, int viewx, int viewy, int viewwidth, int viewheight)
5810 {
5811         qbool shadowmapping = false;
5812
5813         if (r_timereport_active)
5814                 R_TimeReport("beginscene");
5815
5816         r_refdef.stats[r_stat_renders]++;
5817
5818         R_UpdateFog();
5819
5820         // don't let sound skip if going slow
5821         if (r_refdef.scene.extraupdate)
5822                 S_ExtraUpdate ();
5823
5824         R_MeshQueue_BeginScene();
5825
5826         R_SkyStartFrame();
5827
5828         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);
5829
5830         if (r_timereport_active)
5831                 R_TimeReport("skystartframe");
5832
5833         if (cl.csqc_vidvars.drawworld)
5834         {
5835                 // don't let sound skip if going slow
5836                 if (r_refdef.scene.extraupdate)
5837                         S_ExtraUpdate ();
5838
5839                 if (r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawSky)
5840                 {
5841                         r_refdef.scene.worldmodel->DrawSky(r_refdef.scene.worldentity);
5842                         if (r_timereport_active)
5843                                 R_TimeReport("worldsky");
5844                 }
5845
5846                 if (R_DrawBrushModelsSky() && r_timereport_active)
5847                         R_TimeReport("bmodelsky");
5848
5849                 if (skyrendermasked && skyrenderlater)
5850                 {
5851                         // we have to force off the water clipping plane while rendering sky
5852                         R_SetupView(false, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5853                         R_Sky();
5854                         R_SetupView(true, viewfbo, viewdepthtexture, viewcolortexture, viewx, viewy, viewwidth, viewheight);
5855                         if (r_timereport_active)
5856                                 R_TimeReport("sky");
5857                 }
5858         }
5859
5860         // save the framebuffer info for R_Shadow_RenderMode_Reset during this view render
5861         r_shadow_viewfbo = viewfbo;
5862         r_shadow_viewdepthtexture = viewdepthtexture;
5863         r_shadow_viewcolortexture = viewcolortexture;
5864         r_shadow_viewx = viewx;
5865         r_shadow_viewy = viewy;
5866         r_shadow_viewwidth = viewwidth;
5867         r_shadow_viewheight = viewheight;
5868
5869         R_Shadow_PrepareModelShadows();
5870         R_Shadow_PrepareLights();
5871         if (r_timereport_active)
5872                 R_TimeReport("preparelights");
5873
5874         // render all the shadowmaps that will be used for this view
5875         shadowmapping = R_Shadow_ShadowMappingEnabled();
5876         if (shadowmapping || r_shadow_shadowmapatlas_modelshadows_size)
5877         {
5878                 R_Shadow_DrawShadowMaps();
5879                 if (r_timereport_active)
5880                         R_TimeReport("shadowmaps");
5881         }
5882
5883         // render prepass deferred lighting if r_shadow_deferred is on, this produces light buffers that will be sampled in forward pass
5884         if (r_shadow_usingdeferredprepass)
5885                 R_Shadow_DrawPrepass();
5886
5887         // now we begin the forward pass of the view render
5888         if (r_depthfirst.integer >= 1 && cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->DrawDepth)
5889         {
5890                 r_refdef.scene.worldmodel->DrawDepth(r_refdef.scene.worldentity);
5891                 if (r_timereport_active)
5892                         R_TimeReport("worlddepth");
5893         }
5894         if (r_depthfirst.integer >= 2)
5895         {
5896                 R_DrawModelsDepth();
5897                 if (r_timereport_active)
5898                         R_TimeReport("modeldepth");
5899         }
5900
5901         if (cl.csqc_vidvars.drawworld && r_refdef.scene.worldmodel && r_refdef.scene.worldmodel->Draw)
5902         {
5903                 r_refdef.scene.worldmodel->Draw(r_refdef.scene.worldentity);
5904                 if (r_timereport_active)
5905                         R_TimeReport("world");
5906         }
5907
5908         // don't let sound skip if going slow
5909         if (r_refdef.scene.extraupdate)
5910                 S_ExtraUpdate ();
5911
5912         R_DrawModels();
5913         if (r_timereport_active)
5914                 R_TimeReport("models");
5915
5916         // don't let sound skip if going slow
5917         if (r_refdef.scene.extraupdate)
5918                 S_ExtraUpdate ();
5919
5920         if (!r_shadow_usingdeferredprepass)
5921         {
5922                 R_Shadow_DrawLights();
5923                 if (r_timereport_active)
5924                         R_TimeReport("rtlights");
5925         }
5926
5927         // don't let sound skip if going slow
5928         if (r_refdef.scene.extraupdate)
5929                 S_ExtraUpdate ();
5930
5931         if (cl.csqc_vidvars.drawworld)
5932         {
5933                 R_DrawModelDecals();
5934                 if (r_timereport_active)
5935                         R_TimeReport("modeldecals");
5936
5937                 R_DrawParticles();
5938                 if (r_timereport_active)
5939                         R_TimeReport("particles");
5940
5941                 R_DrawExplosions();
5942                 if (r_timereport_active)
5943                         R_TimeReport("explosions");
5944         }
5945
5946         if (r_refdef.view.showdebug)
5947         {
5948                 if (cl_locs_show.integer)
5949                 {
5950                         R_DrawLocs();
5951                         if (r_timereport_active)
5952                                 R_TimeReport("showlocs");
5953                 }
5954
5955                 if (r_drawportals.integer)
5956                 {
5957                         R_DrawPortals();
5958                         if (r_timereport_active)
5959                                 R_TimeReport("portals");
5960                 }
5961
5962                 if (r_showbboxes_client.value > 0)
5963                 {
5964                         R_DrawEntityBBoxes(CLVM_prog);
5965                         if (r_timereport_active)
5966                                 R_TimeReport("clbboxes");
5967                 }
5968                 if (r_showbboxes.value > 0)
5969                 {
5970                         R_DrawEntityBBoxes(SVVM_prog);
5971                         if (r_timereport_active)
5972                                 R_TimeReport("svbboxes");
5973                 }
5974         }
5975
5976         if (r_transparent.integer)
5977         {
5978                 R_MeshQueue_RenderTransparent();
5979                 if (r_timereport_active)
5980                         R_TimeReport("drawtrans");
5981         }
5982
5983         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))
5984         {
5985                 r_refdef.scene.worldmodel->DrawDebug(r_refdef.scene.worldentity);
5986                 if (r_timereport_active)
5987                         R_TimeReport("worlddebug");
5988                 R_DrawModelsDebug();
5989                 if (r_timereport_active)
5990                         R_TimeReport("modeldebug");
5991         }
5992
5993         if (cl.csqc_vidvars.drawworld)
5994         {
5995                 R_Shadow_DrawCoronas();
5996                 if (r_timereport_active)
5997                         R_TimeReport("coronas");
5998         }
5999
6000         // don't let sound skip if going slow
6001         if (r_refdef.scene.extraupdate)
6002                 S_ExtraUpdate ();
6003 }
6004
6005 static const unsigned short bboxelements[36] =
6006 {
6007         5, 1, 3, 5, 3, 7,
6008         6, 2, 0, 6, 0, 4,
6009         7, 3, 2, 7, 2, 6,
6010         4, 0, 1, 4, 1, 5,
6011         4, 5, 7, 4, 7, 6,
6012         1, 0, 2, 1, 2, 3,
6013 };
6014
6015 #define BBOXEDGES 13
6016 static const float bboxedges[BBOXEDGES][6] = 
6017 {
6018         // whole box
6019         { 0, 0, 0, 1, 1, 1 },
6020         // bottom edges
6021         { 0, 0, 0, 0, 1, 0 },
6022         { 0, 0, 0, 1, 0, 0 },
6023         { 0, 1, 0, 1, 1, 0 },
6024         { 1, 0, 0, 1, 1, 0 },
6025         // top edges
6026         { 0, 0, 1, 0, 1, 1 },
6027         { 0, 0, 1, 1, 0, 1 },
6028         { 0, 1, 1, 1, 1, 1 },
6029         { 1, 0, 1, 1, 1, 1 },
6030         // vertical edges
6031         { 0, 0, 0, 0, 0, 1 },
6032         { 1, 0, 0, 1, 0, 1 },
6033         { 0, 1, 0, 0, 1, 1 },
6034         { 1, 1, 0, 1, 1, 1 },
6035 };
6036
6037 static void R_DrawBBoxMesh(vec3_t mins, vec3_t maxs, float cr, float cg, float cb, float ca)
6038 {
6039         int numvertices = BBOXEDGES * 8;
6040         float vertex3f[BBOXEDGES * 8 * 3], color4f[BBOXEDGES * 8 * 4];
6041         int numtriangles = BBOXEDGES * 12;
6042         unsigned short elements[BBOXEDGES * 36];
6043         int i, edge;
6044         float *v, *c, f1, f2, edgemins[3], edgemaxs[3];
6045
6046         RSurf_ActiveModelEntity(r_refdef.scene.worldentity, false, false, false);
6047
6048         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6049         GL_DepthMask(false);
6050         GL_DepthRange(0, 1);
6051         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
6052
6053         for (edge = 0; edge < BBOXEDGES; edge++)
6054         {
6055                 for (i = 0; i < 3; i++)
6056                 {
6057                         edgemins[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][i] - 0.25f;
6058                         edgemaxs[i] = mins[i] + (maxs[i] - mins[i]) * bboxedges[edge][3 + i] + 0.25f;
6059                 }
6060                 vertex3f[edge * 24 + 0] = edgemins[0]; vertex3f[edge * 24 + 1] = edgemins[1]; vertex3f[edge * 24 + 2] = edgemins[2];
6061                 vertex3f[edge * 24 + 3] = edgemaxs[0]; vertex3f[edge * 24 + 4] = edgemins[1]; vertex3f[edge * 24 + 5] = edgemins[2];
6062                 vertex3f[edge * 24 + 6] = edgemins[0]; vertex3f[edge * 24 + 7] = edgemaxs[1]; vertex3f[edge * 24 + 8] = edgemins[2];
6063                 vertex3f[edge * 24 + 9] = edgemaxs[0]; vertex3f[edge * 24 + 10] = edgemaxs[1]; vertex3f[edge * 24 + 11] = edgemins[2];
6064                 vertex3f[edge * 24 + 12] = edgemins[0]; vertex3f[edge * 24 + 13] = edgemins[1]; vertex3f[edge * 24 + 14] = edgemaxs[2];
6065                 vertex3f[edge * 24 + 15] = edgemaxs[0]; vertex3f[edge * 24 + 16] = edgemins[1]; vertex3f[edge * 24 + 17] = edgemaxs[2];
6066                 vertex3f[edge * 24 + 18] = edgemins[0]; vertex3f[edge * 24 + 19] = edgemaxs[1]; vertex3f[edge * 24 + 20] = edgemaxs[2];
6067                 vertex3f[edge * 24 + 21] = edgemaxs[0]; vertex3f[edge * 24 + 22] = edgemaxs[1]; vertex3f[edge * 24 + 23] = edgemaxs[2];
6068                 for (i = 0; i < 36; i++)
6069                         elements[edge * 36 + i] = edge * 8 + bboxelements[i];
6070         }
6071         R_FillColors(color4f, numvertices, cr, cg, cb, ca);
6072         if (r_refdef.fogenabled)
6073         {
6074                 for (i = 0, v = vertex3f, c = color4f; i < numvertices; i++, v += 3, c += 4)
6075                 {
6076                         f1 = RSurf_FogVertex(v);
6077                         f2 = 1 - f1;
6078                         c[0] = c[0] * f1 + r_refdef.fogcolor[0] * f2;
6079                         c[1] = c[1] * f1 + r_refdef.fogcolor[1] * f2;
6080                         c[2] = c[2] * f1 + r_refdef.fogcolor[2] * f2;
6081                 }
6082         }
6083         R_Mesh_PrepareVertices_Generic_Arrays(numvertices, vertex3f, color4f, NULL);
6084         R_Mesh_ResetTextureState();
6085         R_SetupShader_Generic_NoTexture(false, false);
6086         R_Mesh_Draw(0, numvertices, 0, numtriangles, NULL, NULL, 0, elements, NULL, 0);
6087 }
6088
6089 static void R_DrawEntityBBoxes_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6090 {
6091         // hacky overloading of the parameters
6092         prvm_prog_t *prog = (prvm_prog_t *)rtlight;
6093         int i;
6094         float color[4];
6095         prvm_edict_t *edict;
6096
6097         GL_CullFace(GL_NONE);
6098         R_SetupShader_Generic_NoTexture(false, false);
6099
6100         for (i = 0;i < numsurfaces;i++)
6101         {
6102                 edict = PRVM_EDICT_NUM(surfacelist[i]);
6103                 switch ((int)PRVM_serveredictfloat(edict, solid))
6104                 {
6105                         case SOLID_NOT:      Vector4Set(color, 1, 1, 1, 0.05);break;
6106                         case SOLID_TRIGGER:  Vector4Set(color, 1, 0, 1, 0.10);break;
6107                         case SOLID_BBOX:     Vector4Set(color, 0, 1, 0, 0.10);break;
6108                         case SOLID_SLIDEBOX: Vector4Set(color, 1, 0, 0, 0.10);break;
6109                         case SOLID_BSP:      Vector4Set(color, 0, 0, 1, 0.05);break;
6110                         case SOLID_CORPSE:   Vector4Set(color, 1, 0.5, 0, 0.05);break;
6111                         default:             Vector4Set(color, 0, 0, 0, 0.50);break;
6112                 }
6113                 if (prog == CLVM_prog)
6114                         color[3] *= r_showbboxes_client.value;
6115                 else
6116                         color[3] *= r_showbboxes.value;
6117                 color[3] = bound(0, color[3], 1);
6118                 GL_DepthTest(!r_showdisabledepthtest.integer);
6119                 R_DrawBBoxMesh(edict->priv.server->areamins, edict->priv.server->areamaxs, color[0], color[1], color[2], color[3]);
6120         }
6121 }
6122
6123 static void R_DrawEntityBBoxes(prvm_prog_t *prog)
6124 {
6125         int i;
6126         prvm_edict_t *edict;
6127         vec3_t center;
6128
6129         if (prog == NULL)
6130                 return;
6131
6132         for (i = 0; i < prog->num_edicts; i++)
6133         {
6134                 edict = PRVM_EDICT_NUM(i);
6135                 if (edict->free)
6136                         continue;
6137                 // exclude the following for now, as they don't live in world coordinate space and can't be solid:
6138                 if (PRVM_gameedictedict(edict, tag_entity) != 0)
6139                         continue;
6140                 if (prog == SVVM_prog && PRVM_serveredictedict(edict, viewmodelforclient) != 0)
6141                         continue;
6142                 VectorLerp(edict->priv.server->areamins, 0.5f, edict->priv.server->areamaxs, center);
6143                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawEntityBBoxes_Callback, (entity_render_t *)NULL, i, (rtlight_t *)prog);
6144         }
6145 }
6146
6147 static const int nomodelelement3i[24] =
6148 {
6149         5, 2, 0,
6150         5, 1, 2,
6151         5, 0, 3,
6152         5, 3, 1,
6153         0, 2, 4,
6154         2, 1, 4,
6155         3, 0, 4,
6156         1, 3, 4
6157 };
6158
6159 static const unsigned short nomodelelement3s[24] =
6160 {
6161         5, 2, 0,
6162         5, 1, 2,
6163         5, 0, 3,
6164         5, 3, 1,
6165         0, 2, 4,
6166         2, 1, 4,
6167         3, 0, 4,
6168         1, 3, 4
6169 };
6170
6171 static const float nomodelvertex3f[6*3] =
6172 {
6173         -16,   0,   0,
6174          16,   0,   0,
6175           0, -16,   0,
6176           0,  16,   0,
6177           0,   0, -16,
6178           0,   0,  16
6179 };
6180
6181 static const float nomodelcolor4f[6*4] =
6182 {
6183         0.0f, 0.0f, 0.5f, 1.0f,
6184         0.0f, 0.0f, 0.5f, 1.0f,
6185         0.0f, 0.5f, 0.0f, 1.0f,
6186         0.0f, 0.5f, 0.0f, 1.0f,
6187         0.5f, 0.0f, 0.0f, 1.0f,
6188         0.5f, 0.0f, 0.0f, 1.0f
6189 };
6190
6191 static void R_DrawNoModel_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
6192 {
6193         int i;
6194         float f1, f2, *c;
6195         float color4f[6*4];
6196
6197         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);
6198
6199         // this is only called once per entity so numsurfaces is always 1, and
6200         // surfacelist is always {0}, so this code does not handle batches
6201
6202         if (rsurface.ent_flags & RENDER_ADDITIVE)
6203         {
6204                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE);
6205                 GL_DepthMask(false);
6206         }
6207         else if (ent->alpha < 1)
6208         {
6209                 GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
6210                 GL_DepthMask(false);
6211         }
6212         else
6213         {
6214                 GL_BlendFunc(GL_ONE, GL_ZERO);
6215                 GL_DepthMask(true);
6216         }
6217         GL_DepthRange(0, (rsurface.ent_flags & RENDER_VIEWMODEL) ? 0.0625 : 1);
6218         GL_PolygonOffset(rsurface.basepolygonfactor, rsurface.basepolygonoffset);
6219         GL_DepthTest(!(rsurface.ent_flags & RENDER_NODEPTHTEST));
6220         GL_CullFace((rsurface.ent_flags & RENDER_DOUBLESIDED) ? GL_NONE : r_refdef.view.cullface_back);
6221         memcpy(color4f, nomodelcolor4f, sizeof(float[6*4]));
6222         for (i = 0, c = color4f;i < 6;i++, c += 4)
6223         {
6224                 c[0] *= ent->render_fullbright[0] * r_refdef.view.colorscale;
6225                 c[1] *= ent->render_fullbright[1] * r_refdef.view.colorscale;
6226                 c[2] *= ent->render_fullbright[2] * r_refdef.view.colorscale;
6227                 c[3] *= ent->alpha;
6228         }
6229         if (r_refdef.fogenabled)
6230         {
6231                 for (i = 0, c = color4f;i < 6;i++, c += 4)
6232                 {
6233                         f1 = RSurf_FogVertex(nomodelvertex3f + 3*i);
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_ResetTextureState();
6241         R_SetupShader_Generic_NoTexture(false, false);
6242         R_Mesh_PrepareVertices_Generic_Arrays(6, nomodelvertex3f, color4f, NULL);
6243         R_Mesh_Draw(0, 6, 0, 8, nomodelelement3i, NULL, 0, nomodelelement3s, NULL, 0);
6244 }
6245
6246 void R_DrawNoModel(entity_render_t *ent)
6247 {
6248         vec3_t org;
6249         Matrix4x4_OriginFromMatrix(&ent->matrix, org);
6250         if ((ent->flags & RENDER_ADDITIVE) || (ent->alpha < 1))
6251                 R_MeshQueue_AddTransparent((ent->flags & RENDER_NODEPTHTEST) ? TRANSPARENTSORT_HUD : TRANSPARENTSORT_DISTANCE, org, R_DrawNoModel_TransparentCallback, ent, 0, rsurface.rtlight);
6252         else
6253                 R_DrawNoModel_TransparentCallback(ent, rsurface.rtlight, 0, NULL);
6254 }
6255
6256 void R_CalcBeam_Vertex3f (float *vert, const float *org1, const float *org2, float width)
6257 {
6258         vec3_t right1, right2, diff, normal;
6259
6260         VectorSubtract (org2, org1, normal);
6261
6262         // calculate 'right' vector for start
6263         VectorSubtract (r_refdef.view.origin, org1, diff);
6264         CrossProduct (normal, diff, right1);
6265         VectorNormalize (right1);
6266
6267         // calculate 'right' vector for end
6268         VectorSubtract (r_refdef.view.origin, org2, diff);
6269         CrossProduct (normal, diff, right2);
6270         VectorNormalize (right2);
6271
6272         vert[ 0] = org1[0] + width * right1[0];
6273         vert[ 1] = org1[1] + width * right1[1];
6274         vert[ 2] = org1[2] + width * right1[2];
6275         vert[ 3] = org1[0] - width * right1[0];
6276         vert[ 4] = org1[1] - width * right1[1];
6277         vert[ 5] = org1[2] - width * right1[2];
6278         vert[ 6] = org2[0] - width * right2[0];
6279         vert[ 7] = org2[1] - width * right2[1];
6280         vert[ 8] = org2[2] - width * right2[2];
6281         vert[ 9] = org2[0] + width * right2[0];
6282         vert[10] = org2[1] + width * right2[1];
6283         vert[11] = org2[2] + width * right2[2];
6284 }
6285
6286 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)
6287 {
6288         vertex3f[ 0] = origin[0] + left[0] * scalex2 + up[0] * scaley1;
6289         vertex3f[ 1] = origin[1] + left[1] * scalex2 + up[1] * scaley1;
6290         vertex3f[ 2] = origin[2] + left[2] * scalex2 + up[2] * scaley1;
6291         vertex3f[ 3] = origin[0] + left[0] * scalex2 + up[0] * scaley2;
6292         vertex3f[ 4] = origin[1] + left[1] * scalex2 + up[1] * scaley2;
6293         vertex3f[ 5] = origin[2] + left[2] * scalex2 + up[2] * scaley2;
6294         vertex3f[ 6] = origin[0] + left[0] * scalex1 + up[0] * scaley2;
6295         vertex3f[ 7] = origin[1] + left[1] * scalex1 + up[1] * scaley2;
6296         vertex3f[ 8] = origin[2] + left[2] * scalex1 + up[2] * scaley2;
6297         vertex3f[ 9] = origin[0] + left[0] * scalex1 + up[0] * scaley1;
6298         vertex3f[10] = origin[1] + left[1] * scalex1 + up[1] * scaley1;
6299         vertex3f[11] = origin[2] + left[2] * scalex1 + up[2] * scaley1;
6300 }
6301
6302 static int R_Mesh_AddVertex(rmesh_t *mesh, float x, float y, float z)
6303 {
6304         int i;
6305         float *vertex3f;
6306         float v[3];
6307         VectorSet(v, x, y, z);
6308         for (i = 0, vertex3f = mesh->vertex3f;i < mesh->numvertices;i++, vertex3f += 3)
6309                 if (VectorDistance2(v, vertex3f) < mesh->epsilon2)
6310                         break;
6311         if (i == mesh->numvertices)
6312         {
6313                 if (mesh->numvertices < mesh->maxvertices)
6314                 {
6315                         VectorCopy(v, vertex3f);
6316                         mesh->numvertices++;
6317                 }
6318                 return mesh->numvertices;
6319         }
6320         else
6321                 return i;
6322 }
6323
6324 void R_Mesh_AddPolygon3f(rmesh_t *mesh, int numvertices, float *vertex3f)
6325 {
6326         int i;
6327         int *e, element[3];
6328         element[0] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6329         element[1] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);vertex3f += 3;
6330         e = mesh->element3i + mesh->numtriangles * 3;
6331         for (i = 0;i < numvertices - 2;i++, vertex3f += 3)
6332         {
6333                 element[2] = R_Mesh_AddVertex(mesh, vertex3f[0], vertex3f[1], vertex3f[2]);
6334                 if (mesh->numtriangles < mesh->maxtriangles)
6335                 {
6336                         *e++ = element[0];
6337                         *e++ = element[1];
6338                         *e++ = element[2];
6339                         mesh->numtriangles++;
6340                 }
6341                 element[1] = element[2];
6342         }
6343 }
6344
6345 static void R_Mesh_AddPolygon3d(rmesh_t *mesh, int numvertices, double *vertex3d)
6346 {
6347         int i;
6348         int *e, element[3];
6349         element[0] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6350         element[1] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);vertex3d += 3;
6351         e = mesh->element3i + mesh->numtriangles * 3;
6352         for (i = 0;i < numvertices - 2;i++, vertex3d += 3)
6353         {
6354                 element[2] = R_Mesh_AddVertex(mesh, vertex3d[0], vertex3d[1], vertex3d[2]);
6355                 if (mesh->numtriangles < mesh->maxtriangles)
6356                 {
6357                         *e++ = element[0];
6358                         *e++ = element[1];
6359                         *e++ = element[2];
6360                         mesh->numtriangles++;
6361                 }
6362                 element[1] = element[2];
6363         }
6364 }
6365
6366 #define R_MESH_PLANE_DIST_EPSILON (1.0 / 32.0)
6367 void R_Mesh_AddBrushMeshFromPlanes(rmesh_t *mesh, int numplanes, mplane_t *planes)
6368 {
6369         int planenum, planenum2;
6370         int w;
6371         int tempnumpoints;
6372         mplane_t *plane, *plane2;
6373         double maxdist;
6374         double temppoints[2][256*3];
6375         // figure out how large a bounding box we need to properly compute this brush
6376         maxdist = 0;
6377         for (w = 0;w < numplanes;w++)
6378                 maxdist = max(maxdist, fabs(planes[w].dist));
6379         // now make it large enough to enclose the entire brush, and round it off to a reasonable multiple of 1024
6380         maxdist = floor(maxdist * (4.0 / 1024.0) + 1) * 1024.0;
6381         for (planenum = 0, plane = planes;planenum < numplanes;planenum++, plane++)
6382         {
6383                 w = 0;
6384                 tempnumpoints = 4;
6385                 PolygonD_QuadForPlane(temppoints[w], plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, maxdist);
6386                 for (planenum2 = 0, plane2 = planes;planenum2 < numplanes && tempnumpoints >= 3;planenum2++, plane2++)
6387                 {
6388                         if (planenum2 == planenum)
6389                                 continue;
6390                         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);
6391                         w = !w;
6392                 }
6393                 if (tempnumpoints < 3)
6394                         continue;
6395                 // generate elements forming a triangle fan for this polygon
6396                 R_Mesh_AddPolygon3d(mesh, tempnumpoints, temppoints[w]);
6397         }
6398 }
6399
6400 static qbool R_TestQ3WaveFunc(q3wavefunc_t func, const float *parms)
6401 {
6402         if(parms[0] == 0 && parms[1] == 0)
6403                 return false;
6404         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6405                 if(rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)] == 0)
6406                         return false;
6407         return true;
6408 }
6409
6410 static float R_EvaluateQ3WaveFunc(q3wavefunc_t func, const float *parms)
6411 {
6412         double index, f;
6413         index = parms[2] + rsurface.shadertime * parms[3];
6414         index -= floor(index);
6415         switch (func & ((1 << Q3WAVEFUNC_USER_SHIFT) - 1))
6416         {
6417         default:
6418         case Q3WAVEFUNC_NONE:
6419         case Q3WAVEFUNC_NOISE:
6420         case Q3WAVEFUNC_COUNT:
6421                 f = 0;
6422                 break;
6423         case Q3WAVEFUNC_SIN: f = sin(index * M_PI * 2);break;
6424         case Q3WAVEFUNC_SQUARE: f = index < 0.5 ? 1 : -1;break;
6425         case Q3WAVEFUNC_SAWTOOTH: f = index;break;
6426         case Q3WAVEFUNC_INVERSESAWTOOTH: f = 1 - index;break;
6427         case Q3WAVEFUNC_TRIANGLE:
6428                 index *= 4;
6429                 f = index - floor(index);
6430                 if (index < 1)
6431                 {
6432                         // f = f;
6433                 }
6434                 else if (index < 2)
6435                         f = 1 - f;
6436                 else if (index < 3)
6437                         f = -f;
6438                 else
6439                         f = -(1 - f);
6440                 break;
6441         }
6442         f = parms[0] + parms[1] * f;
6443         if(func >> Q3WAVEFUNC_USER_SHIFT) // assumes rsurface to be set!
6444                 f *= rsurface.userwavefunc_param[bound(0, (func >> Q3WAVEFUNC_USER_SHIFT) - 1, Q3WAVEFUNC_USER_COUNT - 1)];
6445         return (float) f;
6446 }
6447
6448 static void R_tcMod_ApplyToMatrix(matrix4x4_t *texmatrix, q3shaderinfo_layer_tcmod_t *tcmod, int currentmaterialflags)
6449 {
6450         int w, h, idx;
6451         float shadertime;
6452         float f;
6453         float offsetd[2];
6454         float tcmat[12];
6455         matrix4x4_t matrix, temp;
6456         // if shadertime exceeds about 9 hours (32768 seconds), just wrap it,
6457         // it's better to have one huge fixup every 9 hours than gradual
6458         // degradation over time which looks consistently bad after many hours.
6459         //
6460         // tcmod scroll in particular suffers from this degradation which can't be
6461         // effectively worked around even with floor() tricks because we don't
6462         // know if tcmod scroll is the last tcmod being applied, and for clampmap
6463         // a workaround involving floor() would be incorrect anyway...
6464         shadertime = rsurface.shadertime;
6465         if (shadertime >= 32768.0f)
6466                 shadertime -= floor(rsurface.shadertime * (1.0f / 32768.0f)) * 32768.0f;
6467         switch(tcmod->tcmod)
6468         {
6469                 case Q3TCMOD_COUNT:
6470                 case Q3TCMOD_NONE:
6471                         if (currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6472                                 matrix = r_waterscrollmatrix;
6473                         else
6474                                 matrix = identitymatrix;
6475                         break;
6476                 case Q3TCMOD_ENTITYTRANSLATE:
6477                         // this is used in Q3 to allow the gamecode to control texcoord
6478                         // scrolling on the entity, which is not supported in darkplaces yet.
6479                         Matrix4x4_CreateTranslate(&matrix, 0, 0, 0);
6480                         break;
6481                 case Q3TCMOD_ROTATE:
6482                         Matrix4x4_CreateTranslate(&matrix, 0.5, 0.5, 0);
6483                         Matrix4x4_ConcatRotate(&matrix, tcmod->parms[0] * rsurface.shadertime, 0, 0, 1);
6484                         Matrix4x4_ConcatTranslate(&matrix, -0.5, -0.5, 0);
6485                         break;
6486                 case Q3TCMOD_SCALE:
6487                         Matrix4x4_CreateScale3(&matrix, tcmod->parms[0], tcmod->parms[1], 1);
6488                         break;
6489                 case Q3TCMOD_SCROLL:
6490                         // this particular tcmod is a "bug for bug" compatible one with regards to
6491                         // Quake3, the wrapping is unnecessary with our shadetime fix but quake3
6492                         // specifically did the wrapping and so we must mimic that...
6493                         offsetd[0] = tcmod->parms[0] * rsurface.shadertime;
6494                         offsetd[1] = tcmod->parms[1] * rsurface.shadertime;
6495                         Matrix4x4_CreateTranslate(&matrix, offsetd[0] - floor(offsetd[0]), offsetd[1] - floor(offsetd[1]), 0);
6496                         break;
6497                 case Q3TCMOD_PAGE: // poor man's animmap (to store animations into a single file, useful for HTTP downloaded textures)
6498                         w = (int) tcmod->parms[0];
6499                         h = (int) tcmod->parms[1];
6500                         f = rsurface.shadertime / (tcmod->parms[2] * w * h);
6501                         f = f - floor(f);
6502                         idx = (int) floor(f * w * h);
6503                         Matrix4x4_CreateTranslate(&matrix, (idx % w) / tcmod->parms[0], (idx / w) / tcmod->parms[1], 0);
6504                         break;
6505                 case Q3TCMOD_STRETCH:
6506                         f = 1.0f / R_EvaluateQ3WaveFunc(tcmod->wavefunc, tcmod->waveparms);
6507                         Matrix4x4_CreateFromQuakeEntity(&matrix, 0.5f * (1 - f), 0.5 * (1 - f), 0, 0, 0, 0, f);
6508                         break;
6509                 case Q3TCMOD_TRANSFORM:
6510                         VectorSet(tcmat +  0, tcmod->parms[0], tcmod->parms[1], 0);
6511                         VectorSet(tcmat +  3, tcmod->parms[2], tcmod->parms[3], 0);
6512                         VectorSet(tcmat +  6, 0                   , 0                , 1);
6513                         VectorSet(tcmat +  9, tcmod->parms[4], tcmod->parms[5], 0);
6514                         Matrix4x4_FromArray12FloatGL(&matrix, tcmat);
6515                         break;
6516                 case Q3TCMOD_TURBULENT:
6517                         // this is handled in the RSurf_PrepareVertices function
6518                         matrix = identitymatrix;
6519                         break;
6520         }
6521         temp = *texmatrix;
6522         Matrix4x4_Concat(texmatrix, &matrix, &temp);
6523 }
6524
6525 static void R_LoadQWSkin(r_qwskincache_t *cache, const char *skinname)
6526 {
6527         int textureflags = (r_mipskins.integer ? TEXF_MIPMAP : 0) | TEXF_PICMIP;
6528         char name[MAX_QPATH];
6529         skinframe_t *skinframe;
6530         unsigned char pixels[296*194];
6531         strlcpy(cache->name, skinname, sizeof(cache->name));
6532         dpsnprintf(name, sizeof(name), "skins/%s.pcx", cache->name);
6533         if (developer_loading.integer)
6534                 Con_Printf("loading %s\n", name);
6535         skinframe = R_SkinFrame_Find(name, textureflags, 0, 0, 0, false);
6536         if (!skinframe || !skinframe->base)
6537         {
6538                 unsigned char *f;
6539                 fs_offset_t filesize;
6540                 skinframe = NULL;
6541                 f = FS_LoadFile(name, tempmempool, true, &filesize);
6542                 if (f)
6543                 {
6544                         if (LoadPCX_QWSkin(f, (int)filesize, pixels, 296, 194))
6545                                 skinframe = R_SkinFrame_LoadInternalQuake(name, textureflags, true, r_fullbrights.integer, pixels, image_width, image_height);
6546                         Mem_Free(f);
6547                 }
6548         }
6549         cache->skinframe = skinframe;
6550 }
6551
6552 texture_t *R_GetCurrentTexture(texture_t *t)
6553 {
6554         int i, q;
6555         const entity_render_t *ent = rsurface.entity;
6556         model_t *model = ent->model; // when calling this, ent must not be NULL
6557         q3shaderinfo_layer_tcmod_t *tcmod;
6558         float specularscale = 0.0f;
6559
6560         if (t->update_lastrenderframe == r_textureframe && t->update_lastrenderentity == (void *)ent && !rsurface.forcecurrenttextureupdate)
6561                 return t->currentframe;
6562         t->update_lastrenderframe = r_textureframe;
6563         t->update_lastrenderentity = (void *)ent;
6564
6565         if(ent->entitynumber >= MAX_EDICTS && ent->entitynumber < 2 * MAX_EDICTS)
6566                 t->camera_entity = ent->entitynumber;
6567         else
6568                 t->camera_entity = 0;
6569
6570         // switch to an alternate material if this is a q1bsp animated material
6571         {
6572                 texture_t *texture = t;
6573                 int s = rsurface.ent_skinnum;
6574                 if ((unsigned int)s >= (unsigned int)model->numskins)
6575                         s = 0;
6576                 if (model->skinscenes)
6577                 {
6578                         if (model->skinscenes[s].framecount > 1)
6579                                 s = model->skinscenes[s].firstframe + (unsigned int) (rsurface.shadertime * model->skinscenes[s].framerate) % model->skinscenes[s].framecount;
6580                         else
6581                                 s = model->skinscenes[s].firstframe;
6582                 }
6583                 if (s > 0)
6584                         t = t + s * model->num_surfaces;
6585                 if (t->animated)
6586                 {
6587                         // use an alternate animation if the entity's frame is not 0,
6588                         // and only if the texture has an alternate animation
6589                         if (t->animated == 2) // q2bsp
6590                                 t = t->anim_frames[0][ent->framegroupblend[0].frame % t->anim_total[0]];
6591                         else if (rsurface.ent_alttextures && t->anim_total[1])
6592                                 t = t->anim_frames[1][(t->anim_total[1] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[1]) : 0];
6593                         else
6594                                 t = t->anim_frames[0][(t->anim_total[0] >= 2) ? ((int)(rsurface.shadertime * 5.0f) % t->anim_total[0]) : 0];
6595                 }
6596                 texture->currentframe = t;
6597         }
6598
6599         // update currentskinframe to be a qw skin or animation frame
6600         if (rsurface.ent_qwskin >= 0)
6601         {
6602                 i = rsurface.ent_qwskin;
6603                 if (!r_qwskincache || r_qwskincache_size != cl.maxclients)
6604                 {
6605                         r_qwskincache_size = cl.maxclients;
6606                         if (r_qwskincache)
6607                                 Mem_Free(r_qwskincache);
6608                         r_qwskincache = (r_qwskincache_t *)Mem_Alloc(r_main_mempool, sizeof(*r_qwskincache) * r_qwskincache_size);
6609                 }
6610                 if (strcmp(r_qwskincache[i].name, cl.scores[i].qw_skin))
6611                         R_LoadQWSkin(&r_qwskincache[i], cl.scores[i].qw_skin);
6612                 t->currentskinframe = r_qwskincache[i].skinframe;
6613                 if (t->materialshaderpass && t->currentskinframe == NULL)
6614                         t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6615         }
6616         else if (t->materialshaderpass && t->materialshaderpass->numframes >= 2)
6617                 t->currentskinframe = t->materialshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->materialshaderpass->framerate, t->materialshaderpass->numframes)];
6618         if (t->backgroundshaderpass && t->backgroundshaderpass->numframes >= 2)
6619                 t->backgroundcurrentskinframe = t->backgroundshaderpass->skinframes[LoopingFrameNumberFromDouble(rsurface.shadertime * t->backgroundshaderpass->framerate, t->backgroundshaderpass->numframes)];
6620
6621         t->currentmaterialflags = t->basematerialflags;
6622         t->currentalpha = rsurface.entity->alpha * t->basealpha;
6623         if (t->basematerialflags & MATERIALFLAG_WATERALPHA && (model->brush.supportwateralpha || r_water.integer || r_novis.integer || r_trippy.integer))
6624                 t->currentalpha *= r_wateralpha.value;
6625         if(t->basematerialflags & MATERIALFLAG_WATERSHADER && r_fb.water.enabled && !r_refdef.view.isoverlay)
6626                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW; // we apply wateralpha later
6627         if(!r_fb.water.enabled || r_refdef.view.isoverlay)
6628                 t->currentmaterialflags &= ~(MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA);
6629
6630         // decide on which type of lighting to use for this surface
6631         if (rsurface.entity->render_modellight_forced)
6632                 t->currentmaterialflags |= MATERIALFLAG_MODELLIGHT;
6633         if (rsurface.entity->render_rtlight_disabled)
6634                 t->currentmaterialflags |= MATERIALFLAG_NORTLIGHT;
6635         if (rsurface.entity->render_lightgrid)
6636                 t->currentmaterialflags |= MATERIALFLAG_LIGHTGRID;
6637         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND && !(R_BlendFuncFlags(t->customblendfunc[0], t->customblendfunc[1]) & BLENDFUNC_ALLOWS_COLORMOD))
6638         {
6639                 // some CUSTOMBLEND blendfuncs are too weird, we have to ignore colormod and view colorscale
6640                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NORTLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6641                 for (q = 0; q < 3; q++)
6642                 {
6643                         t->render_glowmod[q] = rsurface.entity->glowmod[q];
6644                         t->render_modellight_lightdir_world[q] = q == 2;
6645                         t->render_modellight_lightdir_local[q] = q == 2;
6646                         t->render_modellight_ambient[q] = 1;
6647                         t->render_modellight_diffuse[q] = 0;
6648                         t->render_modellight_specular[q] = 0;
6649                         t->render_lightmap_ambient[q] = 0;
6650                         t->render_lightmap_diffuse[q] = 0;
6651                         t->render_lightmap_specular[q] = 0;
6652                         t->render_rtlight_diffuse[q] = 0;
6653                         t->render_rtlight_specular[q] = 0;
6654                 }
6655         }
6656         else if ((t->currentmaterialflags & MATERIALFLAG_FULLBRIGHT) || !(rsurface.ent_flags & RENDER_LIGHT))
6657         {
6658                 // fullbright is basically MATERIALFLAG_MODELLIGHT but with ambient locked to 1,1,1 and no shading
6659                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_NORTLIGHT | MATERIALFLAG_MODELLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6660                 for (q = 0; q < 3; q++)
6661                 {
6662                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6663                         t->render_modellight_ambient[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6664                         t->render_modellight_lightdir_world[q] = q == 2;
6665                         t->render_modellight_lightdir_local[q] = q == 2;
6666                         t->render_modellight_diffuse[q] = 0;
6667                         t->render_modellight_specular[q] = 0;
6668                         t->render_lightmap_ambient[q] = 0;
6669                         t->render_lightmap_diffuse[q] = 0;
6670                         t->render_lightmap_specular[q] = 0;
6671                         t->render_rtlight_diffuse[q] = 0;
6672                         t->render_rtlight_specular[q] = 0;
6673                 }
6674         }
6675         else if (t->currentmaterialflags & MATERIALFLAG_LIGHTGRID)
6676         {
6677                 t->currentmaterialflags &= ~MATERIALFLAG_MODELLIGHT;
6678                 for (q = 0; q < 3; q++)
6679                 {
6680                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6681                         t->render_modellight_lightdir_world[q] = q == 2;
6682                         t->render_modellight_lightdir_local[q] = q == 2;
6683                         t->render_modellight_ambient[q] = 0;
6684                         t->render_modellight_diffuse[q] = 0;
6685                         t->render_modellight_specular[q] = 0;
6686                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6687                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6688                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6689                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6690                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6691                 }
6692         }
6693         else if ((rsurface.ent_flags & (RENDER_DYNAMICMODELLIGHT | RENDER_CUSTOMIZEDMODELLIGHT)) || rsurface.modeltexcoordlightmap2f == NULL)
6694         {
6695                 // ambient + single direction light (modellight)
6696                 t->currentmaterialflags = (t->currentmaterialflags | MATERIALFLAG_MODELLIGHT) & ~MATERIALFLAG_LIGHTGRID;
6697                 for (q = 0; q < 3; q++)
6698                 {
6699                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6700                         t->render_modellight_lightdir_world[q] = rsurface.entity->render_modellight_lightdir_world[q];
6701                         t->render_modellight_lightdir_local[q] = rsurface.entity->render_modellight_lightdir_local[q];
6702                         t->render_modellight_ambient[q] = rsurface.entity->render_modellight_ambient[q] * r_refdef.view.colorscale;
6703                         t->render_modellight_diffuse[q] = rsurface.entity->render_modellight_diffuse[q] * r_refdef.view.colorscale;
6704                         t->render_modellight_specular[q] = rsurface.entity->render_modellight_specular[q] * r_refdef.view.colorscale;
6705                         t->render_lightmap_ambient[q] = 0;
6706                         t->render_lightmap_diffuse[q] = 0;
6707                         t->render_lightmap_specular[q] = 0;
6708                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6709                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6710                 }
6711         }
6712         else
6713         {
6714                 // lightmap - 2x diffuse and specular brightness because bsp files have 0-2 colors as 0-1
6715                 for (q = 0; q < 3; q++)
6716                 {
6717                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6718                         t->render_modellight_lightdir_world[q] = q == 2;
6719                         t->render_modellight_lightdir_local[q] = q == 2;
6720                         t->render_modellight_ambient[q] = 0;
6721                         t->render_modellight_diffuse[q] = 0;
6722                         t->render_modellight_specular[q] = 0;
6723                         t->render_lightmap_ambient[q] = rsurface.entity->render_lightmap_ambient[q] * r_refdef.view.colorscale;
6724                         t->render_lightmap_diffuse[q] = rsurface.entity->render_lightmap_diffuse[q] * 2 * r_refdef.view.colorscale;
6725                         t->render_lightmap_specular[q] = rsurface.entity->render_lightmap_specular[q] * 2 * r_refdef.view.colorscale;
6726                         t->render_rtlight_diffuse[q] = rsurface.entity->render_rtlight_diffuse[q] * r_refdef.view.colorscale;
6727                         t->render_rtlight_specular[q] = rsurface.entity->render_rtlight_specular[q] * r_refdef.view.colorscale;
6728                 }
6729         }
6730
6731         if (t->currentmaterialflags & MATERIALFLAG_VERTEXCOLOR)
6732         {
6733                 // since MATERIALFLAG_VERTEXCOLOR uses the lightmapcolor4f vertex
6734                 // attribute, we punt it to the lightmap path and hope for the best,
6735                 // but lighting doesn't work.
6736                 //
6737                 // FIXME: this is fine for effects but CSQC polygons should be subject
6738                 // to lighting.
6739                 t->currentmaterialflags &= ~(MATERIALFLAG_MODELLIGHT | MATERIALFLAG_LIGHTGRID);
6740                 for (q = 0; q < 3; q++)
6741                 {
6742                         t->render_glowmod[q] = rsurface.entity->render_glowmod[q] * r_refdef.view.colorscale;
6743                         t->render_modellight_lightdir_world[q] = q == 2;
6744                         t->render_modellight_lightdir_local[q] = q == 2;
6745                         t->render_modellight_ambient[q] = 0;
6746                         t->render_modellight_diffuse[q] = 0;
6747                         t->render_modellight_specular[q] = 0;
6748                         t->render_lightmap_ambient[q] = 0;
6749                         t->render_lightmap_diffuse[q] = rsurface.entity->render_fullbright[q] * r_refdef.view.colorscale;
6750                         t->render_lightmap_specular[q] = 0;
6751                         t->render_rtlight_diffuse[q] = 0;
6752                         t->render_rtlight_specular[q] = 0;
6753                 }
6754         }
6755
6756         for (q = 0; q < 3; q++)
6757         {
6758                 t->render_colormap_pants[q] = rsurface.entity->colormap_pantscolor[q];
6759                 t->render_colormap_shirt[q] = rsurface.entity->colormap_shirtcolor[q];
6760         }
6761
6762         if (rsurface.ent_flags & RENDER_ADDITIVE)
6763                 t->currentmaterialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6764         else if (t->currentalpha < 1)
6765                 t->currentmaterialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
6766         // LadyHavoc: prevent bugs where code checks add or alpha at higher priority than customblend by clearing these flags
6767         if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6768                 t->currentmaterialflags &= ~(MATERIALFLAG_ADD | MATERIALFLAG_ALPHA);
6769         if (rsurface.ent_flags & RENDER_DOUBLESIDED)
6770                 t->currentmaterialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
6771         if (rsurface.ent_flags & (RENDER_NODEPTHTEST | RENDER_VIEWMODEL))
6772                 t->currentmaterialflags |= MATERIALFLAG_SHORTDEPTHRANGE;
6773         if (t->backgroundshaderpass)
6774                 t->currentmaterialflags |= MATERIALFLAG_VERTEXTEXTUREBLEND;
6775         if (t->currentmaterialflags & MATERIALFLAG_BLENDED)
6776         {
6777                 if (t->currentmaterialflags & (MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA))
6778                         t->currentmaterialflags &= ~MATERIALFLAG_BLENDED;
6779         }
6780         else
6781                 t->currentmaterialflags &= ~(MATERIALFLAG_REFRACTION | MATERIALFLAG_WATERSHADER | MATERIALFLAG_CAMERA);
6782         if (vid.allowalphatocoverage && r_transparent_alphatocoverage.integer >= 2 && ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA | MATERIALFLAG_ADD | MATERIALFLAG_CUSTOMBLEND)) == (MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)))
6783         {
6784                 // promote alphablend to alphatocoverage (a type of alphatest) if antialiasing is on
6785                 t->currentmaterialflags = (t->currentmaterialflags & ~(MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHA)) | MATERIALFLAG_ALPHATEST;
6786         }
6787         if ((t->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST)) == MATERIALFLAG_BLENDED && r_transparentdepthmasking.integer && !(t->basematerialflags & MATERIALFLAG_BLENDED))
6788                 t->currentmaterialflags |= MATERIALFLAG_TRANSDEPTH;
6789
6790         // there is no tcmod
6791         if (t->currentmaterialflags & MATERIALFLAG_WATERSCROLL)
6792         {
6793                 t->currenttexmatrix = r_waterscrollmatrix;
6794                 t->currentbackgroundtexmatrix = r_waterscrollmatrix;
6795         }
6796         else if (!(t->currentmaterialflags & MATERIALFLAG_CUSTOMSURFACE))
6797         {
6798                 Matrix4x4_CreateIdentity(&t->currenttexmatrix);
6799                 Matrix4x4_CreateIdentity(&t->currentbackgroundtexmatrix);
6800         }
6801
6802         if (t->materialshaderpass)
6803                 for (i = 0, tcmod = t->materialshaderpass->tcmods;i < Q3MAXTCMODS && tcmod->tcmod;i++, tcmod++)
6804                         R_tcMod_ApplyToMatrix(&t->currenttexmatrix, tcmod, t->currentmaterialflags);
6805
6806         t->colormapping = VectorLength2(t->render_colormap_pants) + VectorLength2(t->render_colormap_shirt) >= (1.0f / 1048576.0f);
6807         if (t->currentskinframe->qpixels)
6808                 R_SkinFrame_GenerateTexturesFromQPixels(t->currentskinframe, t->colormapping);
6809         t->basetexture = (!t->colormapping && t->currentskinframe->merged) ? t->currentskinframe->merged : t->currentskinframe->base;
6810         if (!t->basetexture)
6811                 t->basetexture = r_texture_notexture;
6812         t->pantstexture = t->colormapping ? t->currentskinframe->pants : NULL;
6813         t->shirttexture = t->colormapping ? t->currentskinframe->shirt : NULL;
6814         t->nmaptexture = t->currentskinframe->nmap;
6815         if (!t->nmaptexture)
6816                 t->nmaptexture = r_texture_blanknormalmap;
6817         t->glosstexture = r_texture_black;
6818         t->glowtexture = t->currentskinframe->glow;
6819         t->fogtexture = t->currentskinframe->fog;
6820         t->reflectmasktexture = t->currentskinframe->reflect;
6821         if (t->backgroundshaderpass)
6822         {
6823                 for (i = 0, tcmod = t->backgroundshaderpass->tcmods; i < Q3MAXTCMODS && tcmod->tcmod; i++, tcmod++)
6824                         R_tcMod_ApplyToMatrix(&t->currentbackgroundtexmatrix, tcmod, t->currentmaterialflags);
6825                 t->backgroundbasetexture = (!t->colormapping && t->backgroundcurrentskinframe->merged) ? t->backgroundcurrentskinframe->merged : t->backgroundcurrentskinframe->base;
6826                 t->backgroundnmaptexture = t->backgroundcurrentskinframe->nmap;
6827                 t->backgroundglosstexture = r_texture_black;
6828                 t->backgroundglowtexture = t->backgroundcurrentskinframe->glow;
6829                 if (!t->backgroundnmaptexture)
6830                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6831                 // make sure that if glow is going to be used, both textures are not NULL
6832                 if (!t->backgroundglowtexture && t->glowtexture)
6833                         t->backgroundglowtexture = r_texture_black;
6834                 if (!t->glowtexture && t->backgroundglowtexture)
6835                         t->glowtexture = r_texture_black;
6836         }
6837         else
6838         {
6839                 t->backgroundbasetexture = r_texture_white;
6840                 t->backgroundnmaptexture = r_texture_blanknormalmap;
6841                 t->backgroundglosstexture = r_texture_black;
6842                 t->backgroundglowtexture = NULL;
6843         }
6844         t->specularpower = r_shadow_glossexponent.value;
6845         // TODO: store reference values for these in the texture?
6846         if (r_shadow_gloss.integer > 0)
6847         {
6848                 if (t->currentskinframe->gloss || (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss))
6849                 {
6850                         if (r_shadow_glossintensity.value > 0)
6851                         {
6852                                 t->glosstexture = t->currentskinframe->gloss ? t->currentskinframe->gloss : r_texture_white;
6853                                 t->backgroundglosstexture = (t->backgroundcurrentskinframe && t->backgroundcurrentskinframe->gloss) ? t->backgroundcurrentskinframe->gloss : r_texture_white;
6854                                 specularscale = r_shadow_glossintensity.value;
6855                         }
6856                 }
6857                 else if (r_shadow_gloss.integer >= 2 && r_shadow_gloss2intensity.value > 0)
6858                 {
6859                         t->glosstexture = r_texture_white;
6860                         t->backgroundglosstexture = r_texture_white;
6861                         specularscale = r_shadow_gloss2intensity.value;
6862                         t->specularpower = r_shadow_gloss2exponent.value;
6863                 }
6864         }
6865         specularscale *= t->specularscalemod;
6866         t->specularpower *= t->specularpowermod;
6867
6868         // lightmaps mode looks bad with dlights using actual texturing, so turn
6869         // off the colormap and glossmap, but leave the normalmap on as it still
6870         // accurately represents the shading involved
6871         if (gl_lightmaps.integer && ent != &cl_meshentities[MESH_UI].render)
6872         {
6873                 t->basetexture = r_texture_grey128;
6874                 t->pantstexture = r_texture_black;
6875                 t->shirttexture = r_texture_black;
6876                 if (gl_lightmaps.integer < 2)
6877                         t->nmaptexture = r_texture_blanknormalmap;
6878                 t->glosstexture = r_texture_black;
6879                 t->glowtexture = NULL;
6880                 t->fogtexture = NULL;
6881                 t->reflectmasktexture = NULL;
6882                 t->backgroundbasetexture = NULL;
6883                 if (gl_lightmaps.integer < 2)
6884                         t->backgroundnmaptexture = r_texture_blanknormalmap;
6885                 t->backgroundglosstexture = r_texture_black;
6886                 t->backgroundglowtexture = NULL;
6887                 specularscale = 0;
6888                 t->currentmaterialflags = MATERIALFLAG_WALL | (t->currentmaterialflags & (MATERIALFLAG_NOCULLFACE | MATERIALFLAG_MODELLIGHT | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SHORTDEPTHRANGE));
6889         }
6890
6891         if (specularscale != 1.0f)
6892         {
6893                 for (q = 0; q < 3; q++)
6894                 {
6895                         t->render_modellight_specular[q] *= specularscale;
6896                         t->render_lightmap_specular[q] *= specularscale;
6897                         t->render_rtlight_specular[q] *= specularscale;
6898                 }
6899         }
6900
6901         t->currentblendfunc[0] = GL_ONE;
6902         t->currentblendfunc[1] = GL_ZERO;
6903         if (t->currentmaterialflags & MATERIALFLAG_ADD)
6904         {
6905                 t->currentblendfunc[0] = GL_SRC_ALPHA;
6906                 t->currentblendfunc[1] = GL_ONE;
6907         }
6908         else if (t->currentmaterialflags & MATERIALFLAG_ALPHA)
6909         {
6910                 t->currentblendfunc[0] = GL_SRC_ALPHA;
6911                 t->currentblendfunc[1] = GL_ONE_MINUS_SRC_ALPHA;
6912         }
6913         else if (t->currentmaterialflags & MATERIALFLAG_CUSTOMBLEND)
6914         {
6915                 t->currentblendfunc[0] = t->customblendfunc[0];
6916                 t->currentblendfunc[1] = t->customblendfunc[1];
6917         }
6918
6919         return t;
6920 }
6921
6922 rsurfacestate_t rsurface;
6923
6924 void RSurf_ActiveModelEntity(const entity_render_t *ent, qbool wantnormals, qbool wanttangents, qbool prepass)
6925 {
6926         model_t *model = ent->model;
6927         //if (rsurface.entity == ent && (!model->surfmesh.isanimated || (!wantnormals && !wanttangents)))
6928         //      return;
6929         rsurface.entity = (entity_render_t *)ent;
6930         rsurface.skeleton = ent->skeleton;
6931         memcpy(rsurface.userwavefunc_param, ent->userwavefunc_param, sizeof(rsurface.userwavefunc_param));
6932         rsurface.ent_skinnum = ent->skinnum;
6933         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;
6934         rsurface.ent_flags = ent->flags;
6935         if (r_fullbright_directed.integer && (r_fullbright.integer || !model->lit))
6936                 rsurface.ent_flags |= RENDER_LIGHT | RENDER_DYNAMICMODELLIGHT;
6937         rsurface.shadertime = r_refdef.scene.time - ent->shadertime;
6938         rsurface.matrix = ent->matrix;
6939         rsurface.inversematrix = ent->inversematrix;
6940         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
6941         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
6942         R_EntityMatrix(&rsurface.matrix);
6943         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
6944         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
6945         rsurface.fogplaneviewdist = r_refdef.fogplaneviewdist * rsurface.inversematrixscale;
6946         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
6947         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
6948         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
6949         memcpy(rsurface.frameblend, ent->frameblend, sizeof(ent->frameblend));
6950         rsurface.ent_alttextures = ent->framegroupblend[0].frame != 0;
6951         rsurface.basepolygonfactor = r_refdef.polygonfactor;
6952         rsurface.basepolygonoffset = r_refdef.polygonoffset;
6953         if (ent->model->brush.submodel && !prepass)
6954         {
6955                 rsurface.basepolygonfactor += r_polygonoffset_submodel_factor.value;
6956                 rsurface.basepolygonoffset += r_polygonoffset_submodel_offset.value;
6957         }
6958         // if the animcache code decided it should use the shader path, skip the deform step
6959         rsurface.entityskeletaltransform3x4 = ent->animcache_skeletaltransform3x4;
6960         rsurface.entityskeletaltransform3x4buffer = ent->animcache_skeletaltransform3x4buffer;
6961         rsurface.entityskeletaltransform3x4offset = ent->animcache_skeletaltransform3x4offset;
6962         rsurface.entityskeletaltransform3x4size = ent->animcache_skeletaltransform3x4size;
6963         rsurface.entityskeletalnumtransforms = rsurface.entityskeletaltransform3x4 ? model->num_bones : 0;
6964         if (model->surfmesh.isanimated && model->AnimateVertices && !rsurface.entityskeletaltransform3x4)
6965         {
6966                 if (ent->animcache_vertex3f)
6967                 {
6968                         r_refdef.stats[r_stat_batch_entitycache_count]++;
6969                         r_refdef.stats[r_stat_batch_entitycache_surfaces] += model->num_surfaces;
6970                         r_refdef.stats[r_stat_batch_entitycache_vertices] += model->surfmesh.num_vertices;
6971                         r_refdef.stats[r_stat_batch_entitycache_triangles] += model->surfmesh.num_triangles;
6972                         rsurface.modelvertex3f = ent->animcache_vertex3f;
6973                         rsurface.modelvertex3f_vertexbuffer = ent->animcache_vertex3f_vertexbuffer;
6974                         rsurface.modelvertex3f_bufferoffset = ent->animcache_vertex3f_bufferoffset;
6975                         rsurface.modelsvector3f = wanttangents ? ent->animcache_svector3f : NULL;
6976                         rsurface.modelsvector3f_vertexbuffer = wanttangents ? ent->animcache_svector3f_vertexbuffer : NULL;
6977                         rsurface.modelsvector3f_bufferoffset = wanttangents ? ent->animcache_svector3f_bufferoffset : 0;
6978                         rsurface.modeltvector3f = wanttangents ? ent->animcache_tvector3f : NULL;
6979                         rsurface.modeltvector3f_vertexbuffer = wanttangents ? ent->animcache_tvector3f_vertexbuffer : NULL;
6980                         rsurface.modeltvector3f_bufferoffset = wanttangents ? ent->animcache_tvector3f_bufferoffset : 0;
6981                         rsurface.modelnormal3f = wantnormals ? ent->animcache_normal3f : NULL;
6982                         rsurface.modelnormal3f_vertexbuffer = wantnormals ? ent->animcache_normal3f_vertexbuffer : NULL;
6983                         rsurface.modelnormal3f_bufferoffset = wantnormals ? ent->animcache_normal3f_bufferoffset : 0;
6984                 }
6985                 else if (wanttangents)
6986                 {
6987                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
6988                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
6989                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
6990                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
6991                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6992                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6993                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6994                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
6995                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, rsurface.modelsvector3f, rsurface.modeltvector3f);
6996                         rsurface.modelvertex3f_vertexbuffer = NULL;
6997                         rsurface.modelvertex3f_bufferoffset = 0;
6998                         rsurface.modelvertex3f_vertexbuffer = 0;
6999                         rsurface.modelvertex3f_bufferoffset = 0;
7000                         rsurface.modelsvector3f_vertexbuffer = 0;
7001                         rsurface.modelsvector3f_bufferoffset = 0;
7002                         rsurface.modeltvector3f_vertexbuffer = 0;
7003                         rsurface.modeltvector3f_bufferoffset = 0;
7004                         rsurface.modelnormal3f_vertexbuffer = 0;
7005                         rsurface.modelnormal3f_bufferoffset = 0;
7006                 }
7007                 else if (wantnormals)
7008                 {
7009                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7010                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7011                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7012                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7013                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7014                         rsurface.modelsvector3f = NULL;
7015                         rsurface.modeltvector3f = NULL;
7016                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7017                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, rsurface.modelnormal3f, NULL, NULL);
7018                         rsurface.modelvertex3f_vertexbuffer = NULL;
7019                         rsurface.modelvertex3f_bufferoffset = 0;
7020                         rsurface.modelvertex3f_vertexbuffer = 0;
7021                         rsurface.modelvertex3f_bufferoffset = 0;
7022                         rsurface.modelsvector3f_vertexbuffer = 0;
7023                         rsurface.modelsvector3f_bufferoffset = 0;
7024                         rsurface.modeltvector3f_vertexbuffer = 0;
7025                         rsurface.modeltvector3f_bufferoffset = 0;
7026                         rsurface.modelnormal3f_vertexbuffer = 0;
7027                         rsurface.modelnormal3f_bufferoffset = 0;
7028                 }
7029                 else
7030                 {
7031                         r_refdef.stats[r_stat_batch_entityanimate_count]++;
7032                         r_refdef.stats[r_stat_batch_entityanimate_surfaces] += model->num_surfaces;
7033                         r_refdef.stats[r_stat_batch_entityanimate_vertices] += model->surfmesh.num_vertices;
7034                         r_refdef.stats[r_stat_batch_entityanimate_triangles] += model->surfmesh.num_triangles;
7035                         rsurface.modelvertex3f = (float *)R_FrameData_Alloc(model->surfmesh.num_vertices * sizeof(float[3]));
7036                         rsurface.modelsvector3f = NULL;
7037                         rsurface.modeltvector3f = NULL;
7038                         rsurface.modelnormal3f = NULL;
7039                         model->AnimateVertices(model, rsurface.frameblend, rsurface.skeleton, rsurface.modelvertex3f, NULL, NULL, NULL);
7040                         rsurface.modelvertex3f_vertexbuffer = NULL;
7041                         rsurface.modelvertex3f_bufferoffset = 0;
7042                         rsurface.modelvertex3f_vertexbuffer = 0;
7043                         rsurface.modelvertex3f_bufferoffset = 0;
7044                         rsurface.modelsvector3f_vertexbuffer = 0;
7045                         rsurface.modelsvector3f_bufferoffset = 0;
7046                         rsurface.modeltvector3f_vertexbuffer = 0;
7047                         rsurface.modeltvector3f_bufferoffset = 0;
7048                         rsurface.modelnormal3f_vertexbuffer = 0;
7049                         rsurface.modelnormal3f_bufferoffset = 0;
7050                 }
7051                 rsurface.modelgeneratedvertex = true;
7052         }
7053         else
7054         {
7055                 if (rsurface.entityskeletaltransform3x4)
7056                 {
7057                         r_refdef.stats[r_stat_batch_entityskeletal_count]++;
7058                         r_refdef.stats[r_stat_batch_entityskeletal_surfaces] += model->num_surfaces;
7059                         r_refdef.stats[r_stat_batch_entityskeletal_vertices] += model->surfmesh.num_vertices;
7060                         r_refdef.stats[r_stat_batch_entityskeletal_triangles] += model->surfmesh.num_triangles;
7061                 }
7062                 else
7063                 {
7064                         r_refdef.stats[r_stat_batch_entitystatic_count]++;
7065                         r_refdef.stats[r_stat_batch_entitystatic_surfaces] += model->num_surfaces;
7066                         r_refdef.stats[r_stat_batch_entitystatic_vertices] += model->surfmesh.num_vertices;
7067                         r_refdef.stats[r_stat_batch_entitystatic_triangles] += model->surfmesh.num_triangles;
7068                 }
7069                 rsurface.modelvertex3f  = model->surfmesh.data_vertex3f;
7070                 rsurface.modelvertex3f_vertexbuffer = model->surfmesh.data_vertex3f_vertexbuffer;
7071                 rsurface.modelvertex3f_bufferoffset = model->surfmesh.data_vertex3f_bufferoffset;
7072                 rsurface.modelsvector3f = model->surfmesh.data_svector3f;
7073                 rsurface.modelsvector3f_vertexbuffer = model->surfmesh.data_svector3f_vertexbuffer;
7074                 rsurface.modelsvector3f_bufferoffset = model->surfmesh.data_svector3f_bufferoffset;
7075                 rsurface.modeltvector3f = model->surfmesh.data_tvector3f;
7076                 rsurface.modeltvector3f_vertexbuffer = model->surfmesh.data_tvector3f_vertexbuffer;
7077                 rsurface.modeltvector3f_bufferoffset = model->surfmesh.data_tvector3f_bufferoffset;
7078                 rsurface.modelnormal3f  = model->surfmesh.data_normal3f;
7079                 rsurface.modelnormal3f_vertexbuffer = model->surfmesh.data_normal3f_vertexbuffer;
7080                 rsurface.modelnormal3f_bufferoffset = model->surfmesh.data_normal3f_bufferoffset;
7081                 rsurface.modelgeneratedvertex = false;
7082         }
7083         rsurface.modellightmapcolor4f  = model->surfmesh.data_lightmapcolor4f;
7084         rsurface.modellightmapcolor4f_vertexbuffer = model->surfmesh.data_lightmapcolor4f_vertexbuffer;
7085         rsurface.modellightmapcolor4f_bufferoffset = model->surfmesh.data_lightmapcolor4f_bufferoffset;
7086         rsurface.modeltexcoordtexture2f  = model->surfmesh.data_texcoordtexture2f;
7087         rsurface.modeltexcoordtexture2f_vertexbuffer = model->surfmesh.data_texcoordtexture2f_vertexbuffer;
7088         rsurface.modeltexcoordtexture2f_bufferoffset = model->surfmesh.data_texcoordtexture2f_bufferoffset;
7089         rsurface.modeltexcoordlightmap2f  = model->surfmesh.data_texcoordlightmap2f;
7090         rsurface.modeltexcoordlightmap2f_vertexbuffer = model->surfmesh.data_texcoordlightmap2f_vertexbuffer;
7091         rsurface.modeltexcoordlightmap2f_bufferoffset = model->surfmesh.data_texcoordlightmap2f_bufferoffset;
7092         rsurface.modelskeletalindex4ub = model->surfmesh.data_skeletalindex4ub;
7093         rsurface.modelskeletalindex4ub_vertexbuffer = model->surfmesh.data_skeletalindex4ub_vertexbuffer;
7094         rsurface.modelskeletalindex4ub_bufferoffset = model->surfmesh.data_skeletalindex4ub_bufferoffset;
7095         rsurface.modelskeletalweight4ub = model->surfmesh.data_skeletalweight4ub;
7096         rsurface.modelskeletalweight4ub_vertexbuffer = model->surfmesh.data_skeletalweight4ub_vertexbuffer;
7097         rsurface.modelskeletalweight4ub_bufferoffset = model->surfmesh.data_skeletalweight4ub_bufferoffset;
7098         rsurface.modelelement3i = model->surfmesh.data_element3i;
7099         rsurface.modelelement3i_indexbuffer = model->surfmesh.data_element3i_indexbuffer;
7100         rsurface.modelelement3i_bufferoffset = model->surfmesh.data_element3i_bufferoffset;
7101         rsurface.modelelement3s = model->surfmesh.data_element3s;
7102         rsurface.modelelement3s_indexbuffer = model->surfmesh.data_element3s_indexbuffer;
7103         rsurface.modelelement3s_bufferoffset = model->surfmesh.data_element3s_bufferoffset;
7104         rsurface.modellightmapoffsets = model->surfmesh.data_lightmapoffsets;
7105         rsurface.modelnumvertices = model->surfmesh.num_vertices;
7106         rsurface.modelnumtriangles = model->surfmesh.num_triangles;
7107         rsurface.modelsurfaces = model->data_surfaces;
7108         rsurface.batchgeneratedvertex = false;
7109         rsurface.batchfirstvertex = 0;
7110         rsurface.batchnumvertices = 0;
7111         rsurface.batchfirsttriangle = 0;
7112         rsurface.batchnumtriangles = 0;
7113         rsurface.batchvertex3f  = NULL;
7114         rsurface.batchvertex3f_vertexbuffer = NULL;
7115         rsurface.batchvertex3f_bufferoffset = 0;
7116         rsurface.batchsvector3f = NULL;
7117         rsurface.batchsvector3f_vertexbuffer = NULL;
7118         rsurface.batchsvector3f_bufferoffset = 0;
7119         rsurface.batchtvector3f = NULL;
7120         rsurface.batchtvector3f_vertexbuffer = NULL;
7121         rsurface.batchtvector3f_bufferoffset = 0;
7122         rsurface.batchnormal3f  = NULL;
7123         rsurface.batchnormal3f_vertexbuffer = NULL;
7124         rsurface.batchnormal3f_bufferoffset = 0;
7125         rsurface.batchlightmapcolor4f = NULL;
7126         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7127         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7128         rsurface.batchtexcoordtexture2f = NULL;
7129         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7130         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7131         rsurface.batchtexcoordlightmap2f = NULL;
7132         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7133         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7134         rsurface.batchskeletalindex4ub = NULL;
7135         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7136         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7137         rsurface.batchskeletalweight4ub = NULL;
7138         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7139         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7140         rsurface.batchelement3i = NULL;
7141         rsurface.batchelement3i_indexbuffer = NULL;
7142         rsurface.batchelement3i_bufferoffset = 0;
7143         rsurface.batchelement3s = NULL;
7144         rsurface.batchelement3s_indexbuffer = NULL;
7145         rsurface.batchelement3s_bufferoffset = 0;
7146         rsurface.forcecurrenttextureupdate = false;
7147 }
7148
7149 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, qbool wantnormals, qbool wanttangents)
7150 {
7151         rsurface.entity = r_refdef.scene.worldentity;
7152         if (r != 1.0f || g != 1.0f || b != 1.0f || a != 1.0f) {
7153                 // HACK to provide a valid entity with modded colors to R_GetCurrentTexture.
7154                 // A better approach could be making this copy only once per frame.
7155                 static entity_render_t custom_entity;
7156                 int q;
7157                 custom_entity = *rsurface.entity;
7158                 for (q = 0; q < 3; ++q) {
7159                         float colormod = q == 0 ? r : q == 1 ? g : b;
7160                         custom_entity.render_fullbright[q] *= colormod;
7161                         custom_entity.render_modellight_ambient[q] *= colormod;
7162                         custom_entity.render_modellight_diffuse[q] *= colormod;
7163                         custom_entity.render_lightmap_ambient[q] *= colormod;
7164                         custom_entity.render_lightmap_diffuse[q] *= colormod;
7165                         custom_entity.render_rtlight_diffuse[q] *= colormod;
7166                 }
7167                 custom_entity.alpha *= a;
7168                 rsurface.entity = &custom_entity;
7169         }
7170         rsurface.skeleton = NULL;
7171         rsurface.ent_skinnum = 0;
7172         rsurface.ent_qwskin = -1;
7173         rsurface.ent_flags = entflags;
7174         rsurface.shadertime = r_refdef.scene.time - shadertime;
7175         rsurface.modelnumvertices = numvertices;
7176         rsurface.modelnumtriangles = numtriangles;
7177         rsurface.matrix = *matrix;
7178         rsurface.inversematrix = *inversematrix;
7179         rsurface.matrixscale = Matrix4x4_ScaleFromMatrix(&rsurface.matrix);
7180         rsurface.inversematrixscale = 1.0f / rsurface.matrixscale;
7181         R_EntityMatrix(&rsurface.matrix);
7182         Matrix4x4_Transform(&rsurface.inversematrix, r_refdef.view.origin, rsurface.localvieworigin);
7183         Matrix4x4_TransformStandardPlane(&rsurface.inversematrix, r_refdef.fogplane[0], r_refdef.fogplane[1], r_refdef.fogplane[2], r_refdef.fogplane[3], rsurface.fogplane);
7184         rsurface.fogplaneviewdist *= rsurface.inversematrixscale;
7185         rsurface.fograngerecip = r_refdef.fograngerecip * rsurface.matrixscale;
7186         rsurface.fogheightfade = r_refdef.fogheightfade * rsurface.matrixscale;
7187         rsurface.fogmasktabledistmultiplier = FOGMASKTABLEWIDTH * rsurface.fograngerecip;
7188         memset(rsurface.frameblend, 0, sizeof(rsurface.frameblend));
7189         rsurface.frameblend[0].lerp = 1;
7190         rsurface.ent_alttextures = false;
7191         rsurface.basepolygonfactor = r_refdef.polygonfactor;
7192         rsurface.basepolygonoffset = r_refdef.polygonoffset;
7193         rsurface.entityskeletaltransform3x4 = NULL;
7194         rsurface.entityskeletaltransform3x4buffer = NULL;
7195         rsurface.entityskeletaltransform3x4offset = 0;
7196         rsurface.entityskeletaltransform3x4size = 0;
7197         rsurface.entityskeletalnumtransforms = 0;
7198         r_refdef.stats[r_stat_batch_entitycustom_count]++;
7199         r_refdef.stats[r_stat_batch_entitycustom_surfaces] += 1;
7200         r_refdef.stats[r_stat_batch_entitycustom_vertices] += rsurface.modelnumvertices;
7201         r_refdef.stats[r_stat_batch_entitycustom_triangles] += rsurface.modelnumtriangles;
7202         if (wanttangents)
7203         {
7204                 rsurface.modelvertex3f = (float *)vertex3f;
7205                 rsurface.modelsvector3f = svector3f ? (float *)svector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7206                 rsurface.modeltvector3f = tvector3f ? (float *)tvector3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7207                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7208         }
7209         else if (wantnormals)
7210         {
7211                 rsurface.modelvertex3f = (float *)vertex3f;
7212                 rsurface.modelsvector3f = NULL;
7213                 rsurface.modeltvector3f = NULL;
7214                 rsurface.modelnormal3f = normal3f ? (float *)normal3f : (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7215         }
7216         else
7217         {
7218                 rsurface.modelvertex3f = (float *)vertex3f;
7219                 rsurface.modelsvector3f = NULL;
7220                 rsurface.modeltvector3f = NULL;
7221                 rsurface.modelnormal3f = NULL;
7222         }
7223         rsurface.modelvertex3f_vertexbuffer = 0;
7224         rsurface.modelvertex3f_bufferoffset = 0;
7225         rsurface.modelsvector3f_vertexbuffer = 0;
7226         rsurface.modelsvector3f_bufferoffset = 0;
7227         rsurface.modeltvector3f_vertexbuffer = 0;
7228         rsurface.modeltvector3f_bufferoffset = 0;
7229         rsurface.modelnormal3f_vertexbuffer = 0;
7230         rsurface.modelnormal3f_bufferoffset = 0;
7231         rsurface.modelgeneratedvertex = true;
7232         rsurface.modellightmapcolor4f  = (float *)color4f;
7233         rsurface.modellightmapcolor4f_vertexbuffer = 0;
7234         rsurface.modellightmapcolor4f_bufferoffset = 0;
7235         rsurface.modeltexcoordtexture2f  = (float *)texcoord2f;
7236         rsurface.modeltexcoordtexture2f_vertexbuffer = 0;
7237         rsurface.modeltexcoordtexture2f_bufferoffset = 0;
7238         rsurface.modeltexcoordlightmap2f  = NULL;
7239         rsurface.modeltexcoordlightmap2f_vertexbuffer = 0;
7240         rsurface.modeltexcoordlightmap2f_bufferoffset = 0;
7241         rsurface.modelskeletalindex4ub = NULL;
7242         rsurface.modelskeletalindex4ub_vertexbuffer = NULL;
7243         rsurface.modelskeletalindex4ub_bufferoffset = 0;
7244         rsurface.modelskeletalweight4ub = NULL;
7245         rsurface.modelskeletalweight4ub_vertexbuffer = NULL;
7246         rsurface.modelskeletalweight4ub_bufferoffset = 0;
7247         rsurface.modelelement3i = (int *)element3i;
7248         rsurface.modelelement3i_indexbuffer = NULL;
7249         rsurface.modelelement3i_bufferoffset = 0;
7250         rsurface.modelelement3s = (unsigned short *)element3s;
7251         rsurface.modelelement3s_indexbuffer = NULL;
7252         rsurface.modelelement3s_bufferoffset = 0;
7253         rsurface.modellightmapoffsets = NULL;
7254         rsurface.modelsurfaces = NULL;
7255         rsurface.batchgeneratedvertex = false;
7256         rsurface.batchfirstvertex = 0;
7257         rsurface.batchnumvertices = 0;
7258         rsurface.batchfirsttriangle = 0;
7259         rsurface.batchnumtriangles = 0;
7260         rsurface.batchvertex3f  = NULL;
7261         rsurface.batchvertex3f_vertexbuffer = NULL;
7262         rsurface.batchvertex3f_bufferoffset = 0;
7263         rsurface.batchsvector3f = NULL;
7264         rsurface.batchsvector3f_vertexbuffer = NULL;
7265         rsurface.batchsvector3f_bufferoffset = 0;
7266         rsurface.batchtvector3f = NULL;
7267         rsurface.batchtvector3f_vertexbuffer = NULL;
7268         rsurface.batchtvector3f_bufferoffset = 0;
7269         rsurface.batchnormal3f  = NULL;
7270         rsurface.batchnormal3f_vertexbuffer = NULL;
7271         rsurface.batchnormal3f_bufferoffset = 0;
7272         rsurface.batchlightmapcolor4f = NULL;
7273         rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7274         rsurface.batchlightmapcolor4f_bufferoffset = 0;
7275         rsurface.batchtexcoordtexture2f = NULL;
7276         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7277         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7278         rsurface.batchtexcoordlightmap2f = NULL;
7279         rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7280         rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7281         rsurface.batchskeletalindex4ub = NULL;
7282         rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7283         rsurface.batchskeletalindex4ub_bufferoffset = 0;
7284         rsurface.batchskeletalweight4ub = NULL;
7285         rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7286         rsurface.batchskeletalweight4ub_bufferoffset = 0;
7287         rsurface.batchelement3i = NULL;
7288         rsurface.batchelement3i_indexbuffer = NULL;
7289         rsurface.batchelement3i_bufferoffset = 0;
7290         rsurface.batchelement3s = NULL;
7291         rsurface.batchelement3s_indexbuffer = NULL;
7292         rsurface.batchelement3s_bufferoffset = 0;
7293         rsurface.forcecurrenttextureupdate = true;
7294
7295         if (rsurface.modelnumvertices && rsurface.modelelement3i)
7296         {
7297                 if ((wantnormals || wanttangents) && !normal3f)
7298                 {
7299                         rsurface.modelnormal3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7300                         Mod_BuildNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modelelement3i, rsurface.modelnormal3f, r_smoothnormals_areaweighting.integer != 0);
7301                 }
7302                 if (wanttangents && !svector3f)
7303                 {
7304                         rsurface.modelsvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7305                         rsurface.modeltvector3f = (float *)R_FrameData_Alloc(rsurface.modelnumvertices * sizeof(float[3]));
7306                         Mod_BuildTextureVectorsFromNormals(0, rsurface.modelnumvertices, rsurface.modelnumtriangles, rsurface.modelvertex3f, rsurface.modeltexcoordtexture2f, rsurface.modelnormal3f, rsurface.modelelement3i, rsurface.modelsvector3f, rsurface.modeltvector3f, r_smoothnormals_areaweighting.integer != 0);
7307                 }
7308         }
7309 }
7310
7311 float RSurf_FogPoint(const float *v)
7312 {
7313         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7314         float FogPlaneViewDist = r_refdef.fogplaneviewdist;
7315         float FogPlaneVertexDist = DotProduct(r_refdef.fogplane, v) + r_refdef.fogplane[3];
7316         float FogHeightFade = r_refdef.fogheightfade;
7317         float fogfrac;
7318         unsigned int fogmasktableindex;
7319         if (r_refdef.fogplaneviewabove)
7320                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7321         else
7322                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7323         fogmasktableindex = (unsigned int)(VectorDistance(r_refdef.view.origin, v) * fogfrac * r_refdef.fogmasktabledistmultiplier);
7324         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7325 }
7326
7327 float RSurf_FogVertex(const float *v)
7328 {
7329         // this code is identical to the USEFOGINSIDE/USEFOGOUTSIDE code in the shader
7330         float FogPlaneViewDist = rsurface.fogplaneviewdist;
7331         float FogPlaneVertexDist = DotProduct(rsurface.fogplane, v) + rsurface.fogplane[3];
7332         float FogHeightFade = rsurface.fogheightfade;
7333         float fogfrac;
7334         unsigned int fogmasktableindex;
7335         if (r_refdef.fogplaneviewabove)
7336                 fogfrac = min(0.0f, FogPlaneVertexDist) / (FogPlaneVertexDist - FogPlaneViewDist) * min(1.0f, min(0.0f, FogPlaneVertexDist) * FogHeightFade);
7337         else
7338                 fogfrac = FogPlaneViewDist / (FogPlaneViewDist - max(0.0f, FogPlaneVertexDist)) * min(1.0f, (min(0.0f, FogPlaneVertexDist) + FogPlaneViewDist) * FogHeightFade);
7339         fogmasktableindex = (unsigned int)(VectorDistance(rsurface.localvieworigin, v) * fogfrac * rsurface.fogmasktabledistmultiplier);
7340         return r_refdef.fogmasktable[min(fogmasktableindex, FOGMASKTABLEWIDTH - 1)];
7341 }
7342
7343 void RSurf_UploadBuffersForBatch(void)
7344 {
7345         // upload buffer data for generated vertex data (dynamicvertex case) or index data (copytriangles case) and models that lack it to begin with (e.g. DrawQ_FlushUI)
7346         // note that if rsurface.batchvertex3f_vertexbuffer is NULL, dynamicvertex is forced as we don't account for the proper base vertex here.
7347         if (rsurface.batchvertex3f && !rsurface.batchvertex3f_vertexbuffer)
7348                 rsurface.batchvertex3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f, R_BUFFERDATA_VERTEX, &rsurface.batchvertex3f_bufferoffset);
7349         if (rsurface.batchsvector3f && !rsurface.batchsvector3f_vertexbuffer)
7350                 rsurface.batchsvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchsvector3f_bufferoffset);
7351         if (rsurface.batchtvector3f && !rsurface.batchtvector3f_vertexbuffer)
7352                 rsurface.batchtvector3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f, R_BUFFERDATA_VERTEX, &rsurface.batchtvector3f_bufferoffset);
7353         if (rsurface.batchnormal3f && !rsurface.batchnormal3f_vertexbuffer)
7354                 rsurface.batchnormal3f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f, R_BUFFERDATA_VERTEX, &rsurface.batchnormal3f_bufferoffset);
7355         if (rsurface.batchlightmapcolor4f && !rsurface.batchlightmapcolor4f_vertexbuffer)
7356                 rsurface.batchlightmapcolor4f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[4]), rsurface.batchlightmapcolor4f, R_BUFFERDATA_VERTEX, &rsurface.batchlightmapcolor4f_bufferoffset);
7357         if (rsurface.batchtexcoordtexture2f && !rsurface.batchtexcoordtexture2f_vertexbuffer)
7358                 rsurface.batchtexcoordtexture2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordtexture2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordtexture2f_bufferoffset);
7359         if (rsurface.batchtexcoordlightmap2f && !rsurface.batchtexcoordlightmap2f_vertexbuffer)
7360                 rsurface.batchtexcoordlightmap2f_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(float[2]), rsurface.batchtexcoordlightmap2f, R_BUFFERDATA_VERTEX, &rsurface.batchtexcoordlightmap2f_bufferoffset);
7361         if (rsurface.batchskeletalindex4ub && !rsurface.batchskeletalindex4ub_vertexbuffer)
7362                 rsurface.batchskeletalindex4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalindex4ub_bufferoffset);
7363         if (rsurface.batchskeletalweight4ub && !rsurface.batchskeletalweight4ub_vertexbuffer)
7364                 rsurface.batchskeletalweight4ub_vertexbuffer = R_BufferData_Store(rsurface.batchnumvertices * sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, R_BUFFERDATA_VERTEX, &rsurface.batchskeletalweight4ub_bufferoffset);
7365
7366         if (rsurface.batchelement3s && !rsurface.batchelement3s_indexbuffer)
7367                 rsurface.batchelement3s_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(short[3]), rsurface.batchelement3s, R_BUFFERDATA_INDEX16, &rsurface.batchelement3s_bufferoffset);
7368         else if (rsurface.batchelement3i && !rsurface.batchelement3i_indexbuffer)
7369                 rsurface.batchelement3i_indexbuffer = R_BufferData_Store(rsurface.batchnumtriangles * sizeof(int[3]), rsurface.batchelement3i, R_BUFFERDATA_INDEX32, &rsurface.batchelement3i_bufferoffset);
7370
7371         R_Mesh_VertexPointer(     3, GL_FLOAT, sizeof(float[3]), rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
7372         R_Mesh_ColorPointer(      4, GL_FLOAT, sizeof(float[4]), rsurface.batchlightmapcolor4f, rsurface.batchlightmapcolor4f_vertexbuffer, rsurface.batchlightmapcolor4f_bufferoffset);
7373         R_Mesh_TexCoordPointer(0, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordtexture2f_vertexbuffer, rsurface.batchtexcoordtexture2f_bufferoffset);
7374         R_Mesh_TexCoordPointer(1, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchsvector3f, rsurface.batchsvector3f_vertexbuffer, rsurface.batchsvector3f_bufferoffset);
7375         R_Mesh_TexCoordPointer(2, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchtvector3f, rsurface.batchtvector3f_vertexbuffer, rsurface.batchtvector3f_bufferoffset);
7376         R_Mesh_TexCoordPointer(3, 3, GL_FLOAT, sizeof(float[3]), rsurface.batchnormal3f, rsurface.batchnormal3f_vertexbuffer, rsurface.batchnormal3f_bufferoffset);
7377         R_Mesh_TexCoordPointer(4, 2, GL_FLOAT, sizeof(float[2]), rsurface.batchtexcoordlightmap2f, rsurface.batchtexcoordlightmap2f_vertexbuffer, rsurface.batchtexcoordlightmap2f_bufferoffset);
7378         R_Mesh_TexCoordPointer(5, 2, GL_FLOAT, sizeof(float[2]), NULL, NULL, 0);
7379         R_Mesh_TexCoordPointer(6, 4, GL_UNSIGNED_BYTE | 0x80000000, sizeof(unsigned char[4]), rsurface.batchskeletalindex4ub, rsurface.batchskeletalindex4ub_vertexbuffer, rsurface.batchskeletalindex4ub_bufferoffset);
7380         R_Mesh_TexCoordPointer(7, 4, GL_UNSIGNED_BYTE, sizeof(unsigned char[4]), rsurface.batchskeletalweight4ub, rsurface.batchskeletalweight4ub_vertexbuffer, rsurface.batchskeletalweight4ub_bufferoffset);
7381 }
7382
7383 static void RSurf_RenumberElements(const int *inelement3i, int *outelement3i, int numelements, int adjust)
7384 {
7385         int i;
7386         for (i = 0;i < numelements;i++)
7387                 outelement3i[i] = inelement3i[i] + adjust;
7388 }
7389
7390 static const int quadedges[6][2] = {{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3}};
7391 void RSurf_PrepareVerticesForBatch(int batchneed, int texturenumsurfaces, const msurface_t **texturesurfacelist)
7392 {
7393         int deformindex;
7394         int firsttriangle;
7395         int numtriangles;
7396         int firstvertex;
7397         int endvertex;
7398         int numvertices;
7399         int surfacefirsttriangle;
7400         int surfacenumtriangles;
7401         int surfacefirstvertex;
7402         int surfaceendvertex;
7403         int surfacenumvertices;
7404         int batchnumsurfaces = texturenumsurfaces;
7405         int batchnumvertices;
7406         int batchnumtriangles;
7407         int i, j;
7408         qbool gaps;
7409         qbool dynamicvertex;
7410         float amplitude;
7411         float animpos;
7412         float center[3], forward[3], right[3], up[3], v[3], newforward[3], newright[3], newup[3];
7413         float waveparms[4];
7414         unsigned char *ub;
7415         q3shaderinfo_deform_t *deform;
7416         const msurface_t *surface, *firstsurface;
7417         if (!texturenumsurfaces)
7418                 return;
7419         // find vertex range of this surface batch
7420         gaps = false;
7421         firstsurface = texturesurfacelist[0];
7422         firsttriangle = firstsurface->num_firsttriangle;
7423         batchnumvertices = 0;
7424         batchnumtriangles = 0;
7425         firstvertex = endvertex = firstsurface->num_firstvertex;
7426         for (i = 0;i < texturenumsurfaces;i++)
7427         {
7428                 surface = texturesurfacelist[i];
7429                 if (surface != firstsurface + i)
7430                         gaps = true;
7431                 surfacefirstvertex = surface->num_firstvertex;
7432                 surfaceendvertex = surfacefirstvertex + surface->num_vertices;
7433                 surfacenumvertices = surface->num_vertices;
7434                 surfacenumtriangles = surface->num_triangles;
7435                 if (firstvertex > surfacefirstvertex)
7436                         firstvertex = surfacefirstvertex;
7437                 if (endvertex < surfaceendvertex)
7438                         endvertex = surfaceendvertex;
7439                 batchnumvertices += surfacenumvertices;
7440                 batchnumtriangles += surfacenumtriangles;
7441         }
7442
7443         r_refdef.stats[r_stat_batch_batches]++;
7444         if (gaps)
7445                 r_refdef.stats[r_stat_batch_withgaps]++;
7446         r_refdef.stats[r_stat_batch_surfaces] += batchnumsurfaces;
7447         r_refdef.stats[r_stat_batch_vertices] += batchnumvertices;
7448         r_refdef.stats[r_stat_batch_triangles] += batchnumtriangles;
7449
7450         // we now know the vertex range used, and if there are any gaps in it
7451         rsurface.batchfirstvertex = firstvertex;
7452         rsurface.batchnumvertices = endvertex - firstvertex;
7453         rsurface.batchfirsttriangle = firsttriangle;
7454         rsurface.batchnumtriangles = batchnumtriangles;
7455
7456         // check if any dynamic vertex processing must occur
7457         dynamicvertex = false;
7458
7459         // we must use vertexbuffers for rendering, we can upload vertex buffers
7460         // easily enough but if the basevertex is non-zero it becomes more
7461         // difficult, so force dynamicvertex path in that case - it's suboptimal
7462         // but the most optimal case is to have the geometry sources provide their
7463         // own anyway.
7464         if (!rsurface.modelvertex3f_vertexbuffer && firstvertex != 0)
7465                 dynamicvertex = true;
7466
7467         // a cvar to force the dynamic vertex path to be taken, for debugging
7468         if (r_batch_debugdynamicvertexpath.integer)
7469         {
7470                 if (!dynamicvertex)
7471                 {
7472                         r_refdef.stats[r_stat_batch_dynamic_batches_because_cvar] += 1;
7473                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_cvar] += batchnumsurfaces;
7474                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_cvar] += batchnumvertices;
7475                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_cvar] += batchnumtriangles;
7476                 }
7477                 dynamicvertex = true;
7478         }
7479
7480         // if there is a chance of animated vertex colors, it's a dynamic batch
7481         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
7482         {
7483                 if (!dynamicvertex)
7484                 {
7485                         r_refdef.stats[r_stat_batch_dynamic_batches_because_lightmapvertex] += 1;
7486                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_lightmapvertex] += batchnumsurfaces;
7487                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_lightmapvertex] += batchnumvertices;
7488                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_lightmapvertex] += batchnumtriangles;
7489                 }
7490                 dynamicvertex = true;
7491         }
7492
7493         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
7494         {
7495                 switch (deform->deform)
7496                 {
7497                 default:
7498                 case Q3DEFORM_PROJECTIONSHADOW:
7499                 case Q3DEFORM_TEXT0:
7500                 case Q3DEFORM_TEXT1:
7501                 case Q3DEFORM_TEXT2:
7502                 case Q3DEFORM_TEXT3:
7503                 case Q3DEFORM_TEXT4:
7504                 case Q3DEFORM_TEXT5:
7505                 case Q3DEFORM_TEXT6:
7506                 case Q3DEFORM_TEXT7:
7507                 case Q3DEFORM_NONE:
7508                         break;
7509                 case Q3DEFORM_AUTOSPRITE:
7510                         if (!dynamicvertex)
7511                         {
7512                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite] += 1;
7513                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite] += batchnumsurfaces;
7514                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite] += batchnumvertices;
7515                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite] += batchnumtriangles;
7516                         }
7517                         dynamicvertex = true;
7518                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_TEXCOORD;
7519                         break;
7520                 case Q3DEFORM_AUTOSPRITE2:
7521                         if (!dynamicvertex)
7522                         {
7523                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_autosprite2] += 1;
7524                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_autosprite2] += batchnumsurfaces;
7525                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_autosprite2] += batchnumvertices;
7526                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_autosprite2] += batchnumtriangles;
7527                         }
7528                         dynamicvertex = true;
7529                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7530                         break;
7531                 case Q3DEFORM_NORMAL:
7532                         if (!dynamicvertex)
7533                         {
7534                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_normal] += 1;
7535                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_normal] += batchnumsurfaces;
7536                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_normal] += batchnumvertices;
7537                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_normal] += batchnumtriangles;
7538                         }
7539                         dynamicvertex = true;
7540                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7541                         break;
7542                 case Q3DEFORM_WAVE:
7543                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7544                                 break; // if wavefunc is a nop, ignore this transform
7545                         if (!dynamicvertex)
7546                         {
7547                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_wave] += 1;
7548                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_wave] += batchnumsurfaces;
7549                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_wave] += batchnumvertices;
7550                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_wave] += batchnumtriangles;
7551                         }
7552                         dynamicvertex = true;
7553                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7554                         break;
7555                 case Q3DEFORM_BULGE:
7556                         if (!dynamicvertex)
7557                         {
7558                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_bulge] += 1;
7559                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_bulge] += batchnumsurfaces;
7560                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_bulge] += batchnumvertices;
7561                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_bulge] += batchnumtriangles;
7562                         }
7563                         dynamicvertex = true;
7564                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_TEXCOORD;
7565                         break;
7566                 case Q3DEFORM_MOVE:
7567                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
7568                                 break; // if wavefunc is a nop, ignore this transform
7569                         if (!dynamicvertex)
7570                         {
7571                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_deformvertexes_move] += 1;
7572                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_deformvertexes_move] += batchnumsurfaces;
7573                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_deformvertexes_move] += batchnumvertices;
7574                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_deformvertexes_move] += batchnumtriangles;
7575                         }
7576                         dynamicvertex = true;
7577                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7578                         break;
7579                 }
7580         }
7581         if (rsurface.texture->materialshaderpass)
7582         {
7583                 switch (rsurface.texture->materialshaderpass->tcgen.tcgen)
7584                 {
7585                 default:
7586                 case Q3TCGEN_TEXTURE:
7587                         break;
7588                 case Q3TCGEN_LIGHTMAP:
7589                         if (!dynamicvertex)
7590                         {
7591                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_lightmap] += 1;
7592                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_lightmap] += batchnumsurfaces;
7593                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_lightmap] += batchnumvertices;
7594                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_lightmap] += batchnumtriangles;
7595                         }
7596                         dynamicvertex = true;
7597                         batchneed |= BATCHNEED_ARRAY_LIGHTMAP;
7598                         break;
7599                 case Q3TCGEN_VECTOR:
7600                         if (!dynamicvertex)
7601                         {
7602                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_vector] += 1;
7603                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_vector] += batchnumsurfaces;
7604                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_vector] += batchnumvertices;
7605                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_vector] += batchnumtriangles;
7606                         }
7607                         dynamicvertex = true;
7608                         batchneed |= BATCHNEED_ARRAY_VERTEX;
7609                         break;
7610                 case Q3TCGEN_ENVIRONMENT:
7611                         if (!dynamicvertex)
7612                         {
7613                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcgen_environment] += 1;
7614                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcgen_environment] += batchnumsurfaces;
7615                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcgen_environment] += batchnumvertices;
7616                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcgen_environment] += batchnumtriangles;
7617                         }
7618                         dynamicvertex = true;
7619                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL;
7620                         break;
7621                 }
7622                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
7623                 {
7624                         if (!dynamicvertex)
7625                         {
7626                                 r_refdef.stats[r_stat_batch_dynamic_batches_because_tcmod_turbulent] += 1;
7627                                 r_refdef.stats[r_stat_batch_dynamic_surfaces_because_tcmod_turbulent] += batchnumsurfaces;
7628                                 r_refdef.stats[r_stat_batch_dynamic_vertices_because_tcmod_turbulent] += batchnumvertices;
7629                                 r_refdef.stats[r_stat_batch_dynamic_triangles_because_tcmod_turbulent] += batchnumtriangles;
7630                         }
7631                         dynamicvertex = true;
7632                         batchneed |= BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_TEXCOORD;
7633                 }
7634         }
7635
7636         // the caller can specify BATCHNEED_NOGAPS to force a batch with
7637         // firstvertex = 0 and endvertex = numvertices (no gaps, no firstvertex),
7638         // we ensure this by treating the vertex batch as dynamic...
7639         if ((batchneed & BATCHNEED_ALWAYSCOPY) || ((batchneed & BATCHNEED_NOGAPS) && (gaps || firstvertex > 0)))
7640         {
7641                 if (!dynamicvertex)
7642                 {
7643                         r_refdef.stats[r_stat_batch_dynamic_batches_because_nogaps] += 1;
7644                         r_refdef.stats[r_stat_batch_dynamic_surfaces_because_nogaps] += batchnumsurfaces;
7645                         r_refdef.stats[r_stat_batch_dynamic_vertices_because_nogaps] += batchnumvertices;
7646                         r_refdef.stats[r_stat_batch_dynamic_triangles_because_nogaps] += batchnumtriangles;
7647                 }
7648                 dynamicvertex = true;
7649         }
7650
7651         // if we're going to have to apply the skeletal transform manually, we need to batch the skeletal data
7652         if (dynamicvertex && rsurface.entityskeletaltransform3x4)
7653                 batchneed |= BATCHNEED_ARRAY_SKELETAL;
7654
7655         rsurface.batchvertex3f = rsurface.modelvertex3f;
7656         rsurface.batchvertex3f_vertexbuffer = rsurface.modelvertex3f_vertexbuffer;
7657         rsurface.batchvertex3f_bufferoffset = rsurface.modelvertex3f_bufferoffset;
7658         rsurface.batchsvector3f = rsurface.modelsvector3f;
7659         rsurface.batchsvector3f_vertexbuffer = rsurface.modelsvector3f_vertexbuffer;
7660         rsurface.batchsvector3f_bufferoffset = rsurface.modelsvector3f_bufferoffset;
7661         rsurface.batchtvector3f = rsurface.modeltvector3f;
7662         rsurface.batchtvector3f_vertexbuffer = rsurface.modeltvector3f_vertexbuffer;
7663         rsurface.batchtvector3f_bufferoffset = rsurface.modeltvector3f_bufferoffset;
7664         rsurface.batchnormal3f = rsurface.modelnormal3f;
7665         rsurface.batchnormal3f_vertexbuffer = rsurface.modelnormal3f_vertexbuffer;
7666         rsurface.batchnormal3f_bufferoffset = rsurface.modelnormal3f_bufferoffset;
7667         rsurface.batchlightmapcolor4f = rsurface.modellightmapcolor4f;
7668         rsurface.batchlightmapcolor4f_vertexbuffer  = rsurface.modellightmapcolor4f_vertexbuffer;
7669         rsurface.batchlightmapcolor4f_bufferoffset  = rsurface.modellightmapcolor4f_bufferoffset;
7670         rsurface.batchtexcoordtexture2f = rsurface.modeltexcoordtexture2f;
7671         rsurface.batchtexcoordtexture2f_vertexbuffer  = rsurface.modeltexcoordtexture2f_vertexbuffer;
7672         rsurface.batchtexcoordtexture2f_bufferoffset  = rsurface.modeltexcoordtexture2f_bufferoffset;
7673         rsurface.batchtexcoordlightmap2f = rsurface.modeltexcoordlightmap2f;
7674         rsurface.batchtexcoordlightmap2f_vertexbuffer = rsurface.modeltexcoordlightmap2f_vertexbuffer;
7675         rsurface.batchtexcoordlightmap2f_bufferoffset = rsurface.modeltexcoordlightmap2f_bufferoffset;
7676         rsurface.batchskeletalindex4ub = rsurface.modelskeletalindex4ub;
7677         rsurface.batchskeletalindex4ub_vertexbuffer = rsurface.modelskeletalindex4ub_vertexbuffer;
7678         rsurface.batchskeletalindex4ub_bufferoffset = rsurface.modelskeletalindex4ub_bufferoffset;
7679         rsurface.batchskeletalweight4ub = rsurface.modelskeletalweight4ub;
7680         rsurface.batchskeletalweight4ub_vertexbuffer = rsurface.modelskeletalweight4ub_vertexbuffer;
7681         rsurface.batchskeletalweight4ub_bufferoffset = rsurface.modelskeletalweight4ub_bufferoffset;
7682         rsurface.batchelement3i = rsurface.modelelement3i;
7683         rsurface.batchelement3i_indexbuffer = rsurface.modelelement3i_indexbuffer;
7684         rsurface.batchelement3i_bufferoffset = rsurface.modelelement3i_bufferoffset;
7685         rsurface.batchelement3s = rsurface.modelelement3s;
7686         rsurface.batchelement3s_indexbuffer = rsurface.modelelement3s_indexbuffer;
7687         rsurface.batchelement3s_bufferoffset = rsurface.modelelement3s_bufferoffset;
7688         rsurface.batchskeletaltransform3x4 = rsurface.entityskeletaltransform3x4;
7689         rsurface.batchskeletaltransform3x4buffer = rsurface.entityskeletaltransform3x4buffer;
7690         rsurface.batchskeletaltransform3x4offset = rsurface.entityskeletaltransform3x4offset;
7691         rsurface.batchskeletaltransform3x4size = rsurface.entityskeletaltransform3x4size;
7692         rsurface.batchskeletalnumtransforms = rsurface.entityskeletalnumtransforms;
7693
7694         // if any dynamic vertex processing has to occur in software, we copy the
7695         // entire surface list together before processing to rebase the vertices
7696         // to start at 0 (otherwise we waste a lot of room in a vertex buffer).
7697         //
7698         // if any gaps exist and we do not have a static vertex buffer, we have to
7699         // copy the surface list together to avoid wasting upload bandwidth on the
7700         // vertices in the gaps.
7701         //
7702         // if gaps exist and we have a static vertex buffer, we can choose whether
7703         // to combine the index buffer ranges into one dynamic index buffer or
7704         // simply issue multiple glDrawElements calls (BATCHNEED_ALLOWMULTIDRAW).
7705         //
7706         // in many cases the batch is reduced to one draw call.
7707
7708         rsurface.batchmultidraw = false;
7709         rsurface.batchmultidrawnumsurfaces = 0;
7710         rsurface.batchmultidrawsurfacelist = NULL;
7711
7712         if (!dynamicvertex)
7713         {
7714                 // static vertex data, just set pointers...
7715                 rsurface.batchgeneratedvertex = false;
7716                 // if there are gaps, we want to build a combined index buffer,
7717                 // otherwise use the original static buffer with an appropriate offset
7718                 if (gaps)
7719                 {
7720                         r_refdef.stats[r_stat_batch_copytriangles_batches] += 1;
7721                         r_refdef.stats[r_stat_batch_copytriangles_surfaces] += batchnumsurfaces;
7722                         r_refdef.stats[r_stat_batch_copytriangles_vertices] += batchnumvertices;
7723                         r_refdef.stats[r_stat_batch_copytriangles_triangles] += batchnumtriangles;
7724                         if ((batchneed & BATCHNEED_ALLOWMULTIDRAW) && r_batch_multidraw.integer && batchnumtriangles >= r_batch_multidraw_mintriangles.integer)
7725                         {
7726                                 rsurface.batchmultidraw = true;
7727                                 rsurface.batchmultidrawnumsurfaces = texturenumsurfaces;
7728                                 rsurface.batchmultidrawsurfacelist = texturesurfacelist;
7729                                 return;
7730                         }
7731                         // build a new triangle elements array for this batch
7732                         rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7733                         rsurface.batchfirsttriangle = 0;
7734                         numtriangles = 0;
7735                         for (i = 0;i < texturenumsurfaces;i++)
7736                         {
7737                                 surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7738                                 surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7739                                 memcpy(rsurface.batchelement3i + 3*numtriangles, rsurface.modelelement3i + 3*surfacefirsttriangle, surfacenumtriangles*sizeof(int[3]));
7740                                 numtriangles += surfacenumtriangles;
7741                         }
7742                         rsurface.batchelement3i_indexbuffer = NULL;
7743                         rsurface.batchelement3i_bufferoffset = 0;
7744                         rsurface.batchelement3s = NULL;
7745                         rsurface.batchelement3s_indexbuffer = NULL;
7746                         rsurface.batchelement3s_bufferoffset = 0;
7747                         if (endvertex <= 65536)
7748                         {
7749                                 // make a 16bit (unsigned short) index array if possible
7750                                 rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7751                                 for (i = 0;i < numtriangles*3;i++)
7752                                         rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7753                         }
7754                 }
7755                 else
7756                 {
7757                         r_refdef.stats[r_stat_batch_fast_batches] += 1;
7758                         r_refdef.stats[r_stat_batch_fast_surfaces] += batchnumsurfaces;
7759                         r_refdef.stats[r_stat_batch_fast_vertices] += batchnumvertices;
7760                         r_refdef.stats[r_stat_batch_fast_triangles] += batchnumtriangles;
7761                 }
7762                 return;
7763         }
7764
7765         // something needs software processing, do it for real...
7766         // we only directly handle separate array data in this case and then
7767         // generate interleaved data if needed...
7768         rsurface.batchgeneratedvertex = true;
7769         r_refdef.stats[r_stat_batch_dynamic_batches] += 1;
7770         r_refdef.stats[r_stat_batch_dynamic_surfaces] += batchnumsurfaces;
7771         r_refdef.stats[r_stat_batch_dynamic_vertices] += batchnumvertices;
7772         r_refdef.stats[r_stat_batch_dynamic_triangles] += batchnumtriangles;
7773
7774         // now copy the vertex data into a combined array and make an index array
7775         // (this is what Quake3 does all the time)
7776         // we also apply any skeletal animation here that would have been done in
7777         // the vertex shader, because most of the dynamic vertex animation cases
7778         // need actual vertex positions and normals
7779         //if (dynamicvertex)
7780         {
7781                 rsurface.batchvertex3f = NULL;
7782                 rsurface.batchvertex3f_vertexbuffer = NULL;
7783                 rsurface.batchvertex3f_bufferoffset = 0;
7784                 rsurface.batchsvector3f = NULL;
7785                 rsurface.batchsvector3f_vertexbuffer = NULL;
7786                 rsurface.batchsvector3f_bufferoffset = 0;
7787                 rsurface.batchtvector3f = NULL;
7788                 rsurface.batchtvector3f_vertexbuffer = NULL;
7789                 rsurface.batchtvector3f_bufferoffset = 0;
7790                 rsurface.batchnormal3f = NULL;
7791                 rsurface.batchnormal3f_vertexbuffer = NULL;
7792                 rsurface.batchnormal3f_bufferoffset = 0;
7793                 rsurface.batchlightmapcolor4f = NULL;
7794                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
7795                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
7796                 rsurface.batchtexcoordtexture2f = NULL;
7797                 rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
7798                 rsurface.batchtexcoordtexture2f_bufferoffset = 0;
7799                 rsurface.batchtexcoordlightmap2f = NULL;
7800                 rsurface.batchtexcoordlightmap2f_vertexbuffer = NULL;
7801                 rsurface.batchtexcoordlightmap2f_bufferoffset = 0;
7802                 rsurface.batchskeletalindex4ub = NULL;
7803                 rsurface.batchskeletalindex4ub_vertexbuffer = NULL;
7804                 rsurface.batchskeletalindex4ub_bufferoffset = 0;
7805                 rsurface.batchskeletalweight4ub = NULL;
7806                 rsurface.batchskeletalweight4ub_vertexbuffer = NULL;
7807                 rsurface.batchskeletalweight4ub_bufferoffset = 0;
7808                 rsurface.batchelement3i = (int *)R_FrameData_Alloc(batchnumtriangles * sizeof(int[3]));
7809                 rsurface.batchelement3i_indexbuffer = NULL;
7810                 rsurface.batchelement3i_bufferoffset = 0;
7811                 rsurface.batchelement3s = NULL;
7812                 rsurface.batchelement3s_indexbuffer = NULL;
7813                 rsurface.batchelement3s_bufferoffset = 0;
7814                 rsurface.batchskeletaltransform3x4buffer = NULL;
7815                 rsurface.batchskeletaltransform3x4offset = 0;
7816                 rsurface.batchskeletaltransform3x4size = 0;
7817                 // we'll only be setting up certain arrays as needed
7818                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7819                         rsurface.batchvertex3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7820                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7821                         rsurface.batchnormal3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7822                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7823                 {
7824                         rsurface.batchsvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7825                         rsurface.batchtvector3f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
7826                 }
7827                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7828                         rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
7829                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7830                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7831                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7832                         rsurface.batchtexcoordlightmap2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
7833                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7834                 {
7835                         rsurface.batchskeletalindex4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7836                         rsurface.batchskeletalweight4ub = (unsigned char *)R_FrameData_Alloc(batchnumvertices * sizeof(unsigned char[4]));
7837                 }
7838                 numvertices = 0;
7839                 numtriangles = 0;
7840                 for (i = 0;i < texturenumsurfaces;i++)
7841                 {
7842                         surfacefirstvertex = texturesurfacelist[i]->num_firstvertex;
7843                         surfacenumvertices = texturesurfacelist[i]->num_vertices;
7844                         surfacefirsttriangle = texturesurfacelist[i]->num_firsttriangle;
7845                         surfacenumtriangles = texturesurfacelist[i]->num_triangles;
7846                         // copy only the data requested
7847                         if (batchneed & (BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ARRAY_LIGHTMAP))
7848                         {
7849                                 if (batchneed & BATCHNEED_ARRAY_VERTEX)
7850                                 {
7851                                         if (rsurface.batchvertex3f)
7852                                                 memcpy(rsurface.batchvertex3f + 3*numvertices, rsurface.modelvertex3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7853                                         else
7854                                                 memset(rsurface.batchvertex3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7855                                 }
7856                                 if (batchneed & BATCHNEED_ARRAY_NORMAL)
7857                                 {
7858                                         if (rsurface.modelnormal3f)
7859                                                 memcpy(rsurface.batchnormal3f + 3*numvertices, rsurface.modelnormal3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7860                                         else
7861                                                 memset(rsurface.batchnormal3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7862                                 }
7863                                 if (batchneed & BATCHNEED_ARRAY_VECTOR)
7864                                 {
7865                                         if (rsurface.modelsvector3f)
7866                                         {
7867                                                 memcpy(rsurface.batchsvector3f + 3*numvertices, rsurface.modelsvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7868                                                 memcpy(rsurface.batchtvector3f + 3*numvertices, rsurface.modeltvector3f + 3*surfacefirstvertex, surfacenumvertices * sizeof(float[3]));
7869                                         }
7870                                         else
7871                                         {
7872                                                 memset(rsurface.batchsvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7873                                                 memset(rsurface.batchtvector3f + 3*numvertices, 0, surfacenumvertices * sizeof(float[3]));
7874                                         }
7875                                 }
7876                                 if (batchneed & BATCHNEED_ARRAY_VERTEXCOLOR)
7877                                 {
7878                                         if (rsurface.modellightmapcolor4f)
7879                                                 memcpy(rsurface.batchlightmapcolor4f + 4*numvertices, rsurface.modellightmapcolor4f + 4*surfacefirstvertex, surfacenumvertices * sizeof(float[4]));
7880                                         else
7881                                                 memset(rsurface.batchlightmapcolor4f + 4*numvertices, 0, surfacenumvertices * sizeof(float[4]));
7882                                 }
7883                                 if (batchneed & BATCHNEED_ARRAY_TEXCOORD)
7884                                 {
7885                                         if (rsurface.modeltexcoordtexture2f)
7886                                                 memcpy(rsurface.batchtexcoordtexture2f + 2*numvertices, rsurface.modeltexcoordtexture2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7887                                         else
7888                                                 memset(rsurface.batchtexcoordtexture2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7889                                 }
7890                                 if (batchneed & BATCHNEED_ARRAY_LIGHTMAP)
7891                                 {
7892                                         if (rsurface.modeltexcoordlightmap2f)
7893                                                 memcpy(rsurface.batchtexcoordlightmap2f + 2*numvertices, rsurface.modeltexcoordlightmap2f + 2*surfacefirstvertex, surfacenumvertices * sizeof(float[2]));
7894                                         else
7895                                                 memset(rsurface.batchtexcoordlightmap2f + 2*numvertices, 0, surfacenumvertices * sizeof(float[2]));
7896                                 }
7897                                 if (batchneed & BATCHNEED_ARRAY_SKELETAL)
7898                                 {
7899                                         if (rsurface.modelskeletalindex4ub)
7900                                         {
7901                                                 memcpy(rsurface.batchskeletalindex4ub + 4*numvertices, rsurface.modelskeletalindex4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7902                                                 memcpy(rsurface.batchskeletalweight4ub + 4*numvertices, rsurface.modelskeletalweight4ub + 4*surfacefirstvertex, surfacenumvertices * sizeof(unsigned char[4]));
7903                                         }
7904                                         else
7905                                         {
7906                                                 memset(rsurface.batchskeletalindex4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7907                                                 memset(rsurface.batchskeletalweight4ub + 4*numvertices, 0, surfacenumvertices * sizeof(unsigned char[4]));
7908                                                 ub = rsurface.batchskeletalweight4ub + 4*numvertices;
7909                                                 for (j = 0;j < surfacenumvertices;j++)
7910                                                         ub[j*4] = 255;
7911                                         }
7912                                 }
7913                         }
7914                         RSurf_RenumberElements(rsurface.modelelement3i + 3*surfacefirsttriangle, rsurface.batchelement3i + 3*numtriangles, 3*surfacenumtriangles, numvertices - surfacefirstvertex);
7915                         numvertices += surfacenumvertices;
7916                         numtriangles += surfacenumtriangles;
7917                 }
7918
7919                 // generate a 16bit index array as well if possible
7920                 // (in general, dynamic batches fit)
7921                 if (numvertices <= 65536)
7922                 {
7923                         rsurface.batchelement3s = (unsigned short *)R_FrameData_Alloc(batchnumtriangles * sizeof(unsigned short[3]));
7924                         for (i = 0;i < numtriangles*3;i++)
7925                                 rsurface.batchelement3s[i] = rsurface.batchelement3i[i];
7926                 }
7927
7928                 // since we've copied everything, the batch now starts at 0
7929                 rsurface.batchfirstvertex = 0;
7930                 rsurface.batchnumvertices = batchnumvertices;
7931                 rsurface.batchfirsttriangle = 0;
7932                 rsurface.batchnumtriangles = batchnumtriangles;
7933         }
7934
7935         // apply skeletal animation that would have been done in the vertex shader
7936         if (rsurface.batchskeletaltransform3x4)
7937         {
7938                 const unsigned char *si;
7939                 const unsigned char *sw;
7940                 const float *t[4];
7941                 const float *b = rsurface.batchskeletaltransform3x4;
7942                 float *vp, *vs, *vt, *vn;
7943                 float w[4];
7944                 float m[3][4], n[3][4];
7945                 float tp[3], ts[3], tt[3], tn[3];
7946                 r_refdef.stats[r_stat_batch_dynamicskeletal_batches] += 1;
7947                 r_refdef.stats[r_stat_batch_dynamicskeletal_surfaces] += batchnumsurfaces;
7948                 r_refdef.stats[r_stat_batch_dynamicskeletal_vertices] += batchnumvertices;
7949                 r_refdef.stats[r_stat_batch_dynamicskeletal_triangles] += batchnumtriangles;
7950                 si = rsurface.batchskeletalindex4ub;
7951                 sw = rsurface.batchskeletalweight4ub;
7952                 vp = rsurface.batchvertex3f;
7953                 vs = rsurface.batchsvector3f;
7954                 vt = rsurface.batchtvector3f;
7955                 vn = rsurface.batchnormal3f;
7956                 memset(m[0], 0, sizeof(m));
7957                 memset(n[0], 0, sizeof(n));
7958                 for (i = 0;i < batchnumvertices;i++)
7959                 {
7960                         t[0] = b + si[0]*12;
7961                         if (sw[0] == 255)
7962                         {
7963                                 // common case - only one matrix
7964                                 m[0][0] = t[0][ 0];
7965                                 m[0][1] = t[0][ 1];
7966                                 m[0][2] = t[0][ 2];
7967                                 m[0][3] = t[0][ 3];
7968                                 m[1][0] = t[0][ 4];
7969                                 m[1][1] = t[0][ 5];
7970                                 m[1][2] = t[0][ 6];
7971                                 m[1][3] = t[0][ 7];
7972                                 m[2][0] = t[0][ 8];
7973                                 m[2][1] = t[0][ 9];
7974                                 m[2][2] = t[0][10];
7975                                 m[2][3] = t[0][11];
7976                         }
7977                         else if (sw[2] + sw[3])
7978                         {
7979                                 // blend 4 matrices
7980                                 t[1] = b + si[1]*12;
7981                                 t[2] = b + si[2]*12;
7982                                 t[3] = b + si[3]*12;
7983                                 w[0] = sw[0] * (1.0f / 255.0f);
7984                                 w[1] = sw[1] * (1.0f / 255.0f);
7985                                 w[2] = sw[2] * (1.0f / 255.0f);
7986                                 w[3] = sw[3] * (1.0f / 255.0f);
7987                                 // blend the matrices
7988                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1] + t[2][ 0] * w[2] + t[3][ 0] * w[3];
7989                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1] + t[2][ 1] * w[2] + t[3][ 1] * w[3];
7990                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1] + t[2][ 2] * w[2] + t[3][ 2] * w[3];
7991                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1] + t[2][ 3] * w[2] + t[3][ 3] * w[3];
7992                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1] + t[2][ 4] * w[2] + t[3][ 4] * w[3];
7993                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1] + t[2][ 5] * w[2] + t[3][ 5] * w[3];
7994                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1] + t[2][ 6] * w[2] + t[3][ 6] * w[3];
7995                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1] + t[2][ 7] * w[2] + t[3][ 7] * w[3];
7996                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1] + t[2][ 8] * w[2] + t[3][ 8] * w[3];
7997                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1] + t[2][ 9] * w[2] + t[3][ 9] * w[3];
7998                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1] + t[2][10] * w[2] + t[3][10] * w[3];
7999                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1] + t[2][11] * w[2] + t[3][11] * w[3];
8000                         }
8001                         else
8002                         {
8003                                 // blend 2 matrices
8004                                 t[1] = b + si[1]*12;
8005                                 w[0] = sw[0] * (1.0f / 255.0f);
8006                                 w[1] = sw[1] * (1.0f / 255.0f);
8007                                 // blend the matrices
8008                                 m[0][0] = t[0][ 0] * w[0] + t[1][ 0] * w[1];
8009                                 m[0][1] = t[0][ 1] * w[0] + t[1][ 1] * w[1];
8010                                 m[0][2] = t[0][ 2] * w[0] + t[1][ 2] * w[1];
8011                                 m[0][3] = t[0][ 3] * w[0] + t[1][ 3] * w[1];
8012                                 m[1][0] = t[0][ 4] * w[0] + t[1][ 4] * w[1];
8013                                 m[1][1] = t[0][ 5] * w[0] + t[1][ 5] * w[1];
8014                                 m[1][2] = t[0][ 6] * w[0] + t[1][ 6] * w[1];
8015                                 m[1][3] = t[0][ 7] * w[0] + t[1][ 7] * w[1];
8016                                 m[2][0] = t[0][ 8] * w[0] + t[1][ 8] * w[1];
8017                                 m[2][1] = t[0][ 9] * w[0] + t[1][ 9] * w[1];
8018                                 m[2][2] = t[0][10] * w[0] + t[1][10] * w[1];
8019                                 m[2][3] = t[0][11] * w[0] + t[1][11] * w[1];
8020                         }
8021                         si += 4;
8022                         sw += 4;
8023                         // modify the vertex
8024                         VectorCopy(vp, tp);
8025                         vp[0] = tp[0] * m[0][0] + tp[1] * m[0][1] + tp[2] * m[0][2] + m[0][3];
8026                         vp[1] = tp[0] * m[1][0] + tp[1] * m[1][1] + tp[2] * m[1][2] + m[1][3];
8027                         vp[2] = tp[0] * m[2][0] + tp[1] * m[2][1] + tp[2] * m[2][2] + m[2][3];
8028                         vp += 3;
8029                         if (vn)
8030                         {
8031                                 // the normal transformation matrix is a set of cross products...
8032                                 CrossProduct(m[1], m[2], n[0]);
8033                                 CrossProduct(m[2], m[0], n[1]);
8034                                 CrossProduct(m[0], m[1], n[2]); // is actually transpose(inverse(m)) * det(m)
8035                                 VectorCopy(vn, tn);
8036                                 vn[0] = tn[0] * n[0][0] + tn[1] * n[0][1] + tn[2] * n[0][2];
8037                                 vn[1] = tn[0] * n[1][0] + tn[1] * n[1][1] + tn[2] * n[1][2];
8038                                 vn[2] = tn[0] * n[2][0] + tn[1] * n[2][1] + tn[2] * n[2][2];
8039                                 VectorNormalize(vn);
8040                                 vn += 3;
8041                                 if (vs)
8042                                 {
8043                                         VectorCopy(vs, ts);
8044                                         vs[0] = ts[0] * n[0][0] + ts[1] * n[0][1] + ts[2] * n[0][2];
8045                                         vs[1] = ts[0] * n[1][0] + ts[1] * n[1][1] + ts[2] * n[1][2];
8046                                         vs[2] = ts[0] * n[2][0] + ts[1] * n[2][1] + ts[2] * n[2][2];
8047                                         VectorNormalize(vs);
8048                                         vs += 3;
8049                                         VectorCopy(vt, tt);
8050                                         vt[0] = tt[0] * n[0][0] + tt[1] * n[0][1] + tt[2] * n[0][2];
8051                                         vt[1] = tt[0] * n[1][0] + tt[1] * n[1][1] + tt[2] * n[1][2];
8052                                         vt[2] = tt[0] * n[2][0] + tt[1] * n[2][1] + tt[2] * n[2][2];
8053                                         VectorNormalize(vt);
8054                                         vt += 3;
8055                                 }
8056                         }
8057                 }
8058                 rsurface.batchskeletaltransform3x4 = NULL;
8059                 rsurface.batchskeletalnumtransforms = 0;
8060         }
8061
8062         // q1bsp surfaces rendered in vertex color mode have to have colors
8063         // calculated based on lightstyles
8064         if ((batchneed & BATCHNEED_ARRAY_VERTEXCOLOR) && texturesurfacelist[0]->lightmapinfo)
8065         {
8066                 // generate color arrays for the surfaces in this list
8067                 int c[4];
8068                 int scale;
8069                 int size3;
8070                 const int *offsets;
8071                 const unsigned char *lm;
8072                 rsurface.batchlightmapcolor4f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[4]));
8073                 rsurface.batchlightmapcolor4f_vertexbuffer = NULL;
8074                 rsurface.batchlightmapcolor4f_bufferoffset = 0;
8075                 numvertices = 0;
8076                 for (i = 0;i < texturenumsurfaces;i++)
8077                 {
8078                         surface = texturesurfacelist[i];
8079                         offsets = rsurface.modellightmapoffsets + surface->num_firstvertex;
8080                         surfacenumvertices = surface->num_vertices;
8081                         if (surface->lightmapinfo->samples)
8082                         {
8083                                 for (j = 0;j < surfacenumvertices;j++)
8084                                 {
8085                                         lm = surface->lightmapinfo->samples + offsets[j];
8086                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[0]];
8087                                         VectorScale(lm, scale, c);
8088                                         if (surface->lightmapinfo->styles[1] != 255)
8089                                         {
8090                                                 size3 = ((surface->lightmapinfo->extents[0]>>4)+1)*((surface->lightmapinfo->extents[1]>>4)+1)*3;
8091                                                 lm += size3;
8092                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[1]];
8093                                                 VectorMA(c, scale, lm, c);
8094                                                 if (surface->lightmapinfo->styles[2] != 255)
8095                                                 {
8096                                                         lm += size3;
8097                                                         scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[2]];
8098                                                         VectorMA(c, scale, lm, c);
8099                                                         if (surface->lightmapinfo->styles[3] != 255)
8100                                                         {
8101                                                                 lm += size3;
8102                                                                 scale = r_refdef.scene.lightstylevalue[surface->lightmapinfo->styles[3]];
8103                                                                 VectorMA(c, scale, lm, c);
8104                                                         }
8105                                                 }
8106                                         }
8107                                         c[0] >>= 7;
8108                                         c[1] >>= 7;
8109                                         c[2] >>= 7;
8110                                         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);
8111                                         numvertices++;
8112                                 }
8113                         }
8114                         else
8115                         {
8116                                 for (j = 0;j < surfacenumvertices;j++)
8117                                 {
8118                                         Vector4Set(rsurface.batchlightmapcolor4f + 4*numvertices, 0, 0, 0, 1);
8119                                         numvertices++;
8120                                 }
8121                         }
8122                 }
8123         }
8124
8125         // if vertices are deformed (sprite flares and things in maps, possibly
8126         // water waves, bulges and other deformations), modify the copied vertices
8127         // in place
8128         for (deformindex = 0, deform = rsurface.texture->deforms;deformindex < Q3MAXDEFORMS && deform->deform && r_deformvertexes.integer;deformindex++, deform++)
8129         {
8130                 float scale;
8131                 switch (deform->deform)
8132                 {
8133                 default:
8134                 case Q3DEFORM_PROJECTIONSHADOW:
8135                 case Q3DEFORM_TEXT0:
8136                 case Q3DEFORM_TEXT1:
8137                 case Q3DEFORM_TEXT2:
8138                 case Q3DEFORM_TEXT3:
8139                 case Q3DEFORM_TEXT4:
8140                 case Q3DEFORM_TEXT5:
8141                 case Q3DEFORM_TEXT6:
8142                 case Q3DEFORM_TEXT7:
8143                 case Q3DEFORM_NONE:
8144                         break;
8145                 case Q3DEFORM_AUTOSPRITE:
8146                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8147                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8148                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8149                         VectorNormalize(newforward);
8150                         VectorNormalize(newright);
8151                         VectorNormalize(newup);
8152 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8153 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8154 //                      rsurface.batchvertex3f_bufferoffset = 0;
8155 //                      rsurface.batchsvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchsvector3f);
8156 //                      rsurface.batchsvector3f_vertexbuffer = NULL;
8157 //                      rsurface.batchsvector3f_bufferoffset = 0;
8158 //                      rsurface.batchtvector3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchtvector3f);
8159 //                      rsurface.batchtvector3f_vertexbuffer = NULL;
8160 //                      rsurface.batchtvector3f_bufferoffset = 0;
8161 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8162 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8163 //                      rsurface.batchnormal3f_bufferoffset = 0;
8164                         // sometimes we're on a renderpath that does not use vectors (GL11/GL13/GLES1)
8165                         if (!VectorLength2(rsurface.batchnormal3f + 3*rsurface.batchfirstvertex))
8166                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8167                         if (!VectorLength2(rsurface.batchsvector3f + 3*rsurface.batchfirstvertex))
8168                                 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);
8169                         // a single autosprite surface can contain multiple sprites...
8170                         for (j = 0;j < batchnumvertices - 3;j += 4)
8171                         {
8172                                 VectorClear(center);
8173                                 for (i = 0;i < 4;i++)
8174                                         VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8175                                 VectorScale(center, 0.25f, center);
8176                                 VectorCopy(rsurface.batchnormal3f + 3*j, forward);
8177                                 VectorCopy(rsurface.batchsvector3f + 3*j, right);
8178                                 VectorCopy(rsurface.batchtvector3f + 3*j, up);
8179                                 for (i = 0;i < 4;i++)
8180                                 {
8181                                         VectorSubtract(rsurface.batchvertex3f + 3*(j+i), center, v);
8182                                         VectorMAMAMAM(1, center, DotProduct(forward, v), newforward, DotProduct(right, v), newright, DotProduct(up, v), newup, rsurface.batchvertex3f + 3*(j+i));
8183                                 }
8184                         }
8185                         // if we get here, BATCHNEED_ARRAY_NORMAL and BATCHNEED_ARRAY_VECTOR are in batchneed, so no need to check
8186                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8187                         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);
8188                         break;
8189                 case Q3DEFORM_AUTOSPRITE2:
8190                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, newforward);
8191                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.right, newright);
8192                         Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.up, newup);
8193                         VectorNormalize(newforward);
8194                         VectorNormalize(newright);
8195                         VectorNormalize(newup);
8196 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8197 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8198 //                      rsurface.batchvertex3f_bufferoffset = 0;
8199                         {
8200                                 const float *v1, *v2;
8201                                 vec3_t start, end;
8202                                 float f, l;
8203                                 struct
8204                                 {
8205                                         float length2;
8206                                         const float *v1;
8207                                         const float *v2;
8208                                 }
8209                                 shortest[2];
8210                                 memset(shortest, 0, sizeof(shortest));
8211                                 // a single autosprite surface can contain multiple sprites...
8212                                 for (j = 0;j < batchnumvertices - 3;j += 4)
8213                                 {
8214                                         VectorClear(center);
8215                                         for (i = 0;i < 4;i++)
8216                                                 VectorAdd(center, rsurface.batchvertex3f + 3*(j+i), center);
8217                                         VectorScale(center, 0.25f, center);
8218                                         // find the two shortest edges, then use them to define the
8219                                         // axis vectors for rotating around the central axis
8220                                         for (i = 0;i < 6;i++)
8221                                         {
8222                                                 v1 = rsurface.batchvertex3f + 3*(j+quadedges[i][0]);
8223                                                 v2 = rsurface.batchvertex3f + 3*(j+quadedges[i][1]);
8224                                                 l = VectorDistance2(v1, v2);
8225                                                 // this length bias tries to make sense of square polygons, assuming they are meant to be upright
8226                                                 if (v1[2] != v2[2])
8227                                                         l += (1.0f / 1024.0f);
8228                                                 if (shortest[0].length2 > l || i == 0)
8229                                                 {
8230                                                         shortest[1] = shortest[0];
8231                                                         shortest[0].length2 = l;
8232                                                         shortest[0].v1 = v1;
8233                                                         shortest[0].v2 = v2;
8234                                                 }
8235                                                 else if (shortest[1].length2 > l || i == 1)
8236                                                 {
8237                                                         shortest[1].length2 = l;
8238                                                         shortest[1].v1 = v1;
8239                                                         shortest[1].v2 = v2;
8240                                                 }
8241                                         }
8242                                         VectorLerp(shortest[0].v1, 0.5f, shortest[0].v2, start);
8243                                         VectorLerp(shortest[1].v1, 0.5f, shortest[1].v2, end);
8244                                         // this calculates the right vector from the shortest edge
8245                                         // and the up vector from the edge midpoints
8246                                         VectorSubtract(shortest[0].v1, shortest[0].v2, right);
8247                                         VectorNormalize(right);
8248                                         VectorSubtract(end, start, up);
8249                                         VectorNormalize(up);
8250                                         // calculate a forward vector to use instead of the original plane normal (this is how we get a new right vector)
8251                                         VectorSubtract(rsurface.localvieworigin, center, forward);
8252                                         //Matrix4x4_Transform3x3(&rsurface.inversematrix, r_refdef.view.forward, forward);
8253                                         VectorNegate(forward, forward);
8254                                         VectorReflect(forward, 0, up, forward);
8255                                         VectorNormalize(forward);
8256                                         CrossProduct(up, forward, newright);
8257                                         VectorNormalize(newright);
8258                                         // rotate the quad around the up axis vector, this is made
8259                                         // especially easy by the fact we know the quad is flat,
8260                                         // so we only have to subtract the center position and
8261                                         // measure distance along the right vector, and then
8262                                         // multiply that by the newright vector and add back the
8263                                         // center position
8264                                         // we also need to subtract the old position to undo the
8265                                         // displacement from the center, which we do with a
8266                                         // DotProduct, the subtraction/addition of center is also
8267                                         // optimized into DotProducts here
8268                                         l = DotProduct(right, center);
8269                                         for (i = 0;i < 4;i++)
8270                                         {
8271                                                 v1 = rsurface.batchvertex3f + 3*(j+i);
8272                                                 f = DotProduct(right, v1) - l;
8273                                                 VectorMAMAM(1, v1, -f, right, f, newright, rsurface.batchvertex3f + 3*(j+i));
8274                                         }
8275                                 }
8276                         }
8277                         if(batchneed & (BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR)) // otherwise these can stay NULL
8278                         {
8279 //                              rsurface.batchnormal3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8280 //                              rsurface.batchnormal3f_vertexbuffer = NULL;
8281 //                              rsurface.batchnormal3f_bufferoffset = 0;
8282                                 Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8283                         }
8284                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8285                         {
8286 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8287 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8288 //                              rsurface.batchsvector3f_bufferoffset = 0;
8289 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8290 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8291 //                              rsurface.batchtvector3f_bufferoffset = 0;
8292                                 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);
8293                         }
8294                         break;
8295                 case Q3DEFORM_NORMAL:
8296                         // deform the normals to make reflections wavey
8297                         rsurface.batchnormal3f = (float *)R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8298                         rsurface.batchnormal3f_vertexbuffer = NULL;
8299                         rsurface.batchnormal3f_bufferoffset = 0;
8300                         for (j = 0;j < batchnumvertices;j++)
8301                         {
8302                                 float vertex[3];
8303                                 float *normal = rsurface.batchnormal3f + 3*j;
8304                                 VectorScale(rsurface.batchvertex3f + 3*j, 0.98f, vertex);
8305                                 normal[0] = rsurface.batchnormal3f[j*3+0] + deform->parms[0] * noise4f(      vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8306                                 normal[1] = rsurface.batchnormal3f[j*3+1] + deform->parms[0] * noise4f( 98 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8307                                 normal[2] = rsurface.batchnormal3f[j*3+2] + deform->parms[0] * noise4f(196 + vertex[0], vertex[1], vertex[2], rsurface.shadertime * deform->parms[1]);
8308                                 VectorNormalize(normal);
8309                         }
8310                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8311                         {
8312 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8313 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8314 //                              rsurface.batchsvector3f_bufferoffset = 0;
8315 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8316 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8317 //                              rsurface.batchtvector3f_bufferoffset = 0;
8318                                 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);
8319                         }
8320                         break;
8321                 case Q3DEFORM_WAVE:
8322                         // deform vertex array to make wavey water and flags and such
8323                         waveparms[0] = deform->waveparms[0];
8324                         waveparms[1] = deform->waveparms[1];
8325                         waveparms[2] = deform->waveparms[2];
8326                         waveparms[3] = deform->waveparms[3];
8327                         if(!R_TestQ3WaveFunc(deform->wavefunc, waveparms))
8328                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8329                         // this is how a divisor of vertex influence on deformation
8330                         animpos = deform->parms[0] ? 1.0f / deform->parms[0] : 100.0f;
8331                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8332 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8333 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8334 //                      rsurface.batchvertex3f_bufferoffset = 0;
8335 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8336 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8337 //                      rsurface.batchnormal3f_bufferoffset = 0;
8338                         for (j = 0;j < batchnumvertices;j++)
8339                         {
8340                                 // if the wavefunc depends on time, evaluate it per-vertex
8341                                 if (waveparms[3])
8342                                 {
8343                                         waveparms[2] = deform->waveparms[2] + (rsurface.batchvertex3f[j*3+0] + rsurface.batchvertex3f[j*3+1] + rsurface.batchvertex3f[j*3+2]) * animpos;
8344                                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, waveparms);
8345                                 }
8346                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8347                         }
8348                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8349                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8350                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8351                         {
8352 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8353 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8354 //                              rsurface.batchsvector3f_bufferoffset = 0;
8355 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8356 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8357 //                              rsurface.batchtvector3f_bufferoffset = 0;
8358                                 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);
8359                         }
8360                         break;
8361                 case Q3DEFORM_BULGE:
8362                         // deform vertex array to make the surface have moving bulges
8363 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8364 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8365 //                      rsurface.batchvertex3f_bufferoffset = 0;
8366 //                      rsurface.batchnormal3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchnormal3f);
8367 //                      rsurface.batchnormal3f_vertexbuffer = NULL;
8368 //                      rsurface.batchnormal3f_bufferoffset = 0;
8369                         for (j = 0;j < batchnumvertices;j++)
8370                         {
8371                                 scale = sin(rsurface.batchtexcoordtexture2f[j*2+0] * deform->parms[0] + rsurface.shadertime * deform->parms[2]) * deform->parms[1];
8372                                 VectorMA(rsurface.batchvertex3f + 3*j, scale, rsurface.batchnormal3f + 3*j, rsurface.batchvertex3f + 3*j);
8373                         }
8374                         // if we get here, BATCHNEED_ARRAY_NORMAL is in batchneed, so no need to check
8375                         Mod_BuildNormals(rsurface.batchfirstvertex, batchnumvertices, batchnumtriangles, rsurface.batchvertex3f, rsurface.batchelement3i + 3 * rsurface.batchfirsttriangle, rsurface.batchnormal3f, r_smoothnormals_areaweighting.integer != 0);
8376                         if(batchneed & BATCHNEED_ARRAY_VECTOR) // otherwise these can stay NULL
8377                         {
8378 //                              rsurface.batchsvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8379 //                              rsurface.batchsvector3f_vertexbuffer = NULL;
8380 //                              rsurface.batchsvector3f_bufferoffset = 0;
8381 //                              rsurface.batchtvector3f = R_FrameData_Alloc(batchnumvertices * sizeof(float[3]));
8382 //                              rsurface.batchtvector3f_vertexbuffer = NULL;
8383 //                              rsurface.batchtvector3f_bufferoffset = 0;
8384                                 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);
8385                         }
8386                         break;
8387                 case Q3DEFORM_MOVE:
8388                         // deform vertex array
8389                         if(!R_TestQ3WaveFunc(deform->wavefunc, deform->waveparms))
8390                                 break; // if wavefunc is a nop, don't make a dynamic vertex array
8391                         scale = R_EvaluateQ3WaveFunc(deform->wavefunc, deform->waveparms);
8392                         VectorScale(deform->parms, scale, waveparms);
8393 //                      rsurface.batchvertex3f = R_FrameData_Store(batchnumvertices * sizeof(float[3]), rsurface.batchvertex3f);
8394 //                      rsurface.batchvertex3f_vertexbuffer = NULL;
8395 //                      rsurface.batchvertex3f_bufferoffset = 0;
8396                         for (j = 0;j < batchnumvertices;j++)
8397                                 VectorAdd(rsurface.batchvertex3f + 3*j, waveparms, rsurface.batchvertex3f + 3*j);
8398                         break;
8399                 }
8400         }
8401
8402         if (rsurface.batchtexcoordtexture2f && rsurface.texture->materialshaderpass)
8403         {
8404         // generate texcoords based on the chosen texcoord source
8405                 switch(rsurface.texture->materialshaderpass->tcgen.tcgen)
8406                 {
8407                 default:
8408                 case Q3TCGEN_TEXTURE:
8409                         break;
8410                 case Q3TCGEN_LIGHTMAP:
8411         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8412         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8413         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8414                         if (rsurface.batchtexcoordlightmap2f)
8415                                 memcpy(rsurface.batchtexcoordtexture2f, rsurface.batchtexcoordlightmap2f, batchnumvertices * sizeof(float[2]));
8416                         break;
8417                 case Q3TCGEN_VECTOR:
8418         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8419         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8420         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8421                         for (j = 0;j < batchnumvertices;j++)
8422                         {
8423                                 rsurface.batchtexcoordtexture2f[j*2+0] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms);
8424                                 rsurface.batchtexcoordtexture2f[j*2+1] = DotProduct(rsurface.batchvertex3f + 3*j, rsurface.texture->materialshaderpass->tcgen.parms + 3);
8425                         }
8426                         break;
8427                 case Q3TCGEN_ENVIRONMENT:
8428                         // make environment reflections using a spheremap
8429                         rsurface.batchtexcoordtexture2f = (float *)R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8430                         rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8431                         rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8432                         for (j = 0;j < batchnumvertices;j++)
8433                         {
8434                                 // identical to Q3A's method, but executed in worldspace so
8435                                 // carried models can be shiny too
8436
8437                                 float viewer[3], d, reflected[3], worldreflected[3];
8438
8439                                 VectorSubtract(rsurface.localvieworigin, rsurface.batchvertex3f + 3*j, viewer);
8440                                 // VectorNormalize(viewer);
8441
8442                                 d = DotProduct(rsurface.batchnormal3f + 3*j, viewer);
8443
8444                                 reflected[0] = rsurface.batchnormal3f[j*3+0]*2*d - viewer[0];
8445                                 reflected[1] = rsurface.batchnormal3f[j*3+1]*2*d - viewer[1];
8446                                 reflected[2] = rsurface.batchnormal3f[j*3+2]*2*d - viewer[2];
8447                                 // note: this is proportinal to viewer, so we can normalize later
8448
8449                                 Matrix4x4_Transform3x3(&rsurface.matrix, reflected, worldreflected);
8450                                 VectorNormalize(worldreflected);
8451
8452                                 // note: this sphere map only uses world x and z!
8453                                 // so positive and negative y will LOOK THE SAME.
8454                                 rsurface.batchtexcoordtexture2f[j*2+0] = 0.5 + 0.5 * worldreflected[1];
8455                                 rsurface.batchtexcoordtexture2f[j*2+1] = 0.5 - 0.5 * worldreflected[2];
8456                         }
8457                         break;
8458                 }
8459                 // the only tcmod that needs software vertex processing is turbulent, so
8460                 // check for it here and apply the changes if needed
8461                 // and we only support that as the first one
8462                 // (handling a mixture of turbulent and other tcmods would be problematic
8463                 //  without punting it entirely to a software path)
8464                 if (rsurface.texture->materialshaderpass->tcmods[0].tcmod == Q3TCMOD_TURBULENT)
8465                 {
8466                         amplitude = rsurface.texture->materialshaderpass->tcmods[0].parms[1];
8467                         animpos = rsurface.texture->materialshaderpass->tcmods[0].parms[2] + rsurface.shadertime * rsurface.texture->materialshaderpass->tcmods[0].parms[3];
8468         //              rsurface.batchtexcoordtexture2f = R_FrameData_Alloc(batchnumvertices * sizeof(float[2]));
8469         //              rsurface.batchtexcoordtexture2f_vertexbuffer = NULL;
8470         //              rsurface.batchtexcoordtexture2f_bufferoffset = 0;
8471                         for (j = 0;j < batchnumvertices;j++)
8472                         {
8473                                 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);
8474                                 rsurface.batchtexcoordtexture2f[j*2+1] += amplitude * sin(((rsurface.batchvertex3f[j*3+1]                                ) * 1.0 / 1024.0f + animpos) * M_PI * 2);
8475                         }
8476                 }
8477         }
8478 }
8479
8480 void RSurf_DrawBatch(void)
8481 {
8482         // sometimes a zero triangle surface (usually a degenerate patch) makes it
8483         // through the pipeline, killing it earlier in the pipeline would have
8484         // per-surface overhead rather than per-batch overhead, so it's best to
8485         // reject it here, before it hits glDraw.
8486         if (rsurface.batchnumtriangles == 0)
8487                 return;
8488 #if 0
8489         // batch debugging code
8490         if (r_test.integer && rsurface.entity == r_refdef.scene.worldentity && rsurface.batchvertex3f == r_refdef.scene.worldentity->model->surfmesh.data_vertex3f)
8491         {
8492                 int i;
8493                 int j;
8494                 int c;
8495                 const int *e;
8496                 e = rsurface.batchelement3i + rsurface.batchfirsttriangle*3;
8497                 for (i = 0;i < rsurface.batchnumtriangles*3;i++)
8498                 {
8499                         c = e[i];
8500                         for (j = 0;j < rsurface.entity->model->num_surfaces;j++)
8501                         {
8502                                 if (c >= rsurface.modelsurfaces[j].num_firstvertex && c < (rsurface.modelsurfaces[j].num_firstvertex + rsurface.modelsurfaces[j].num_vertices))
8503                                 {
8504                                         if (rsurface.modelsurfaces[j].texture != rsurface.texture)
8505                                                 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);
8506                                         break;
8507                                 }
8508                         }
8509                 }
8510         }
8511 #endif
8512         if (rsurface.batchmultidraw)
8513         {
8514                 // issue multiple draws rather than copying index data
8515                 int numsurfaces = rsurface.batchmultidrawnumsurfaces;
8516                 const msurface_t **surfacelist = rsurface.batchmultidrawsurfacelist;
8517                 int i, j, k, firstvertex, endvertex, firsttriangle, endtriangle;
8518                 for (i = 0;i < numsurfaces;)
8519                 {
8520                         // combine consecutive surfaces as one draw
8521                         for (k = i, j = i + 1;j < numsurfaces;k = j, j++)
8522                                 if (surfacelist[j] != surfacelist[k] + 1)
8523                                         break;
8524                         firstvertex = surfacelist[i]->num_firstvertex;
8525                         endvertex = surfacelist[k]->num_firstvertex + surfacelist[k]->num_vertices;
8526                         firsttriangle = surfacelist[i]->num_firsttriangle;
8527                         endtriangle = surfacelist[k]->num_firsttriangle + surfacelist[k]->num_triangles;
8528                         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);
8529                         i = j;
8530                 }
8531         }
8532         else
8533         {
8534                 // there is only one consecutive run of index data (may have been combined)
8535                 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);
8536         }
8537 }
8538
8539 static int RSurf_FindWaterPlaneForSurface(const msurface_t *surface)
8540 {
8541         // pick the closest matching water plane
8542         int planeindex, vertexindex, bestplaneindex = -1;
8543         float d, bestd;
8544         vec3_t vert;
8545         const float *v;
8546         r_waterstate_waterplane_t *p;
8547         qbool prepared = false;
8548         bestd = 0;
8549         for (planeindex = 0, p = r_fb.water.waterplanes;planeindex < r_fb.water.numwaterplanes;planeindex++, p++)
8550         {
8551                 if(p->camera_entity != rsurface.texture->camera_entity)
8552                         continue;
8553                 d = 0;
8554                 if(!prepared)
8555                 {
8556                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX, 1, &surface);
8557                         prepared = true;
8558                         if(rsurface.batchnumvertices == 0)
8559                                 break;
8560                 }
8561                 for (vertexindex = 0, v = rsurface.batchvertex3f + rsurface.batchfirstvertex * 3;vertexindex < rsurface.batchnumvertices;vertexindex++, v += 3)
8562                 {
8563                         Matrix4x4_Transform(&rsurface.matrix, v, vert);
8564                         d += fabs(PlaneDiff(vert, &p->plane));
8565                 }
8566                 if (bestd > d || bestplaneindex < 0)
8567                 {
8568                         bestd = d;
8569                         bestplaneindex = planeindex;
8570                 }
8571         }
8572         return bestplaneindex;
8573         // NOTE: this MAY return a totally unrelated water plane; we can ignore
8574         // this situation though, as it might be better to render single larger
8575         // batches with useless stuff (backface culled for example) than to
8576         // render multiple smaller batches
8577 }
8578
8579 void RSurf_SetupDepthAndCulling(void)
8580 {
8581         // submodels are biased to avoid z-fighting with world surfaces that they
8582         // may be exactly overlapping (avoids z-fighting artifacts on certain
8583         // doors and things in Quake maps)
8584         GL_DepthRange(0, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SHORTDEPTHRANGE) ? 0.0625 : 1);
8585         GL_PolygonOffset(rsurface.basepolygonfactor + rsurface.texture->biaspolygonfactor, rsurface.basepolygonoffset + rsurface.texture->biaspolygonoffset);
8586         GL_DepthTest(!(rsurface.texture->currentmaterialflags & MATERIALFLAG_NODEPTHTEST));
8587         GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
8588 }
8589
8590 static void R_DrawTextureSurfaceList_Sky(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8591 {
8592         int j;
8593         const float *v;
8594         float p[3], mins[3], maxs[3];
8595         int scissor[4];
8596         // transparent sky would be ridiculous
8597         if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8598                 return;
8599         R_SetupShader_Generic_NoTexture(false, false);
8600         skyrenderlater = true;
8601         RSurf_SetupDepthAndCulling();
8602         GL_DepthMask(true);
8603
8604         // add the vertices of the surfaces to a world bounding box so we can scissor the sky render later
8605         if (r_sky_scissor.integer)
8606         {
8607                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8608                 for (j = 0, v = rsurface.batchvertex3f + 3 * rsurface.batchfirstvertex; j < rsurface.batchnumvertices; j++, v += 3)
8609                 {
8610                         Matrix4x4_Transform(&rsurface.matrix, v, p);
8611                         if (j > 0)
8612                         {
8613                                 if (mins[0] > p[0]) mins[0] = p[0];
8614                                 if (mins[1] > p[1]) mins[1] = p[1];
8615                                 if (mins[2] > p[2]) mins[2] = p[2];
8616                                 if (maxs[0] < p[0]) maxs[0] = p[0];
8617                                 if (maxs[1] < p[1]) maxs[1] = p[1];
8618                                 if (maxs[2] < p[2]) maxs[2] = p[2];
8619                         }
8620                         else
8621                         {
8622                                 VectorCopy(p, mins);
8623                                 VectorCopy(p, maxs);
8624                         }
8625                 }
8626                 if (!R_ScissorForBBox(mins, maxs, scissor))
8627                 {
8628                         if (skyscissor[2])
8629                         {
8630                                 if (skyscissor[0] > scissor[0])
8631                                 {
8632                                         skyscissor[2] += skyscissor[0] - scissor[0];
8633                                         skyscissor[0] = scissor[0];
8634                                 }
8635                                 if (skyscissor[1] > scissor[1])
8636                                 {
8637                                         skyscissor[3] += skyscissor[1] - scissor[1];
8638                                         skyscissor[1] = scissor[1];
8639                                 }
8640                                 if (skyscissor[0] + skyscissor[2] < scissor[0] + scissor[2])
8641                                         skyscissor[2] = scissor[0] + scissor[2] - skyscissor[0];
8642                                 if (skyscissor[1] + skyscissor[3] < scissor[1] + scissor[3])
8643                                         skyscissor[3] = scissor[1] + scissor[3] - skyscissor[1];
8644                         }
8645                         else
8646                                 Vector4Copy(scissor, skyscissor);
8647                 }
8648         }
8649
8650         // LadyHavoc: HalfLife maps have freaky skypolys so don't use
8651         // skymasking on them, and Quake3 never did sky masking (unlike
8652         // software Quake and software Quake2), so disable the sky masking
8653         // in Quake3 maps as it causes problems with q3map2 sky tricks,
8654         // and skymasking also looks very bad when noclipping outside the
8655         // level, so don't use it then either.
8656         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)
8657         {
8658                 R_Mesh_ResetTextureState();
8659                 if (skyrendermasked)
8660                 {
8661                         R_SetupShader_DepthOrShadow(false, false, false);
8662                         // depth-only (masking)
8663                         GL_ColorMask(0, 0, 0, 0);
8664                         // just to make sure that braindead drivers don't draw
8665                         // anything despite that colormask...
8666                         GL_BlendFunc(GL_ZERO, GL_ONE);
8667                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8668                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8669                 }
8670                 else
8671                 {
8672                         R_SetupShader_Generic_NoTexture(false, false);
8673                         // fog sky
8674                         GL_BlendFunc(GL_ONE, GL_ZERO);
8675                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, texturenumsurfaces, texturesurfacelist);
8676                         GL_Color(r_refdef.fogcolor[0], r_refdef.fogcolor[1], r_refdef.fogcolor[2], 1);
8677                         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
8678                 }
8679                 RSurf_DrawBatch();
8680                 if (skyrendermasked)
8681                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8682         }
8683         R_Mesh_ResetTextureState();
8684         GL_Color(1, 1, 1, 1);
8685 }
8686
8687 extern rtexture_t *r_shadow_prepasslightingdiffusetexture;
8688 extern rtexture_t *r_shadow_prepasslightingspeculartexture;
8689 static void R_DrawTextureSurfaceList_GL20(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth, qbool prepass, qbool ui)
8690 {
8691         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA)))
8692                 return;
8693         if (prepass)
8694         {
8695                 // render screenspace normalmap to texture
8696                 GL_DepthMask(true);
8697                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_DEFERREDGEOMETRY, texturenumsurfaces, texturesurfacelist, NULL, false, false);
8698                 RSurf_DrawBatch();
8699                 return;
8700         }
8701
8702         // bind lightmap texture
8703
8704         // water/refraction/reflection/camera surfaces have to be handled specially
8705         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA | MATERIALFLAG_REFLECTION)))
8706         {
8707                 int start, end, startplaneindex;
8708                 for (start = 0;start < texturenumsurfaces;start = end)
8709                 {
8710                         startplaneindex = RSurf_FindWaterPlaneForSurface(texturesurfacelist[start]);
8711                         if(startplaneindex < 0)
8712                         {
8713                                 // this happens if the plane e.g. got backface culled and thus didn't get a water plane. We can just ignore this.
8714                                 // Con_Printf("No matching water plane for surface with material flags 0x%08x - PLEASE DEBUG THIS\n", rsurface.texture->currentmaterialflags);
8715                                 end = start + 1;
8716                                 continue;
8717                         }
8718                         for (end = start + 1;end < texturenumsurfaces && startplaneindex == RSurf_FindWaterPlaneForSurface(texturesurfacelist[end]);end++)
8719                                 ;
8720                         // now that we have a batch using the same planeindex, render it
8721                         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_CAMERA)))
8722                         {
8723                                 // render water or distortion background
8724                                 GL_DepthMask(true);
8725                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BACKGROUND, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false, false);
8726                                 RSurf_DrawBatch();
8727                                 // blend surface on top
8728                                 GL_DepthMask(false);
8729                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, NULL, false, false);
8730                                 RSurf_DrawBatch();
8731                         }
8732                         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_REFLECTION))
8733                         {
8734                                 // render surface with reflection texture as input
8735                                 GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8736                                 R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, end-start, texturesurfacelist + start, (void *)(r_fb.water.waterplanes + startplaneindex), false, false);
8737                                 RSurf_DrawBatch();
8738                         }
8739                 }
8740                 return;
8741         }
8742
8743         // render surface batch normally
8744         GL_DepthMask(writedepth && !(rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED));
8745         R_SetupShader_Surface(vec3_origin, vec3_origin, vec3_origin, RSURFPASS_BASE, texturenumsurfaces, texturesurfacelist, NULL, (rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) != 0 || ui, ui);
8746         RSurf_DrawBatch();
8747 }
8748
8749 static void R_DrawTextureSurfaceList_ShowSurfaces(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth)
8750 {
8751         int vi;
8752         int j;
8753         int texturesurfaceindex;
8754         int k;
8755         const msurface_t *surface;
8756         float surfacecolor4f[4];
8757
8758 //      R_Mesh_ResetTextureState();
8759         R_SetupShader_Generic_NoTexture(false, false);
8760
8761         GL_BlendFunc(GL_ONE, GL_ZERO);
8762         GL_DepthMask(writedepth);
8763
8764         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_VERTEXCOLOR | BATCHNEED_ARRAY_TEXCOORD | BATCHNEED_ALWAYSCOPY, texturenumsurfaces, texturesurfacelist);
8765         vi = 0;
8766         for (texturesurfaceindex = 0;texturesurfaceindex < texturenumsurfaces;texturesurfaceindex++)
8767         {
8768                 surface = texturesurfacelist[texturesurfaceindex];
8769                 k = (int)(((size_t)surface) / sizeof(msurface_t));
8770                 Vector4Set(surfacecolor4f, (k & 0xF) * (1.0f / 16.0f), (k & 0xF0) * (1.0f / 256.0f), (k & 0xF00) * (1.0f / 4096.0f), 1);
8771                 for (j = 0;j < surface->num_vertices;j++)
8772                 {
8773                         Vector4Copy(surfacecolor4f, rsurface.batchlightmapcolor4f + 4 * vi);
8774                         vi++;
8775                 }
8776         }
8777         R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchlightmapcolor4f, rsurface.batchtexcoordtexture2f);
8778         RSurf_DrawBatch();
8779 }
8780
8781 static void R_DrawModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth, qbool prepass, qbool ui)
8782 {
8783         CHECKGLERROR
8784         RSurf_SetupDepthAndCulling();
8785         if (r_showsurfaces.integer && r_refdef.view.showdebug)
8786         {
8787                 R_DrawTextureSurfaceList_ShowSurfaces(texturenumsurfaces, texturesurfacelist, writedepth);
8788                 return;
8789         }
8790         switch (vid.renderpath)
8791         {
8792         case RENDERPATH_GL32:
8793         case RENDERPATH_GLES2:
8794                 R_DrawTextureSurfaceList_GL20(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8795                 break;
8796         }
8797         CHECKGLERROR
8798 }
8799
8800 static void R_DrawSurface_TransparentCallback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
8801 {
8802         int i, j;
8803         int texturenumsurfaces, endsurface;
8804         texture_t *texture;
8805         const msurface_t *surface;
8806         const msurface_t *texturesurfacelist[MESHQUEUE_TRANSPARENT_BATCHSIZE];
8807
8808         RSurf_ActiveModelEntity(ent, true, true, false);
8809
8810         if (r_transparentdepthmasking.integer)
8811         {
8812                 qbool setup = false;
8813                 for (i = 0;i < numsurfaces;i = j)
8814                 {
8815                         j = i + 1;
8816                         surface = rsurface.modelsurfaces + surfacelist[i];
8817                         texture = surface->texture;
8818                         rsurface.texture = R_GetCurrentTexture(texture);
8819                         rsurface.lightmaptexture = NULL;
8820                         rsurface.deluxemaptexture = NULL;
8821                         rsurface.uselightmaptexture = false;
8822                         // scan ahead until we find a different texture
8823                         endsurface = min(i + 1024, numsurfaces);
8824                         texturenumsurfaces = 0;
8825                         texturesurfacelist[texturenumsurfaces++] = surface;
8826                         for (;j < endsurface;j++)
8827                         {
8828                                 surface = rsurface.modelsurfaces + surfacelist[j];
8829                                 if (texture != surface->texture)
8830                                         break;
8831                                 texturesurfacelist[texturenumsurfaces++] = surface;
8832                         }
8833                         if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_TRANSDEPTH))
8834                                 continue;
8835                         // render the range of surfaces as depth
8836                         if (!setup)
8837                         {
8838                                 setup = true;
8839                                 GL_ColorMask(0,0,0,0);
8840                                 GL_Color(1,1,1,1);
8841                                 GL_DepthTest(true);
8842                                 GL_BlendFunc(GL_ONE, GL_ZERO);
8843                                 GL_DepthMask(true);
8844 //                              R_Mesh_ResetTextureState();
8845                         }
8846                         RSurf_SetupDepthAndCulling();
8847                         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8848                         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
8849                         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8850                         RSurf_DrawBatch();
8851                 }
8852                 if (setup)
8853                         GL_ColorMask(r_refdef.view.colormask[0], r_refdef.view.colormask[1], r_refdef.view.colormask[2], 1);
8854         }
8855
8856         for (i = 0;i < numsurfaces;i = j)
8857         {
8858                 j = i + 1;
8859                 surface = rsurface.modelsurfaces + surfacelist[i];
8860                 texture = surface->texture;
8861                 rsurface.texture = R_GetCurrentTexture(texture);
8862                 // scan ahead until we find a different texture
8863                 endsurface = min(i + MESHQUEUE_TRANSPARENT_BATCHSIZE, numsurfaces);
8864                 texturenumsurfaces = 0;
8865                 texturesurfacelist[texturenumsurfaces++] = surface;
8866                         rsurface.lightmaptexture = surface->lightmaptexture;
8867                         rsurface.deluxemaptexture = surface->deluxemaptexture;
8868                         rsurface.uselightmaptexture = surface->lightmaptexture != NULL;
8869                         for (;j < endsurface;j++)
8870                         {
8871                                 surface = rsurface.modelsurfaces + surfacelist[j];
8872                                 if (texture != surface->texture || rsurface.lightmaptexture != surface->lightmaptexture)
8873                                         break;
8874                                 texturesurfacelist[texturenumsurfaces++] = surface;
8875                         }
8876                 // render the range of surfaces
8877                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, false, false, false);
8878         }
8879         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
8880 }
8881
8882 static void R_ProcessTransparentTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8883 {
8884         // transparent surfaces get pushed off into the transparent queue
8885         int surfacelistindex;
8886         const msurface_t *surface;
8887         vec3_t tempcenter, center;
8888         for (surfacelistindex = 0;surfacelistindex < texturenumsurfaces;surfacelistindex++)
8889         {
8890                 surface = texturesurfacelist[surfacelistindex];
8891                 if (r_transparent_sortsurfacesbynearest.integer)
8892                 {
8893                         tempcenter[0] = bound(surface->mins[0], rsurface.localvieworigin[0], surface->maxs[0]);
8894                         tempcenter[1] = bound(surface->mins[1], rsurface.localvieworigin[1], surface->maxs[1]);
8895                         tempcenter[2] = bound(surface->mins[2], rsurface.localvieworigin[2], surface->maxs[2]);
8896                 }
8897                 else
8898                 {
8899                         tempcenter[0] = (surface->mins[0] + surface->maxs[0]) * 0.5f;
8900                         tempcenter[1] = (surface->mins[1] + surface->maxs[1]) * 0.5f;
8901                         tempcenter[2] = (surface->mins[2] + surface->maxs[2]) * 0.5f;
8902                 }
8903                 Matrix4x4_Transform(&rsurface.matrix, tempcenter, center);
8904                 if (rsurface.entity->transparent_offset) // transparent offset
8905                 {
8906                         center[0] += r_refdef.view.forward[0]*rsurface.entity->transparent_offset;
8907                         center[1] += r_refdef.view.forward[1]*rsurface.entity->transparent_offset;
8908                         center[2] += r_refdef.view.forward[2]*rsurface.entity->transparent_offset;
8909                 }
8910                 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);
8911         }
8912 }
8913
8914 static void R_DrawTextureSurfaceList_DepthOnly(int texturenumsurfaces, const msurface_t **texturesurfacelist)
8915 {
8916         if ((rsurface.texture->currentmaterialflags & (MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_BLENDED | MATERIALFLAG_ALPHATEST)))
8917                 return;
8918         if (r_fb.water.renderingscene && (rsurface.texture->currentmaterialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFLECTION)))
8919                 return;
8920         RSurf_SetupDepthAndCulling();
8921         RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ALLOWMULTIDRAW, texturenumsurfaces, texturesurfacelist);
8922         R_Mesh_PrepareVertices_Vertex3f(rsurface.batchnumvertices, rsurface.batchvertex3f, rsurface.batchvertex3f_vertexbuffer, rsurface.batchvertex3f_bufferoffset);
8923         R_SetupShader_DepthOrShadow(false, false, !!rsurface.batchskeletaltransform3x4);
8924         RSurf_DrawBatch();
8925 }
8926
8927 static void R_ProcessModelTextureSurfaceList(int texturenumsurfaces, const msurface_t **texturesurfacelist, qbool writedepth, qbool depthonly, qbool prepass, qbool ui)
8928 {
8929         CHECKGLERROR
8930         if (ui)
8931                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8932         else if (depthonly)
8933                 R_DrawTextureSurfaceList_DepthOnly(texturenumsurfaces, texturesurfacelist);
8934         else if (prepass)
8935         {
8936                 if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
8937                         return;
8938                 if (rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED)
8939                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
8940                 else
8941                         R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth, prepass, ui);
8942         }
8943         else if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_SKY) && (!r_showsurfaces.integer || r_showsurfaces.integer == 3))
8944                 R_DrawTextureSurfaceList_Sky(texturenumsurfaces, texturesurfacelist);
8945         else if (!(rsurface.texture->currentmaterialflags & MATERIALFLAG_WALL))
8946                 return;
8947         else if (((rsurface.texture->currentmaterialflags & MATERIALFLAGMASK_DEPTHSORTED) || (r_showsurfaces.integer == 3 && (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST))))
8948         {
8949                 // in the deferred case, transparent surfaces were queued during prepass
8950                 if (!r_shadow_usingdeferredprepass)
8951                         R_ProcessTransparentTextureSurfaceList(texturenumsurfaces, texturesurfacelist);
8952         }
8953         else
8954         {
8955                 // the alphatest check is to make sure we write depth for anything we skipped on the depth-only pass earlier
8956                 R_DrawModelTextureSurfaceList(texturenumsurfaces, texturesurfacelist, writedepth || (rsurface.texture->currentmaterialflags & MATERIALFLAG_ALPHATEST), prepass, ui);
8957         }
8958         CHECKGLERROR
8959 }
8960
8961 static void R_QueueModelSurfaceList(entity_render_t *ent, int numsurfaces, const msurface_t **surfacelist, int flagsmask, qbool writedepth, qbool depthonly, qbool prepass, qbool ui)
8962 {
8963         int i, j;
8964         texture_t *texture;
8965         R_FrameData_SetMark();
8966         // break the surface list down into batches by texture and use of lightmapping
8967         for (i = 0;i < numsurfaces;i = j)
8968         {
8969                 j = i + 1;
8970                 // texture is the base texture pointer, rsurface.texture is the
8971                 // current frame/skin the texture is directing us to use (for example
8972                 // if a model has 2 skins and it is on skin 1, then skin 0 tells us to
8973                 // use skin 1 instead)
8974                 texture = surfacelist[i]->texture;
8975                 rsurface.texture = R_GetCurrentTexture(texture);
8976                 if (!(rsurface.texture->currentmaterialflags & flagsmask) || (rsurface.texture->currentmaterialflags & MATERIALFLAG_NODRAW))
8977                 {
8978                         // if this texture is not the kind we want, skip ahead to the next one
8979                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
8980                                 ;
8981                         continue;
8982                 }
8983                 if(depthonly || prepass)
8984                 {
8985                         rsurface.lightmaptexture = NULL;
8986                         rsurface.deluxemaptexture = NULL;
8987                         rsurface.uselightmaptexture = false;
8988                         // simply scan ahead until we find a different texture or lightmap state
8989                         for (;j < numsurfaces && texture == surfacelist[j]->texture;j++)
8990                                 ;
8991                 }
8992                 else
8993                 {
8994                         rsurface.lightmaptexture = surfacelist[i]->lightmaptexture;
8995                         rsurface.deluxemaptexture = surfacelist[i]->deluxemaptexture;
8996                         rsurface.uselightmaptexture = surfacelist[i]->lightmaptexture != NULL;
8997                         // simply scan ahead until we find a different texture or lightmap state
8998                         for (;j < numsurfaces && texture == surfacelist[j]->texture && rsurface.lightmaptexture == surfacelist[j]->lightmaptexture;j++)
8999                                 ;
9000                 }
9001                 // render the range of surfaces
9002                 R_ProcessModelTextureSurfaceList(j - i, surfacelist + i, writedepth, depthonly, prepass, ui);
9003         }
9004         R_FrameData_ReturnToMark();
9005 }
9006
9007 float locboxvertex3f[6*4*3] =
9008 {
9009         1,0,1, 1,0,0, 1,1,0, 1,1,1,
9010         0,1,1, 0,1,0, 0,0,0, 0,0,1,
9011         1,1,1, 1,1,0, 0,1,0, 0,1,1,
9012         0,0,1, 0,0,0, 1,0,0, 1,0,1,
9013         0,0,1, 1,0,1, 1,1,1, 0,1,1,
9014         1,0,0, 0,0,0, 0,1,0, 1,1,0
9015 };
9016
9017 unsigned short locboxelements[6*2*3] =
9018 {
9019          0, 1, 2, 0, 2, 3,
9020          4, 5, 6, 4, 6, 7,
9021          8, 9,10, 8,10,11,
9022         12,13,14, 12,14,15,
9023         16,17,18, 16,18,19,
9024         20,21,22, 20,22,23
9025 };
9026
9027 static void R_DrawLoc_Callback(const entity_render_t *ent, const rtlight_t *rtlight, int numsurfaces, int *surfacelist)
9028 {
9029         int i, j;
9030         cl_locnode_t *loc = (cl_locnode_t *)ent;
9031         vec3_t mins, size;
9032         float vertex3f[6*4*3];
9033         CHECKGLERROR
9034         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9035         GL_DepthMask(false);
9036         GL_DepthRange(0, 1);
9037         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9038         GL_DepthTest(true);
9039         GL_CullFace(GL_NONE);
9040         R_EntityMatrix(&identitymatrix);
9041
9042 //      R_Mesh_ResetTextureState();
9043
9044         i = surfacelist[0];
9045         GL_Color(((i & 0x0007) >> 0) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9046                          ((i & 0x0038) >> 3) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9047                          ((i & 0x01C0) >> 6) * (1.0f / 7.0f) * r_refdef.view.colorscale,
9048                         surfacelist[0] < 0 ? 0.5f : 0.125f);
9049
9050         if (VectorCompare(loc->mins, loc->maxs))
9051         {
9052                 VectorSet(size, 2, 2, 2);
9053                 VectorMA(loc->mins, -0.5f, size, mins);
9054         }
9055         else
9056         {
9057                 VectorCopy(loc->mins, mins);
9058                 VectorSubtract(loc->maxs, loc->mins, size);
9059         }
9060
9061         for (i = 0;i < 6*4*3;)
9062                 for (j = 0;j < 3;j++, i++)
9063                         vertex3f[i] = mins[j] + size[j] * locboxvertex3f[i];
9064
9065         R_Mesh_PrepareVertices_Generic_Arrays(6*4, vertex3f, NULL, NULL);
9066         R_SetupShader_Generic_NoTexture(false, false);
9067         R_Mesh_Draw(0, 6*4, 0, 6*2, NULL, NULL, 0, locboxelements, NULL, 0);
9068 }
9069
9070 void R_DrawLocs(void)
9071 {
9072         int index;
9073         cl_locnode_t *loc, *nearestloc;
9074         vec3_t center;
9075         nearestloc = CL_Locs_FindNearest(cl.movement_origin);
9076         for (loc = cl.locnodes, index = 0;loc;loc = loc->next, index++)
9077         {
9078                 VectorLerp(loc->mins, 0.5f, loc->maxs, center);
9079                 R_MeshQueue_AddTransparent(TRANSPARENTSORT_DISTANCE, center, R_DrawLoc_Callback, (entity_render_t *)loc, loc == nearestloc ? -1 : index, NULL);
9080         }
9081 }
9082
9083 void R_DecalSystem_Reset(decalsystem_t *decalsystem)
9084 {
9085         if (decalsystem->decals)
9086                 Mem_Free(decalsystem->decals);
9087         memset(decalsystem, 0, sizeof(*decalsystem));
9088 }
9089
9090 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)
9091 {
9092         tridecal_t *decal;
9093         tridecal_t *decals;
9094         int i;
9095
9096         // expand or initialize the system
9097         if (decalsystem->maxdecals <= decalsystem->numdecals)
9098         {
9099                 decalsystem_t old = *decalsystem;
9100                 qbool useshortelements;
9101                 decalsystem->maxdecals = max(16, decalsystem->maxdecals * 2);
9102                 useshortelements = decalsystem->maxdecals * 3 <= 65536;
9103                 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)));
9104                 decalsystem->color4f = (float *)(decalsystem->decals + decalsystem->maxdecals);
9105                 decalsystem->texcoord2f = (float *)(decalsystem->color4f + decalsystem->maxdecals*12);
9106                 decalsystem->vertex3f = (float *)(decalsystem->texcoord2f + decalsystem->maxdecals*6);
9107                 decalsystem->element3i = (int *)(decalsystem->vertex3f + decalsystem->maxdecals*9);
9108                 decalsystem->element3s = (useshortelements ? ((unsigned short *)(decalsystem->element3i + decalsystem->maxdecals*3)) : NULL);
9109                 if (decalsystem->numdecals)
9110                         memcpy(decalsystem->decals, old.decals, decalsystem->numdecals * sizeof(tridecal_t));
9111                 if (old.decals)
9112                         Mem_Free(old.decals);
9113                 for (i = 0;i < decalsystem->maxdecals*3;i++)
9114                         decalsystem->element3i[i] = i;
9115                 if (useshortelements)
9116                         for (i = 0;i < decalsystem->maxdecals*3;i++)
9117                                 decalsystem->element3s[i] = i;
9118         }
9119
9120         // grab a decal and search for another free slot for the next one
9121         decals = decalsystem->decals;
9122         decal = decalsystem->decals + (i = decalsystem->freedecal++);
9123         for (i = decalsystem->freedecal;i < decalsystem->numdecals && decals[i].color4f[0][3];i++)
9124                 ;
9125         decalsystem->freedecal = i;
9126         if (decalsystem->numdecals <= i)
9127                 decalsystem->numdecals = i + 1;
9128
9129         // initialize the decal
9130         decal->lived = 0;
9131         decal->triangleindex = triangleindex;
9132         decal->surfaceindex = surfaceindex;
9133         decal->decalsequence = decalsequence;
9134         decal->color4f[0][0] = c0[0];
9135         decal->color4f[0][1] = c0[1];
9136         decal->color4f[0][2] = c0[2];
9137         decal->color4f[0][3] = 1;
9138         decal->color4f[1][0] = c1[0];
9139         decal->color4f[1][1] = c1[1];
9140         decal->color4f[1][2] = c1[2];
9141         decal->color4f[1][3] = 1;
9142         decal->color4f[2][0] = c2[0];
9143         decal->color4f[2][1] = c2[1];
9144         decal->color4f[2][2] = c2[2];
9145         decal->color4f[2][3] = 1;
9146         decal->vertex3f[0][0] = v0[0];
9147         decal->vertex3f[0][1] = v0[1];
9148         decal->vertex3f[0][2] = v0[2];
9149         decal->vertex3f[1][0] = v1[0];
9150         decal->vertex3f[1][1] = v1[1];
9151         decal->vertex3f[1][2] = v1[2];
9152         decal->vertex3f[2][0] = v2[0];
9153         decal->vertex3f[2][1] = v2[1];
9154         decal->vertex3f[2][2] = v2[2];
9155         decal->texcoord2f[0][0] = t0[0];
9156         decal->texcoord2f[0][1] = t0[1];
9157         decal->texcoord2f[1][0] = t1[0];
9158         decal->texcoord2f[1][1] = t1[1];
9159         decal->texcoord2f[2][0] = t2[0];
9160         decal->texcoord2f[2][1] = t2[1];
9161         TriangleNormal(v0, v1, v2, decal->plane);
9162         VectorNormalize(decal->plane);
9163         decal->plane[3] = DotProduct(v0, decal->plane);
9164 }
9165
9166 extern cvar_t cl_decals_bias;
9167 extern cvar_t cl_decals_models;
9168 extern cvar_t cl_decals_newsystem_intensitymultiplier;
9169 // baseparms, parms, temps
9170 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, qbool dynamic, float (*planes)[4], matrix4x4_t *projection, int triangleindex, int surfaceindex)
9171 {
9172         int cornerindex;
9173         int index;
9174         float v[9][3];
9175         const float *vertex3f;
9176         const float *normal3f;
9177         int numpoints;
9178         float points[2][9][3];
9179         float temp[3];
9180         float tc[9][2];
9181         float f;
9182         float c[9][4];
9183         const int *e;
9184
9185         e = rsurface.modelelement3i + 3*triangleindex;
9186
9187         vertex3f = rsurface.modelvertex3f;
9188         normal3f = rsurface.modelnormal3f;
9189
9190         if (normal3f)
9191         {
9192                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9193                 {
9194                         index = 3*e[cornerindex];
9195                         VectorMA(vertex3f + index, cl_decals_bias.value, normal3f + index, v[cornerindex]);
9196                 }
9197         }
9198         else
9199         {
9200                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9201                 {
9202                         index = 3*e[cornerindex];
9203                         VectorCopy(vertex3f + index, v[cornerindex]);
9204                 }
9205         }
9206
9207         // cull backfaces
9208         //TriangleNormal(v[0], v[1], v[2], normal);
9209         //if (DotProduct(normal, localnormal) < 0.0f)
9210         //      continue;
9211         // clip by each of the box planes formed from the projection matrix
9212         // if anything survives, we emit the decal
9213         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]);
9214         if (numpoints < 3)
9215                 return;
9216         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]);
9217         if (numpoints < 3)
9218                 return;
9219         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]);
9220         if (numpoints < 3)
9221                 return;
9222         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]);
9223         if (numpoints < 3)
9224                 return;
9225         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]);
9226         if (numpoints < 3)
9227                 return;
9228         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]);
9229         if (numpoints < 3)
9230                 return;
9231         // some part of the triangle survived, so we have to accept it...
9232         if (dynamic)
9233         {
9234                 // dynamic always uses the original triangle
9235                 numpoints = 3;
9236                 for (cornerindex = 0;cornerindex < 3;cornerindex++)
9237                 {
9238                         index = 3*e[cornerindex];
9239                         VectorCopy(vertex3f + index, v[cornerindex]);
9240                 }
9241         }
9242         for (cornerindex = 0;cornerindex < numpoints;cornerindex++)
9243         {
9244                 // convert vertex positions to texcoords
9245                 Matrix4x4_Transform(projection, v[cornerindex], temp);
9246                 tc[cornerindex][0] = (temp[1]+1.0f)*0.5f * (s2-s1) + s1;
9247                 tc[cornerindex][1] = (temp[2]+1.0f)*0.5f * (t2-t1) + t1;
9248                 // calculate distance fade from the projection origin
9249                 f = a * (1.0f-fabs(temp[0])) * cl_decals_newsystem_intensitymultiplier.value;
9250                 f = bound(0.0f, f, 1.0f);
9251                 c[cornerindex][0] = r * f;
9252                 c[cornerindex][1] = g * f;
9253                 c[cornerindex][2] = b * f;
9254                 c[cornerindex][3] = 1.0f;
9255                 //VectorMA(v[cornerindex], cl_decals_bias.value, localnormal, v[cornerindex]);
9256         }
9257         if (dynamic)
9258                 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);
9259         else
9260                 for (cornerindex = 0;cornerindex < numpoints-2;cornerindex++)
9261                         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);
9262 }
9263 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)
9264 {
9265         matrix4x4_t projection;
9266         decalsystem_t *decalsystem;
9267         qbool dynamic;
9268         model_t *model;
9269         const msurface_t *surface;
9270         const msurface_t *surfaces;
9271         const texture_t *texture;
9272         int numtriangles;
9273         int surfaceindex;
9274         int triangleindex;
9275         float localorigin[3];
9276         float localnormal[3];
9277         float localmins[3];
9278         float localmaxs[3];
9279         float localsize;
9280         //float normal[3];
9281         float planes[6][4];
9282         float angles[3];
9283         bih_t *bih;
9284         int bih_triangles_count;
9285         int bih_triangles[256];
9286         int bih_surfaces[256];
9287
9288         decalsystem = &ent->decalsystem;
9289         model = ent->model;
9290         if (!model || !ent->allowdecals || ent->alpha < 1 || (ent->flags & (RENDER_ADDITIVE | RENDER_NODEPTHTEST)))
9291         {
9292                 R_DecalSystem_Reset(&ent->decalsystem);
9293                 return;
9294         }
9295
9296         if (!model->brush.data_leafs && !cl_decals_models.integer)
9297         {
9298                 if (decalsystem->model)
9299                         R_DecalSystem_Reset(decalsystem);
9300                 return;
9301         }
9302
9303         if (decalsystem->model != model)
9304                 R_DecalSystem_Reset(decalsystem);
9305         decalsystem->model = model;
9306
9307         RSurf_ActiveModelEntity(ent, true, false, false);
9308
9309         Matrix4x4_Transform(&rsurface.inversematrix, worldorigin, localorigin);
9310         Matrix4x4_Transform3x3(&rsurface.inversematrix, worldnormal, localnormal);
9311         VectorNormalize(localnormal);
9312         localsize = worldsize*rsurface.inversematrixscale;
9313         localmins[0] = localorigin[0] - localsize;
9314         localmins[1] = localorigin[1] - localsize;
9315         localmins[2] = localorigin[2] - localsize;
9316         localmaxs[0] = localorigin[0] + localsize;
9317         localmaxs[1] = localorigin[1] + localsize;
9318         localmaxs[2] = localorigin[2] + localsize;
9319
9320         //VectorCopy(localnormal, planes[4]);
9321         //VectorVectors(planes[4], planes[2], planes[0]);
9322         AnglesFromVectors(angles, localnormal, NULL, false);
9323         AngleVectors(angles, planes[0], planes[2], planes[4]);
9324         VectorNegate(planes[0], planes[1]);
9325         VectorNegate(planes[2], planes[3]);
9326         VectorNegate(planes[4], planes[5]);
9327         planes[0][3] = DotProduct(planes[0], localorigin) - localsize;
9328         planes[1][3] = DotProduct(planes[1], localorigin) - localsize;
9329         planes[2][3] = DotProduct(planes[2], localorigin) - localsize;
9330         planes[3][3] = DotProduct(planes[3], localorigin) - localsize;
9331         planes[4][3] = DotProduct(planes[4], localorigin) - localsize;
9332         planes[5][3] = DotProduct(planes[5], localorigin) - localsize;
9333
9334 #if 1
9335 // works
9336 {
9337         matrix4x4_t forwardprojection;
9338         Matrix4x4_CreateFromQuakeEntity(&forwardprojection, localorigin[0], localorigin[1], localorigin[2], angles[0], angles[1], angles[2], localsize);
9339         Matrix4x4_Invert_Simple(&projection, &forwardprojection);
9340 }
9341 #else
9342 // broken
9343 {
9344         float projectionvector[4][3];
9345         VectorScale(planes[0], ilocalsize, projectionvector[0]);
9346         VectorScale(planes[2], ilocalsize, projectionvector[1]);
9347         VectorScale(planes[4], ilocalsize, projectionvector[2]);
9348         projectionvector[0][0] = planes[0][0] * ilocalsize;
9349         projectionvector[0][1] = planes[1][0] * ilocalsize;
9350         projectionvector[0][2] = planes[2][0] * ilocalsize;
9351         projectionvector[1][0] = planes[0][1] * ilocalsize;
9352         projectionvector[1][1] = planes[1][1] * ilocalsize;
9353         projectionvector[1][2] = planes[2][1] * ilocalsize;
9354         projectionvector[2][0] = planes[0][2] * ilocalsize;
9355         projectionvector[2][1] = planes[1][2] * ilocalsize;
9356         projectionvector[2][2] = planes[2][2] * ilocalsize;
9357         projectionvector[3][0] = -(localorigin[0]*projectionvector[0][0]+localorigin[1]*projectionvector[1][0]+localorigin[2]*projectionvector[2][0]);
9358         projectionvector[3][1] = -(localorigin[0]*projectionvector[0][1]+localorigin[1]*projectionvector[1][1]+localorigin[2]*projectionvector[2][1]);
9359         projectionvector[3][2] = -(localorigin[0]*projectionvector[0][2]+localorigin[1]*projectionvector[1][2]+localorigin[2]*projectionvector[2][2]);
9360         Matrix4x4_FromVectors(&projection, projectionvector[0], projectionvector[1], projectionvector[2], projectionvector[3]);
9361 }
9362 #endif
9363
9364         dynamic = model->surfmesh.isanimated;
9365         surfaces = model->data_surfaces;
9366
9367         bih = NULL;
9368         bih_triangles_count = -1;
9369         if(!dynamic)
9370         {
9371                 if(model->render_bih.numleafs)
9372                         bih = &model->render_bih;
9373                 else if(model->collision_bih.numleafs)
9374                         bih = &model->collision_bih;
9375         }
9376         if(bih)
9377                 bih_triangles_count = BIH_GetTriangleListForBox(bih, sizeof(bih_triangles) / sizeof(*bih_triangles), bih_triangles, bih_surfaces, localmins, localmaxs);
9378         if(bih_triangles_count == 0)
9379                 return;
9380         if(bih_triangles_count > (int) (sizeof(bih_triangles) / sizeof(*bih_triangles))) // hit too many, likely bad anyway
9381                 return;
9382         if(bih_triangles_count > 0)
9383         {
9384                 for (triangleindex = 0; triangleindex < bih_triangles_count; ++triangleindex)
9385                 {
9386                         surfaceindex = bih_surfaces[triangleindex];
9387                         surface = surfaces + surfaceindex;
9388                         texture = surface->texture;
9389                         if (!texture)
9390                                 continue;
9391                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9392                                 continue;
9393                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9394                                 continue;
9395                         R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, bih_triangles[triangleindex], surfaceindex);
9396                 }
9397         }
9398         else
9399         {
9400                 for (surfaceindex = model->submodelsurfaces_start;surfaceindex < model->submodelsurfaces_end;surfaceindex++)
9401                 {
9402                         surface = surfaces + surfaceindex;
9403                         // check cull box first because it rejects more than any other check
9404                         if (!dynamic && !BoxesOverlap(surface->mins, surface->maxs, localmins, localmaxs))
9405                                 continue;
9406                         // skip transparent surfaces
9407                         texture = surface->texture;
9408                         if (!texture)
9409                                 continue;
9410                         if (texture->currentmaterialflags & (MATERIALFLAG_BLENDED | MATERIALFLAG_NODEPTHTEST | MATERIALFLAG_SKY | MATERIALFLAG_SHORTDEPTHRANGE | MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION))
9411                                 continue;
9412                         if (texture->surfaceflags & Q3SURFACEFLAG_NOMARKS)
9413                                 continue;
9414                         numtriangles = surface->num_triangles;
9415                         for (triangleindex = 0; triangleindex < numtriangles; triangleindex++)
9416                                 R_DecalSystem_SplatTriangle(decalsystem, r, g, b, a, s1, t1, s2, t2, decalsequence, dynamic, planes, &projection, triangleindex + surface->num_firsttriangle, surfaceindex);
9417                 }
9418         }
9419 }
9420
9421 // do not call this outside of rendering code - use R_DecalSystem_SplatEntities instead
9422 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)
9423 {
9424         int renderentityindex;
9425         float worldmins[3];
9426         float worldmaxs[3];
9427         entity_render_t *ent;
9428
9429         worldmins[0] = worldorigin[0] - worldsize;
9430         worldmins[1] = worldorigin[1] - worldsize;
9431         worldmins[2] = worldorigin[2] - worldsize;
9432         worldmaxs[0] = worldorigin[0] + worldsize;
9433         worldmaxs[1] = worldorigin[1] + worldsize;
9434         worldmaxs[2] = worldorigin[2] + worldsize;
9435
9436         R_DecalSystem_SplatEntity(r_refdef.scene.worldentity, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9437
9438         for (renderentityindex = 0;renderentityindex < r_refdef.scene.numentities;renderentityindex++)
9439         {
9440                 ent = r_refdef.scene.entities[renderentityindex];
9441                 if (!BoxesOverlap(ent->mins, ent->maxs, worldmins, worldmaxs))
9442                         continue;
9443
9444                 R_DecalSystem_SplatEntity(ent, worldorigin, worldnormal, r, g, b, a, s1, t1, s2, t2, worldsize, decalsequence);
9445         }
9446 }
9447
9448 typedef struct r_decalsystem_splatqueue_s
9449 {
9450         vec3_t worldorigin;
9451         vec3_t worldnormal;
9452         float color[4];
9453         float tcrange[4];
9454         float worldsize;
9455         unsigned int decalsequence;
9456 }
9457 r_decalsystem_splatqueue_t;
9458
9459 int r_decalsystem_numqueued = 0;
9460 r_decalsystem_splatqueue_t r_decalsystem_queue[MAX_DECALSYSTEM_QUEUE];
9461
9462 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)
9463 {
9464         r_decalsystem_splatqueue_t *queue;
9465
9466         if (r_decalsystem_numqueued == MAX_DECALSYSTEM_QUEUE)
9467                 return;
9468
9469         queue = &r_decalsystem_queue[r_decalsystem_numqueued++];
9470         VectorCopy(worldorigin, queue->worldorigin);
9471         VectorCopy(worldnormal, queue->worldnormal);
9472         Vector4Set(queue->color, r, g, b, a);
9473         Vector4Set(queue->tcrange, s1, t1, s2, t2);
9474         queue->worldsize = worldsize;
9475         queue->decalsequence = cl.decalsequence++;
9476 }
9477
9478 static void R_DecalSystem_ApplySplatEntitiesQueue(void)
9479 {
9480         int i;
9481         r_decalsystem_splatqueue_t *queue;
9482
9483         for (i = 0, queue = r_decalsystem_queue;i < r_decalsystem_numqueued;i++, queue++)
9484                 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);
9485         r_decalsystem_numqueued = 0;
9486 }
9487
9488 extern cvar_t cl_decals_max;
9489 static void R_DrawModelDecals_FadeEntity(entity_render_t *ent)
9490 {
9491         int i;
9492         decalsystem_t *decalsystem = &ent->decalsystem;
9493         int numdecals;
9494         unsigned int killsequence;
9495         tridecal_t *decal;
9496         float frametime;
9497         float lifetime;
9498
9499         if (!decalsystem->numdecals)
9500                 return;
9501
9502         if (r_showsurfaces.integer)
9503                 return;
9504
9505         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9506         {
9507                 R_DecalSystem_Reset(decalsystem);
9508                 return;
9509         }
9510
9511         killsequence = cl.decalsequence - bound(1, (unsigned int) cl_decals_max.integer, cl.decalsequence);
9512         lifetime = cl_decals_time.value + cl_decals_fadetime.value;
9513
9514         if (decalsystem->lastupdatetime)
9515                 frametime = (r_refdef.scene.time - decalsystem->lastupdatetime);
9516         else
9517                 frametime = 0;
9518         decalsystem->lastupdatetime = r_refdef.scene.time;
9519         numdecals = decalsystem->numdecals;
9520
9521         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9522         {
9523                 if (decal->color4f[0][3])
9524                 {
9525                         decal->lived += frametime;
9526                         if (killsequence > decal->decalsequence || decal->lived >= lifetime)
9527                         {
9528                                 memset(decal, 0, sizeof(*decal));
9529                                 if (decalsystem->freedecal > i)
9530                                         decalsystem->freedecal = i;
9531                         }
9532                 }
9533         }
9534         decal = decalsystem->decals;
9535         while (numdecals > 0 && !decal[numdecals-1].color4f[0][3])
9536                 numdecals--;
9537
9538         // collapse the array by shuffling the tail decals into the gaps
9539         for (;;)
9540         {
9541                 while (decalsystem->freedecal < numdecals && decal[decalsystem->freedecal].color4f[0][3])
9542                         decalsystem->freedecal++;
9543                 if (decalsystem->freedecal == numdecals)
9544                         break;
9545                 decal[decalsystem->freedecal] = decal[--numdecals];
9546         }
9547
9548         decalsystem->numdecals = numdecals;
9549
9550         if (numdecals <= 0)
9551         {
9552                 // if there are no decals left, reset decalsystem
9553                 R_DecalSystem_Reset(decalsystem);
9554         }
9555 }
9556
9557 extern skinframe_t *decalskinframe;
9558 static void R_DrawModelDecals_Entity(entity_render_t *ent)
9559 {
9560         int i;
9561         decalsystem_t *decalsystem = &ent->decalsystem;
9562         int numdecals;
9563         tridecal_t *decal;
9564         float faderate;
9565         float alpha;
9566         float *v3f;
9567         float *c4f;
9568         float *t2f;
9569         const int *e;
9570         const unsigned char *surfacevisible = ent == r_refdef.scene.worldentity ? r_refdef.viewcache.world_surfacevisible : NULL;
9571         int numtris = 0;
9572
9573         numdecals = decalsystem->numdecals;
9574         if (!numdecals)
9575                 return;
9576
9577         if (r_showsurfaces.integer)
9578                 return;
9579
9580         if (ent->model != decalsystem->model || ent->alpha < 1 || (ent->flags & RENDER_ADDITIVE))
9581         {
9582                 R_DecalSystem_Reset(decalsystem);
9583                 return;
9584         }
9585
9586         // if the model is static it doesn't matter what value we give for
9587         // wantnormals and wanttangents, so this logic uses only rules applicable
9588         // to a model, knowing that they are meaningless otherwise
9589         RSurf_ActiveModelEntity(ent, false, false, false);
9590
9591         decalsystem->lastupdatetime = r_refdef.scene.time;
9592
9593         faderate = 1.0f / max(0.001f, cl_decals_fadetime.value);
9594
9595         // update vertex positions for animated models
9596         v3f = decalsystem->vertex3f;
9597         c4f = decalsystem->color4f;
9598         t2f = decalsystem->texcoord2f;
9599         for (i = 0, decal = decalsystem->decals;i < numdecals;i++, decal++)
9600         {
9601                 if (!decal->color4f[0][3])
9602                         continue;
9603
9604                 if (surfacevisible && !surfacevisible[decal->surfaceindex])
9605                         continue;
9606
9607                 // skip backfaces
9608                 if (decal->triangleindex < 0 && DotProduct(r_refdef.view.origin, decal->plane) < decal->plane[3])
9609                         continue;
9610
9611                 // update color values for fading decals
9612                 if (decal->lived >= cl_decals_time.value)
9613                         alpha = 1 - faderate * (decal->lived - cl_decals_time.value);
9614                 else
9615                         alpha = 1.0f;
9616
9617                 c4f[ 0] = decal->color4f[0][0] * alpha;
9618                 c4f[ 1] = decal->color4f[0][1] * alpha;
9619                 c4f[ 2] = decal->color4f[0][2] * alpha;
9620                 c4f[ 3] = 1;
9621                 c4f[ 4] = decal->color4f[1][0] * alpha;
9622                 c4f[ 5] = decal->color4f[1][1] * alpha;
9623                 c4f[ 6] = decal->color4f[1][2] * alpha;
9624                 c4f[ 7] = 1;
9625                 c4f[ 8] = decal->color4f[2][0] * alpha;
9626                 c4f[ 9] = decal->color4f[2][1] * alpha;
9627                 c4f[10] = decal->color4f[2][2] * alpha;
9628                 c4f[11] = 1;
9629
9630                 t2f[0] = decal->texcoord2f[0][0];
9631                 t2f[1] = decal->texcoord2f[0][1];
9632                 t2f[2] = decal->texcoord2f[1][0];
9633                 t2f[3] = decal->texcoord2f[1][1];
9634                 t2f[4] = decal->texcoord2f[2][0];
9635                 t2f[5] = decal->texcoord2f[2][1];
9636
9637                 // update vertex positions for animated models
9638                 if (decal->triangleindex >= 0 && decal->triangleindex < rsurface.modelnumtriangles)
9639                 {
9640                         e = rsurface.modelelement3i + 3*decal->triangleindex;
9641                         VectorCopy(rsurface.modelvertex3f + 3*e[0], v3f);
9642                         VectorCopy(rsurface.modelvertex3f + 3*e[1], v3f + 3);
9643                         VectorCopy(rsurface.modelvertex3f + 3*e[2], v3f + 6);
9644                 }
9645                 else
9646                 {
9647                         VectorCopy(decal->vertex3f[0], v3f);
9648                         VectorCopy(decal->vertex3f[1], v3f + 3);
9649                         VectorCopy(decal->vertex3f[2], v3f + 6);
9650                 }
9651
9652                 if (r_refdef.fogenabled)
9653                 {
9654                         alpha = RSurf_FogVertex(v3f);
9655                         VectorScale(c4f, alpha, c4f);
9656                         alpha = RSurf_FogVertex(v3f + 3);
9657                         VectorScale(c4f + 4, alpha, c4f + 4);
9658                         alpha = RSurf_FogVertex(v3f + 6);
9659                         VectorScale(c4f + 8, alpha, c4f + 8);
9660                 }
9661
9662                 v3f += 9;
9663                 c4f += 12;
9664                 t2f += 6;
9665                 numtris++;
9666         }
9667
9668         if (numtris > 0)
9669         {
9670                 r_refdef.stats[r_stat_drawndecals] += numtris;
9671
9672                 // now render the decals all at once
9673                 // (this assumes they all use one particle font texture!)
9674                 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);
9675 //              R_Mesh_ResetTextureState();
9676                 R_Mesh_PrepareVertices_Generic_Arrays(numtris * 3, decalsystem->vertex3f, decalsystem->color4f, decalsystem->texcoord2f);
9677                 GL_DepthMask(false);
9678                 GL_DepthRange(0, 1);
9679                 GL_PolygonOffset(rsurface.basepolygonfactor + r_polygonoffset_decals_factor.value, rsurface.basepolygonoffset + r_polygonoffset_decals_offset.value);
9680                 GL_DepthTest(true);
9681                 GL_CullFace(GL_NONE);
9682                 GL_BlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR);
9683                 R_SetupShader_Generic(decalskinframe->base, false, false, false);
9684                 R_Mesh_Draw(0, numtris * 3, 0, numtris, decalsystem->element3i, NULL, 0, decalsystem->element3s, NULL, 0);
9685         }
9686 }
9687
9688 static void R_DrawModelDecals(void)
9689 {
9690         int i, numdecals;
9691
9692         // fade faster when there are too many decals
9693         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9694         for (i = 0;i < r_refdef.scene.numentities;i++)
9695                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9696
9697         R_DrawModelDecals_FadeEntity(r_refdef.scene.worldentity);
9698         for (i = 0;i < r_refdef.scene.numentities;i++)
9699                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9700                         R_DrawModelDecals_FadeEntity(r_refdef.scene.entities[i]);
9701
9702         R_DecalSystem_ApplySplatEntitiesQueue();
9703
9704         numdecals = r_refdef.scene.worldentity->decalsystem.numdecals;
9705         for (i = 0;i < r_refdef.scene.numentities;i++)
9706                 numdecals += r_refdef.scene.entities[i]->decalsystem.numdecals;
9707
9708         r_refdef.stats[r_stat_totaldecals] += numdecals;
9709
9710         if (r_showsurfaces.integer || !r_drawdecals.integer)
9711                 return;
9712
9713         R_DrawModelDecals_Entity(r_refdef.scene.worldentity);
9714
9715         for (i = 0;i < r_refdef.scene.numentities;i++)
9716         {
9717                 if (!r_refdef.viewcache.entityvisible[i])
9718                         continue;
9719                 if (r_refdef.scene.entities[i]->decalsystem.numdecals)
9720                         R_DrawModelDecals_Entity(r_refdef.scene.entities[i]);
9721         }
9722 }
9723
9724 static void R_DrawDebugModel(void)
9725 {
9726         entity_render_t *ent = rsurface.entity;
9727         int j, flagsmask;
9728         const msurface_t *surface;
9729         model_t *model = ent->model;
9730
9731         if (!sv.active  && !cls.demoplayback && ent != r_refdef.scene.worldentity)
9732                 return;
9733
9734         if (r_showoverdraw.value > 0)
9735         {
9736                 float c = r_refdef.view.colorscale * r_showoverdraw.value * 0.125f;
9737                 flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9738                 R_SetupShader_Generic_NoTexture(false, false);
9739                 GL_DepthTest(false);
9740                 GL_DepthMask(false);
9741                 GL_DepthRange(0, 1);
9742                 GL_BlendFunc(GL_ONE, GL_ONE);
9743                 for (j = model->submodelsurfaces_start;j < model->submodelsurfaces_end;j++)
9744                 {
9745                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9746                                 continue;
9747                         surface = model->data_surfaces + j;
9748                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9749                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9750                         {
9751                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_NOGAPS, 1, &surface);
9752                                 GL_CullFace((rsurface.texture->currentmaterialflags & MATERIALFLAG_NOCULLFACE) ? GL_NONE : r_refdef.view.cullface_back);
9753                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9754                                         GL_Color(c, 0, 0, 1.0f);
9755                                 else if (ent == r_refdef.scene.worldentity)
9756                                         GL_Color(c, c, c, 1.0f);
9757                                 else
9758                                         GL_Color(0, c, 0, 1.0f);
9759                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9760                                 RSurf_DrawBatch();
9761                         }
9762                 }
9763                 rsurface.texture = NULL;
9764         }
9765
9766         flagsmask = MATERIALFLAG_SKY | MATERIALFLAG_WALL;
9767
9768 //      R_Mesh_ResetTextureState();
9769         R_SetupShader_Generic_NoTexture(false, false);
9770         GL_DepthRange(0, 1);
9771         GL_DepthTest(!r_showdisabledepthtest.integer);
9772         GL_DepthMask(false);
9773         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9774
9775         if (r_showcollisionbrushes.value > 0 && model->collision_bih.numleafs)
9776         {
9777                 int triangleindex;
9778                 int bihleafindex;
9779                 qbool cullbox = false;
9780                 const q3mbrush_t *brush;
9781                 const bih_t *bih = &model->collision_bih;
9782                 const bih_leaf_t *bihleaf;
9783                 float vertex3f[3][3];
9784                 GL_PolygonOffset(r_refdef.polygonfactor + r_showcollisionbrushes_polygonfactor.value, r_refdef.polygonoffset + r_showcollisionbrushes_polygonoffset.value);
9785                 for (bihleafindex = 0, bihleaf = bih->leafs;bihleafindex < bih->numleafs;bihleafindex++, bihleaf++)
9786                 {
9787                         if (cullbox && R_CullFrustum(bihleaf->mins, bihleaf->maxs))
9788                                 continue;
9789                         switch (bihleaf->type)
9790                         {
9791                         case BIH_BRUSH:
9792                                 brush = model->brush.data_brushes + bihleaf->itemindex;
9793                                 if (brush->colbrushf && brush->colbrushf->numtriangles)
9794                                 {
9795                                         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);
9796                                         R_Mesh_PrepareVertices_Generic_Arrays(brush->colbrushf->numpoints, brush->colbrushf->points->v, NULL, NULL);
9797                                         R_Mesh_Draw(0, brush->colbrushf->numpoints, 0, brush->colbrushf->numtriangles, brush->colbrushf->elements, NULL, 0, NULL, NULL, 0);
9798                                 }
9799                                 break;
9800                         case BIH_COLLISIONTRIANGLE:
9801                                 triangleindex = bihleaf->itemindex;
9802                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+0], vertex3f[0]);
9803                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+1], vertex3f[1]);
9804                                 VectorCopy(model->brush.data_collisionvertex3f + 3*model->brush.data_collisionelement3i[triangleindex*3+2], vertex3f[2]);
9805                                 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);
9806                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9807                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9808                                 break;
9809                         case BIH_RENDERTRIANGLE:
9810                                 triangleindex = bihleaf->itemindex;
9811                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+0], vertex3f[0]);
9812                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+1], vertex3f[1]);
9813                                 VectorCopy(model->surfmesh.data_vertex3f + 3*model->surfmesh.data_element3i[triangleindex*3+2], vertex3f[2]);
9814                                 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);
9815                                 R_Mesh_PrepareVertices_Generic_Arrays(3, vertex3f[0], NULL, NULL);
9816                                 R_Mesh_Draw(0, 3, 0, 1, polygonelement3i, NULL, 0, polygonelement3s, NULL, 0);
9817                                 break;
9818                         }
9819                 }
9820         }
9821
9822         GL_PolygonOffset(r_refdef.polygonfactor, r_refdef.polygonoffset);
9823
9824 #ifndef USE_GLES2
9825         if (r_showtris.value > 0 && qglPolygonMode)
9826         {
9827                 if (r_showdisabledepthtest.integer)
9828                 {
9829                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9830                         GL_DepthMask(false);
9831                 }
9832                 else
9833                 {
9834                         GL_BlendFunc(GL_ONE, GL_ZERO);
9835                         GL_DepthMask(true);
9836                 }
9837                 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);CHECKGLERROR
9838                 for (j = model->submodelsurfaces_start; j < model->submodelsurfaces_end; j++)
9839                 {
9840                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9841                                 continue;
9842                         surface = model->data_surfaces + j;
9843                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9844                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9845                         {
9846                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9847                                 if ((rsurface.texture->currentmaterialflags & MATERIALFLAG_BLENDED))
9848                                         GL_Color(r_refdef.view.colorscale, 0, 0, r_showtris.value);
9849                                 else if (ent == r_refdef.scene.worldentity)
9850                                         GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, r_showtris.value);
9851                                 else
9852                                         GL_Color(0, r_refdef.view.colorscale, 0, r_showtris.value);
9853                                 R_Mesh_PrepareVertices_Generic_Arrays(rsurface.batchnumvertices, rsurface.batchvertex3f, NULL, NULL);
9854                                 RSurf_DrawBatch();
9855                         }
9856                 }
9857                 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);CHECKGLERROR
9858                 rsurface.texture = NULL;
9859         }
9860
9861 # if 0
9862         // FIXME!  implement r_shownormals with just triangles
9863         if (r_shownormals.value != 0 && qglBegin)
9864         {
9865                 int l, k;
9866                 vec3_t v;
9867                 if (r_showdisabledepthtest.integer)
9868                 {
9869                         GL_BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
9870                         GL_DepthMask(false);
9871                 }
9872                 else
9873                 {
9874                         GL_BlendFunc(GL_ONE, GL_ZERO);
9875                         GL_DepthMask(true);
9876                 }
9877                 for (j = model->submodelsurfaces_start; j < model->submodelsurfaces_end; j++)
9878                 {
9879                         if (ent == r_refdef.scene.worldentity && !r_refdef.viewcache.world_surfacevisible[j])
9880                                 continue;
9881                         surface = model->data_surfaces + j;
9882                         rsurface.texture = R_GetCurrentTexture(surface->texture);
9883                         if ((rsurface.texture->currentmaterialflags & flagsmask) && surface->num_triangles)
9884                         {
9885                                 RSurf_PrepareVerticesForBatch(BATCHNEED_ARRAY_VERTEX | BATCHNEED_ARRAY_NORMAL | BATCHNEED_ARRAY_VECTOR | BATCHNEED_NOGAPS, 1, &surface);
9886                                 qglBegin(GL_LINES);
9887                                 if (r_shownormals.value < 0 && rsurface.batchnormal3f)
9888                                 {
9889                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9890                                         {
9891                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9892                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
9893                                                 qglVertex3f(v[0], v[1], v[2]);
9894                                                 VectorMA(v, -r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
9895                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9896                                                 qglVertex3f(v[0], v[1], v[2]);
9897                                         }
9898                                 }
9899                                 if (r_shownormals.value > 0 && rsurface.batchsvector3f)
9900                                 {
9901                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9902                                         {
9903                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9904                                                 GL_Color(r_refdef.view.colorscale, 0, 0, 1);
9905                                                 qglVertex3f(v[0], v[1], v[2]);
9906                                                 VectorMA(v, r_shownormals.value, rsurface.batchsvector3f + l * 3, v);
9907                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9908                                                 qglVertex3f(v[0], v[1], v[2]);
9909                                         }
9910                                 }
9911                                 if (r_shownormals.value > 0 && rsurface.batchtvector3f)
9912                                 {
9913                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9914                                         {
9915                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9916                                                 GL_Color(0, r_refdef.view.colorscale, 0, 1);
9917                                                 qglVertex3f(v[0], v[1], v[2]);
9918                                                 VectorMA(v, r_shownormals.value, rsurface.batchtvector3f + l * 3, v);
9919                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9920                                                 qglVertex3f(v[0], v[1], v[2]);
9921                                         }
9922                                 }
9923                                 if (r_shownormals.value > 0 && rsurface.batchnormal3f)
9924                                 {
9925                                         for (k = 0, l = rsurface.batchfirstvertex;k < rsurface.batchnumvertices;k++, l++)
9926                                         {
9927                                                 VectorCopy(rsurface.batchvertex3f + l * 3, v);
9928                                                 GL_Color(0, 0, r_refdef.view.colorscale, 1);
9929                                                 qglVertex3f(v[0], v[1], v[2]);
9930                                                 VectorMA(v, r_shownormals.value, rsurface.batchnormal3f + l * 3, v);
9931                                                 GL_Color(r_refdef.view.colorscale, r_refdef.view.colorscale, r_refdef.view.colorscale, 1);
9932                                                 qglVertex3f(v[0], v[1], v[2]);
9933                                         }
9934                                 }
9935                                 qglEnd();
9936                                 CHECKGLERROR
9937                         }
9938                 }
9939                 rsurface.texture = NULL;
9940         }
9941 # endif
9942 #endif
9943 }
9944
9945 int r_maxsurfacelist = 0;
9946 const msurface_t **r_surfacelist = NULL;
9947 void R_DrawModelSurfaces(entity_render_t *ent, qbool skysurfaces, qbool writedepth, qbool depthonly, qbool debug, qbool prepass, qbool ui)
9948 {
9949         int i, j, flagsmask;
9950         model_t *model = ent->model;
9951         msurface_t *surfaces;
9952         unsigned char *update;
9953         int numsurfacelist = 0;
9954         if (model == NULL)
9955                 return;
9956
9957         if (r_maxsurfacelist < model->num_surfaces)
9958         {
9959                 r_maxsurfacelist = model->num_surfaces;
9960                 if (r_surfacelist)
9961                         Mem_Free((msurface_t **)r_surfacelist);
9962                 r_surfacelist = (const msurface_t **) Mem_Alloc(r_main_mempool, r_maxsurfacelist * sizeof(*r_surfacelist));
9963         }
9964
9965         if (r_showsurfaces.integer && r_showsurfaces.integer != 3)
9966                 RSurf_ActiveModelEntity(ent, false, false, false);
9967         else if (prepass)
9968                 RSurf_ActiveModelEntity(ent, true, true, true);
9969         else if (depthonly)
9970                 RSurf_ActiveModelEntity(ent, model->wantnormals, model->wanttangents, false);
9971         else
9972                 RSurf_ActiveModelEntity(ent, true, true, false);
9973
9974         surfaces = model->data_surfaces;
9975         update = model->brushq1.lightmapupdateflags;
9976
9977         flagsmask = skysurfaces ? MATERIALFLAG_SKY : MATERIALFLAG_WALL;
9978
9979         if (debug)
9980         {
9981                 R_DrawDebugModel();
9982                 rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
9983                 return;
9984         }
9985
9986         // check if this is an empty model
9987         if (model->submodelsurfaces_start >= model->submodelsurfaces_end)
9988                 return;
9989
9990         rsurface.lightmaptexture = NULL;
9991         rsurface.deluxemaptexture = NULL;
9992         rsurface.uselightmaptexture = false;
9993         rsurface.texture = NULL;
9994         rsurface.rtlight = NULL;
9995         numsurfacelist = 0;
9996
9997         // add visible surfaces to draw list
9998         if (ent == r_refdef.scene.worldentity)
9999         {
10000                 // for the world entity, check surfacevisible
10001                 for (i = model->submodelsurfaces_start;i < model->submodelsurfaces_end;i++)
10002                 {
10003                         j = model->modelsurfaces_sorted[i];
10004                         if (r_refdef.viewcache.world_surfacevisible[j])
10005                                 r_surfacelist[numsurfacelist++] = surfaces + j;
10006                 }
10007
10008                 // don't do anything if there were no surfaces added (none of the world entity is visible)
10009                 if (!numsurfacelist)
10010                 {
10011                         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10012                         return;
10013                 }
10014         }
10015         else if (ui)
10016         {
10017                 // for ui we have to preserve the order of surfaces (not using modelsurfaces_sorted)
10018                 for (i = model->submodelsurfaces_start; i < model->submodelsurfaces_end; i++)
10019                         r_surfacelist[numsurfacelist++] = surfaces + i;
10020         }
10021         else
10022         {
10023                 // add all surfaces
10024                 for (i = model->submodelsurfaces_start; i < model->submodelsurfaces_end; i++)
10025                         r_surfacelist[numsurfacelist++] = surfaces + model->modelsurfaces_sorted[i];
10026         }
10027
10028         /*
10029          * Mark lightmaps as dirty if their lightstyle's value changed. We do this by
10030          * using style chains because most styles do not change on most frames, and most
10031          * surfaces do not have styles on them. Mods like Arcane Dimensions (e.g. ad_necrokeep)
10032          * break this rule and animate most surfaces.
10033          */
10034         if (update && !skysurfaces && !depthonly && !prepass && model->brushq1.num_lightstyles && r_refdef.scene.lightmapintensity > 0 && r_q1bsp_lightmap_updates_enabled.integer)
10035         {
10036                 model_brush_lightstyleinfo_t *style;
10037
10038                 // For each lightstyle, check if its value changed and mark the lightmaps as dirty if so
10039                 for (i = 0, style = model->brushq1.data_lightstyleinfo; i < model->brushq1.num_lightstyles; i++, style++)
10040                 {
10041                         if (style->value != r_refdef.scene.lightstylevalue[style->style])
10042                         {
10043                                 int* list = style->surfacelist;
10044                                 style->value = r_refdef.scene.lightstylevalue[style->style];
10045                                 // Value changed - mark the surfaces belonging to this style chain as dirty
10046                                 for (j = 0; j < style->numsurfaces; j++)
10047                                         update[list[j]] = true;
10048                         }
10049                 }
10050                 // Now check if update flags are set on any surfaces that are visible
10051                 if (r_q1bsp_lightmap_updates_hidden_surfaces.integer)
10052                 {
10053                         /* 
10054                          * We can do less frequent texture uploads (approximately 10hz for animated
10055                          * lightstyles) by rebuilding lightmaps on surfaces that are not currently visible.
10056                          * For optimal efficiency, this includes the submodels of the worldmodel, so we
10057                          * use model->num_surfaces, not nummodelsurfaces.
10058                          */
10059                         for (i = 0; i < model->num_surfaces;i++)
10060                                 if (update[i])
10061                                         R_BuildLightMap(ent, surfaces + i, r_q1bsp_lightmap_updates_combine.integer);
10062                 }
10063                 else
10064                 {
10065                         for (i = 0; i < numsurfacelist; i++)
10066                                 if (update[r_surfacelist[i] - surfaces])
10067                                         R_BuildLightMap(ent, (msurface_t *)r_surfacelist[i], r_q1bsp_lightmap_updates_combine.integer);
10068                 }
10069         }
10070
10071         R_QueueModelSurfaceList(ent, numsurfacelist, r_surfacelist, flagsmask, writedepth, depthonly, prepass, ui);
10072
10073         // add to stats if desired
10074         if (r_speeds.integer && !skysurfaces && !depthonly)
10075         {
10076                 r_refdef.stats[r_stat_entities_surfaces] += numsurfacelist;
10077                 for (j = 0;j < numsurfacelist;j++)
10078                         r_refdef.stats[r_stat_entities_triangles] += r_surfacelist[j]->num_triangles;
10079         }
10080
10081         rsurface.entity = NULL; // used only by R_GetCurrentTexture and RSurf_ActiveModelEntity
10082 }
10083
10084 void R_DebugLine(vec3_t start, vec3_t end)
10085 {
10086         model_t *mod = CL_Mesh_UI();
10087         msurface_t *surf;
10088         int e0, e1, e2, e3;
10089         float offsetx, offsety, x1, y1, x2, y2, width = 1.0f;
10090         float r1 = 1.0f, g1 = 0.0f, b1 = 0.0f, alpha1 = 0.25f;
10091         float r2 = 1.0f, g2 = 1.0f, b2 = 0.0f, alpha2 = 0.25f;
10092         vec4_t w[2], s[2];
10093
10094         // transform to screen coords first
10095         Vector4Set(w[0], start[0], start[1], start[2], 1);
10096         Vector4Set(w[1], end[0], end[1], end[2], 1);
10097         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[0], s[0]);
10098         R_Viewport_TransformToScreen(&r_refdef.view.viewport, w[1], s[1]);
10099         x1 = s[0][0] * vid_conwidth.value / vid.width;
10100         y1 = (vid.height - s[0][1]) * vid_conheight.value / vid.height;
10101         x2 = s[1][0] * vid_conwidth.value / vid.width;
10102         y2 = (vid.height - s[1][1]) * vid_conheight.value / vid.height;
10103         //Con_DPrintf("R_DebugLine: %.0f,%.0f to %.0f,%.0f\n", x1, y1, x2, y2);
10104
10105         // add the line to the UI mesh for drawing later
10106
10107         // width is measured in real pixels
10108         if (fabs(x2 - x1) > fabs(y2 - y1))
10109         {
10110                 offsetx = 0;
10111                 offsety = 0.5f * width * vid_conheight.value / vid.height;
10112         }
10113         else
10114         {
10115                 offsetx = 0.5f * width * vid_conwidth.value / vid.width;
10116                 offsety = 0;
10117         }
10118         surf = Mod_Mesh_AddSurface(mod, Mod_Mesh_GetTexture(mod, "white", 0, 0, MATERIALFLAG_WALL | MATERIALFLAG_VERTEXCOLOR | MATERIALFLAG_ALPHAGEN_VERTEX | MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW), true);
10119         e0 = Mod_Mesh_IndexForVertex(mod, surf, x1 - offsetx, y1 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10120         e1 = Mod_Mesh_IndexForVertex(mod, surf, x2 - offsetx, y2 - offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10121         e2 = Mod_Mesh_IndexForVertex(mod, surf, x2 + offsetx, y2 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r2, g2, b2, alpha2);
10122         e3 = Mod_Mesh_IndexForVertex(mod, surf, x1 + offsetx, y1 + offsety, 10, 0, 0, -1, 0, 0, 0, 0, r1, g1, b1, alpha1);
10123         Mod_Mesh_AddTriangle(mod, surf, e0, e1, e2);
10124         Mod_Mesh_AddTriangle(mod, surf, e0, e2, e3);
10125
10126 }
10127
10128
10129 void R_DrawCustomSurface(skinframe_t *skinframe, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qbool writedepth, qbool prepass, qbool ui)
10130 {
10131         static texture_t texture;
10132
10133         // fake enough texture and surface state to render this geometry
10134
10135         texture.update_lastrenderframe = -1; // regenerate this texture
10136         texture.basematerialflags = materialflags | MATERIALFLAG_CUSTOMSURFACE | MATERIALFLAG_WALL;
10137         texture.basealpha = 1.0f;
10138         texture.currentskinframe = skinframe;
10139         texture.currenttexmatrix = *texmatrix; // requires MATERIALFLAG_CUSTOMSURFACE
10140         texture.offsetmapping = OFFSETMAPPING_OFF;
10141         texture.offsetscale = 1;
10142         texture.specularscalemod = 1;
10143         texture.specularpowermod = 1;
10144         texture.transparentsort = TRANSPARENTSORT_DISTANCE;
10145
10146         R_DrawCustomSurface_Texture(&texture, texmatrix, materialflags, firstvertex, numvertices, firsttriangle, numtriangles, writedepth, prepass, ui);
10147 }
10148
10149 void R_DrawCustomSurface_Texture(texture_t *texture, const matrix4x4_t *texmatrix, int materialflags, int firstvertex, int numvertices, int firsttriangle, int numtriangles, qbool writedepth, qbool prepass, qbool ui)
10150 {
10151         static msurface_t surface;
10152         const msurface_t *surfacelist = &surface;
10153
10154         // fake enough texture and surface state to render this geometry
10155         surface.texture = texture;
10156         surface.num_triangles = numtriangles;
10157         surface.num_firsttriangle = firsttriangle;
10158         surface.num_vertices = numvertices;
10159         surface.num_firstvertex = firstvertex;
10160
10161         // now render it
10162         rsurface.texture = R_GetCurrentTexture(surface.texture);
10163         rsurface.lightmaptexture = NULL;
10164         rsurface.deluxemaptexture = NULL;
10165         rsurface.uselightmaptexture = false;
10166         R_DrawModelTextureSurfaceList(1, &surfacelist, writedepth, prepass, ui);
10167 }